2021 Sub0 Online 精彩回顾|Patract Labs 的Wasm智能合约
Jupiter
Ask!
Redspot
Metis
Europa
Parascan
Himalia
我们中的许多人都玩过 Ink!。然而,WASM 的一大优势是 WASM 支持编译成它的编程语言。墨水!很好,但它需要开发人员熟悉 Rust 作为先决条件。因此,我们创建了 Ask! 这是一种类似于ink! 的eDSL。有了 ask!,任何有 typescript 或 AssemblyScript 经验的人都可以轻松开发 WASM 智能合约。总的来说,我们正在努力将 Solidity 风格的开发引入 Substrate。
eDSL
整体布局类似 ink!
AssemblyScript中的语法
Decorator
类似于ink!中的宏,Ask!提供装饰器。这给出了非常相似的代码布局。
高水平的抽象,开发者可以专注于合约逻辑,而不必学习如何与主机函数和 pallet-contract 进行交互。所有复杂的东西都由 Ask!在引擎盖下完成。
Storage
SpreadStorableMap
SpreadStorableArray
PackedStorableMap
PackedStorableArray 当需要存储大量数据时,应该使用 Spread。当你存储少量数据,并需要访问大部分内容时,比如搜索或统计逻辑,选择Packed可能会更好。
接口和继承
Solidity 开发人员可以很快习惯使用Ask!
支持类似于 Openzeppelin 的标准合约库。
正在开发中
目前我们的版本是 v0.2,很快就会发布 v0.3。
模板
基于合约标准,自动生成合约样本、部署脚本、测试脚本和 Redspot 配置。例如。npx redspot-new erc20将创建一个带有 ERC20 代码、部署和测试的目录。你不不要手动编写部署和配置。我们正在将更多的模板集成到 Redspot 中。所以在未来,你可以用一个命令启动任何合约站。
npx 支持,无需额外设置。
编译
包装 cargo-contract。 npx redspot compile
。npx redspot 编译器将编译代码并放入对应的目录进行部署。
部署
上传合约并使用脚本将其实例化。
npx redspot run scripts/deploy.ts --no-compile
测试
使用脚本测试合约方法。 npx redspot test --no-compile
控制台
用于集成测试的强大 JavaScript 交互式控制台。
控制区块链操作。
在编写详细的测试代码之前,你可以在控制台中进行发挥,了解 Redspot 的工作原理。了解如何测试你的合约等。
npx redspot explorer
Docker
很多时候,一个合约将部署在多个区块链上,Redspot 与 Docker 集成,允许一个合约在多个平台上进行测试。 启动 Docker: npx redspot testnet 在 Docker 上编译: npx redspot compile --docker true
。
插入
不足以满足你的开发需求。
用自定义插件扩展 Redspot,增加更多功能,与其他开发工具集成。
通过简单地编写你的自定义插件扩展类型,来保持与自定义Substrate链的兼容
浏览器 GUI
@polkadot/apps ,但重点是合约。
与 Redspot 配置完全集成,一旦你设置了测试区块链,就不需要更多的操作。
目前在 ink! 开发时的问题
缺乏标准库使得智能合约不安全。由于智能合约中的错误,2016 年的 DAO 攻击窃取了 360 万个 ETH。这次攻击对以太坊主网非标准化合约强制硬分叉,造成了巨大的经济损失,并进一步影响区块链的共识。想象一下,在 2021 年,人们真的会质疑你的区块链的安全性,即使那是由合约开发者造成的。
开发者必须手动复制/粘贴现有的实现
源代码可能是未经审计的,且使用起来不安全。 想象一下从另一个智能合约项目复制代码。他们的合约可能有尚未被注意到的错误。肆无忌惮地复制他们的代码可能会在未来造成巨大的问题。
在此过程中费时费力,且容易出错。 复制粘贴时可能会漏掉一些逻辑。
或者你误解了他们的逻辑,因为他们可能没有正确地命名他们的函数。
你浪费了大量时间来更新他们的合约,每次发布都重复复制和粘贴
介绍 Metis
为了彻底解决上述问题,我们创建了 Metis。
基于可重复使用的组件的标准合约库。 与 Openzeppelin 的继承模型不同,Metis 是基于组件的,这意味着用户不会直接继承标准实现。相反,Metis 提供了一组可重用的组件供用户组装。
Metis vs OpenZepplin
继承——由 Openzeppelin 使用 优点:简单—— 最小化为开发人员编写的代码。
缺点:模糊性——隐藏方法的定义;不确定的继承树与多个继承关系。 例如,在 OpenZepplin 中,当你有多个继承时,你可能很难确定该方法是从哪个父合约中继承的。
组合——由 Metis 使用 优点:明确性——提高代码可读性和可听性,用户可以交互的所有功能都被编码到位,这使得代码审计更容易。
缺点:重复性——为现有实现重复编写相同的代码。
MCCI 架构
数据模型——存储。
组件——实现。
控制器——结合不同的组件,ERC20Pausbale -> ERC20, pausable, ownable。
接口——不可变和可变功能,用户交互。
Metis—vs Native ink!(Storage)
用户不再需要自己声明变量了。
标准化数据结构。 让 Dapp 的开发者更容易熟悉接口。
Metis—vs Native ink!(Constructor)
跳过变量初始化的过程。
无需手动触发事件。 开发者可能会忘记触发事件,这将导致区块链浏览器无法捕捉更改,并让用户很难验证他们的交易。
Metis—vs 原生 ink!(Event)
由于 ink! 的当前设计,Event 的写法几乎保持不变。在不久的将来会有所缓解。 我们将使用宏来自动生成基于 Metis 组件的事件。例如,如果你有一个名为 ERC20Pausable 的合约,我们将生成包括在存储声明中的所有事件。
ink!Metis—vs 原生 ink!(Message)
Metis实现包含默认方法实现,确保余额转移的安全性。 例如,检查余额。 注意实现中可能存在的所有注意事项。
允许开发者更多地关注他们的核心逻辑。
设计原则
在软件设计中重写函数显得很愚蠢。
在右侧写代码。 更加自然。
跳过编写所有冗余的代码。
实例化是指在区块链上创建一个智能合约的实例。
调用另一个实例的方法意味着调用另一个合约方法。
跨合约调用以最终会产生错误的结果。
多个组件的组成
无需在存储中列出所有需要的变量。
按需组合,创造更多可能性。
开箱即用的本地测试网
Europa 是 Subtrate 区块链的另一个实现,特别关注于智能合约的开发。
为了更好的开发体验,我们去掉了共识。原因是当我们使用 Canvas 开发合约时,我们发现自动生成的区块真的很困扰我们。因此,Europa 只有在收到新的用户签名交易时才会生成区块。
没有 Wasm Runtime 。虽然 Wasm Runtime 很好,因为它不允许硬分叉区块链升级,但它给调试合约执行带来了更多困难。
状态 KV 数据库。当新的区块被挖掘时,这个额外的数据库会跟踪所有的状态变化。当我们在调试智能合约时非常有用,因为我们可以确定合约真正改变了区块链的底层状态。
修改 contract-pallet。现在,运行 Wasm 智能合约对于合约开发者来说就像一个黑匣子,因为它不会打印出所有的执行细节。因此,我们修改contract-pallet ,允许节点打印出所有执行细节。
Europa UI
Europa UI - 演示
检查所有状态变化。
进行 RPC 调用。
使用跟踪进行 RPC 调用,以获取更多关于合约执行的见解。
嵌套合约调用可能非常混乱。
清楚地说明了跨合约调用的工作原理。
Europa CLI
自定义 RPC europa_forwardToHeight:将区块链转发到一个指定的高度。
europa_backwardToHeight:将区块链还原到一个指定高度,并删除该高度之后的所有区块链状态。
europa_modifiedStateKvs:获取所有区块链状态变化。
自定义命令 状态 - kv:与 RPC 相同:europa_modifiedStateKvs -> 获取所有区块链状态变化。
工作区 - 允许开发者针对不同的测试场景切换到不同的工作区。
合约执行的详细日志记录: 它将在合约执行期间跟踪和打印所有参数和区块链变化。
提供 Wasm panic 回溯以准确定位智能合约中发生错误的位置。
演示
npx redspot-new erc20
记得修改cargo.toml中的依赖关系,从crate.io拉取,否则会与polkadot.js产生兼容问题。ink!更新速度很快,如果我们直接从 ink! git 拉取,会产生兼容问题。我们也看到 Polkadot/app 的问题,但通常它很快就会被修复。
ink_primitives = { version = "3.0.0-rc5", default-features = false }
ink_metadata = { version = "3.0.0-rc5", default-features = false, features = ["derive"], optional = true }
ink_env = { version = "3.0.0-rc5", default-features = false }
ink_storage = { version = "3.0.0-rc5", default-features = false }
ink_lang = { version = "3.0.0-rc5", default-features = false }
redspot.config.ts: 包含 Redspot 的所有配置,例如网络配置。
scripts/deploy.ts: 是将合约部署到区块链的部署脚本。
tests: 包含所有为集成测试编写的测试。
Windows 10 (21H1 及以上) europa-ui-v0.3.32-x86_64-win.exe(https://github.com/patractlabs/europa-ui/releases/download/v0.3.32/europa-ui-v0.3.32-x86_64-win.exe)。
MacOS(10.15.7 及以上)europa-ui-v0.3.32-x86_64-darwin.dmg(https://github.com/patractlabs/europa-ui/releases/download/v0.3.32/europa-ui-v0.3.32-x86_64-darwin.dmg)。
Ubuntu(20.04 及以上)europa-ui-v0.3.32-x86_64-linux.AppImage(https://github.com/patractlabs/europa-ui/releases/download/v0.3.32/europa-ui-v0.3.32-x86_64-linux.AppImage)。
对于 Ubuntu,记得给它权限
chmod +x europa-ui-v0.3.32-x86_64-linux.AppImage
。
只需双击该图标即可启动它。确保默认端口没有被占用。
单击开始以启动节点。
px redspot run scripts/deploy.ts
打开 Europa-UI,你应该可以看到合约已经部署成功。
你可以使用back to Block 来恢复区块链并删除已部署的测试合约。
cp -R contracts ink_contracts
让我们细致的研究下引入metis后合约代码实现的区别: Cargo.toml:导入我们将使用的 Metis 组件。注意 metis_lang 是使用 Metis 的项目的必备条件。另外,注意我们使用的是分支,因为 ink! 的更新非常频繁,为了与 ink! 保持兼容,我们有相应的 Metis 版本。 lib.rs: 我们从 Metis 导入所有依赖项,而不仅仅是use ink_lang as ink;
Storage:我们不再声明我们自己的变量,而是复合了多个 Metis 组件。
Event:不幸的是,我们仍然需要为事件编写所有代码。在 Metis 的下一个版本中,我们将使 Metis 生成这些事件,只要我们在存储中声明了它们。
Message:我们不再需要自己去实现函数,我们可以使用 Metis 的默认植入方式。
Constructor:这些函数没有暴露给区块链上的用户,Metis 的宏会自动生成其中的大部分。所以我们不再需要自己编写它们。
Metis 的组成特点:
正如我们在PPT中提到的,Metis 允许用户根据需要轻松地将不同的组件组合起来。 扩展: hook:你可能会问为什么我们没有在我们的方法实现中添加特定的逻辑来暂停传输。那是因为我们在 Metis 中使用 hook,并且对于每个组件,我们都有一个实现 hook 的扩展列表。
ERC20 扩展:https://github.com/patractlabs/metis/blob/main/crates/components/token/erc20/src/extensions/pausable.rs。该扩展覆盖了before_token_transferhook ,并在其中添加了逻辑。所以我们不再需要在拥有的每个传递函数中实现可暂停的逻辑。
cd contracts
cargo +nightly contract build --keep-debug-symbols --optimization-passes=0
这将在调试模式下构建合约并保留所有调试符号。
mkdir ../artifacts
cp ./target/ink/erc20_pausable.contract ../artifacts/
cp ./target/ink/metadata.json ../artifacts/erc20_pausable.json
7.编写部署脚本。
从deploy.ts复制代码。
npx redspot run scripts/deploy.ts --no-compile
打开 Europa-UI, 查看合约是否部署成功。
从test(https://github.com/bonanyuan/sub0_erc20_pausable/blob/main/tests)中复制所有代码文件。 npx redspot test ./tests/erc20_pausable_init.test.ts --no-compile 测试合约实例化。 npx redspot test ./tests/erc20_pausable_ownable.test.ts --no-compile
所有者被初始化为发件人的地址。 非所有者将能够放弃所有权。 所有者应该能够放弃所有权。 非所有者不能够转让所有权。 所有者可以转让其所有权。 npx redspot test ./tests/erc20_pausable_init.test.ts --no-compile
默认暂停状态为 false。 非所有者应该能够暂停。 所有者应该能够暂停。 所有者可以取消暂停。 没有暂停的传输应该是成功的。 有暂停的传输应该是失败的。
往期精彩:
ink! 开发实践——组合范式(Metis) 之 ERC721及 ReceiverWasm合约测试网Jupiter已发布平行链版本
从EVM到Wasm的范式转换,为什么波卡会成为公链的常青树?
Patract 为波卡 Wasm 合约生态的平行链和 DApp 开发提供解决方案。
How to join Patract官网|https://patract.ioElement|https://app.element.io/#/room/#PatractLabsDev:matrix.orgDiscord|https://discord.gg/znbmjYfvBRPatract 开放平台|https://open.patract.io
Telegram|https://t.me/patract
Twitter|https://twitter.com/PatractLabs
我们正招聘区块链开发工程师、前端/全栈开发工程师、云平台架构师、数据产品经理、产品经理等岗位,可以联系 sean@patract.io
扫码加入Patract微信开发群