52 个版本 (34 个主要版本)

37.0.0 2024 年 7 月 18 日
35.0.0 2024 年 7 月 12 日
34.0.0 2024 年 6 月 24 日
33.0.0 2024 年 5 月 24 日
2.0.0-alpha.52020 年 3 月 24 日

1412神奇豆

Download history 1272/week @ 2024-04-26 1066/week @ 2024-05-03 793/week @ 2024-05-10 852/week @ 2024-05-17 525/week @ 2024-05-24 566/week @ 2024-05-31 324/week @ 2024-06-07 365/week @ 2024-06-14 638/week @ 2024-06-21 307/week @ 2024-06-28 308/week @ 2024-07-05 960/week @ 2024-07-12 583/week @ 2024-07-19 678/week @ 2024-07-26 579/week @ 2024-08-02 516/week @ 2024-08-09

2,494 每月下载量
22 个crate中 使用 14 个直接使用

Apache-2.0GPL-3.0-only

3.5MB
67K SLoC

合约模块

合约模块为运行时提供部署和执行 WebAssembly 智能合约的功能。

概述

本模块基于 frame_support::traits::fungible 特性扩展账户,使其具有智能合约功能。它可以与其他基于 frame_support::traits::fungible 的账户实现的模块一起使用。这些“智能合约账户”能够实例化智能合约,并调用其他合约和非合约账户。

智能合约代码仅存储一次,以后可以通过其 code_hash 进行检索。这意味着可以从相同的 code 实例化多个智能合约,而不必每次都复制代码。

当调用智能合约时,通过代码哈希检索其相关代码并执行。此调用可以更改智能合约账户的存储条目,实例化新的智能合约,或调用其他智能合约。

最后,当账户被清除时,其关联的智能合约代码和存储也将被删除。

权重

发送者必须为每次调用指定一个 Weight 限制,因为所有由智能合约调用的指令都需要权重。调用后未使用的权重将被退还,无论执行结果如何。

如果达到权重限制,则所有调用和状态更改(包括余额转移)仅回滚到当前调用的合约级别。例如,如果合约A调用B,而B在调用过程中耗尽权重,则B的所有调用都将回滚。假设合约A正确处理了错误,A的其他调用和状态更改仍然持续。

一个 ref_time Weight 被定义为在运行时的参考机器上执行时间的一皮秒。

回滚行为

合约调用失败不会级联。当子调用发生失败时,它们不会“冒泡”上来,调用仅会在特定的合约级别回滚。例如,如果合约A调用合约B,而B失败,A可以决定如何处理此失败,要么继续执行,要么回滚A的更改。

链下执行

一般来说,合约执行必须是确定的,以便所有节点在执行时得出相同的结论。为此,我们禁止任何可能引起不确定性的指令。最显著的是任何浮点运算。话虽如此,有时合约在链下执行,因此不受共识约束。如果代码只由单个节点执行,并且其他参与者隐式信任,则属于这种情况。可信执行环境就属于这种情况。为此,我们允许在以下约束下为链下使用执行不确定性的代码

  1. 不允许从不确定性的代码中实例化任何合约。执行该代码的唯一方法是使用来自确定性合约的委托调用。
  2. 希望使用此功能的代码需要依赖于 pallet-contracts 并直接使用 bare_call()。这确保了默认情况下 pallet-contracts 不暴露任何不确定性。

如何使用

非确定性代码可以通过传递 Determinism::Relaxedupload_code() 来链上部署。确定性合约可以通过使用 bare_call() 并传递 Determinism::Relaxed 来调用它,前提是它是通过该方式运行的。 当合约被链上事务调用时,切勿使用此参数。

接口

可调用的函数

这些在 参考文档 中有记录。

合约暴露的接口

每个合约都是一个类似这样的 WebAssembly 模块

(module
    ;; Invoked by pallet-contracts when a contract is instantiated.
    ;; No arguments and empty return type.
    (func (export "deploy"))

    ;; Invoked by pallet-contracts when a contract is called.
    ;; No arguments and empty return type.
    (func (export "call"))

    ;; If a contract uses memory it must be imported. Memory is optional.
    ;; The maximum allowed memory size depends on the pallet-contracts configuration.
    (import "env" "memory" (memory 1 1))

    ;; This is one of many functions that can be imported and is implemented by pallet-contracts.
    ;; This function is used to copy the result buffer and flags back to the caller.
    (import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
)

所有可导入函数的文档可以在这里找到 这里

使用方法

此模块执行 WebAssembly 智能合约。这些合约可以用任何编译成 Wasm 的语言编写。然而,使用专门针对此模块的语言将使事情变得容易得多。其中一种语言是 ink!。它允许使用 Rust 编程语言编写基于 WebAssembly 的智能合约。

调试

合约可以通过 debug_message API 向客户端发送消息,当作为 RPC 调用时。这些通过 ink! 通过 ink_env::debug_message() 暴露。

这些消息被收集到一个内部缓冲区中,并发送到 RPC 客户端。是否以及如何将这些消息展示给用户由各个客户端自行决定。

此缓冲区也作为调试消息打印出来。为了在节点控制台中看到这些消息,需要将 runtime::contracts 目标的日志级别提高到至少 debug 级别。然而,由于块生成的噪音,这些消息很容易被忽视。在控制台上观察这些消息的好方法是使用以下命令行在 Substrate 仓库的根目录中

cargo run --release -- --dev -lerror,runtime::contracts=debug

这会将 runtime::contracts 的日志级别提高到 debug,并将所有其他目标提高到 error,以防止它们在控制台中 spam。

--dev:使用开发链规范 --tmp:使用临时存储链数据(链状态在退出时被删除)

主机函数跟踪

对于合约作者来说,这是一个有用的调试工具,可以查看哪些主机函数被调用,使用哪些参数,以及结果是什么。

为了在节点控制台中看到这些消息,需要将 runtime::contracts::strace 目标的日志级别提高到 trace 级别。

示例

cargo run --release -- --dev -lerror,runtime::contracts::strace=trace,runtime::contracts=debug

不稳定的接口

由于希望在开发新的合约接口时采用迭代方法,这个组件包含了一个不稳定接口的概念。类似于Rust的nightly编译器,它允许我们添加新的接口,但将它们标记为不稳定,这样合约语言就可以在正式稳定之前对其进行实验并给出反馈。

为了访问在runtime.rs中标记为 #[unstable] 的接口,需要将 pallet_contracts::Config::UnsafeUnstableInterface 设置为 ConstU32<true>显然,任何生产环境下的运行时都不应该使用这个特性:除了可能会更改或删除之外,这些接口可能没有正确的权重与之关联,因此被视为不安全

新接口通常以不稳定的形式添加,在晋升为稳定接口之前可能需要经历几个迭代。

许可证:Apache-2.0

依赖关系

~22–38MB
~659K SLoC