22 个版本 (5 个重大变更)

0.6.0 2020年3月14日
0.4.2 2020年2月26日
0.3.9 2019年12月19日
0.3.7 2019年11月23日
0.1.0 2019年7月22日

#2519 in 魔法豆

Apache-2.0

120KB
2.5K SLoC

near-bindgen

Rust 编写 NEAR 智能合约的库。

Crates.io version Download Join the community on Discord Travis Build

特性 | 先决条件 | 编写 Rust 合约 | 构建 Rust 合约

示例

使用 #[near_bindgen] 包装一个结构体,它将生成与 NEAR 区块链兼容的智能合约

#[near_bindgen]
#[derive(Default, BorshDeserialize, BorshSerialize)]
pub struct StatusMessage {
    records: HashMap<String, String>,
}

#[near_bindgen]
impl StatusMessage {
    pub fn set_status(&mut self, message: String) {
        let account_id = env::signer_account_id();
        self.records.insert(account_id, message);
    }

    pub fn get_status(&self, account_id: String) -> Option<String> {
        self.records.get(&account_id).cloned()
    }
}

特性

  • 可单元测试。 使用 near-bindgen 编写单元测试很容易

    #[test]
    fn set_get_message() {
        let context = get_context(vec![]);
        testing_env!(context);
        let mut contract = StatusMessage::default();
        contract.set_status("hello".to_string());
        assert_eq!("hello".to_string(), contract.get_status("bob_near".to_string()).unwrap());
    }
    

    像通常一样运行单元测试

    cargo test --package status-message
    
  • 异步跨合约调用。 异步跨合约调用允许多个合约并行执行,并在另一个合约上后续聚合。 env 提供以下方法

    • promise_create -- 在某个合约上安排函数执行;
    • promise_then -- 一旦函数执行完毕,将回调附加到当前合约;
    • promise_and -- 组合器,允许在执行回调之前同时等待多个承诺;
    • promise_return -- 将承诺的执行结果视为当前函数的结果。

    按照 examples/cross-contract-high-level 中的说明,查看跨合约调用的各种用法,包括在合约内部执行的 系统级操作,例如余额转账(其他系统级操作的例子包括:账户创建、访问密钥创建/删除、合约部署等)。

  • 初始化方法。 我们可以定义一个初始化方法,用于初始化合约的状态。

    #[near_bindgen]
    impl StatusMessage {
      #[init]
      pub fn new(user: String, status: String) -> Self {
          let mut res = Self::default();
          res.records.insert(user, status);
          res
      }
    }
    

即使你有初始化方法,你的智能合约仍然需要推导 Default 特性。如果你不想禁用默认初始化,可以像这样禁止它:

impl Default for StatusMessage {
    fn default() -> Self {
        panic!("Contract should be initialized before the usage.")
    }
}

先决条件

要开发 Rust 合约,你需要

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • 将 wasm 目标添加到你的工具链中
rustup target add wasm32-unknown-unknown

编写 Rust 合约

你可以参考 examples/status-message 库,它展示了简单的 Rust 合约。

一般工作流程如下

  1. 创建一个 crate 并配置 Cargo.toml,类似于 examples/status-message/Cargo.toml 中的配置;

  2. crate 需要有一个 pub 结构体,它将代表智能合约本身

    • 该结构体需要实现 Default 特性,NEAR 将使用它来创建合约的初始状态;
    • 该结构体还需要实现 BorshSerializeBorshDeserialize 特性,NEAR 将使用它们来保存/加载合约的内部状态;

    以下是一个智能合约结构体的示例

    #[near_bindgen]
    #[derive(Default, BorshSerialize, BorshDeserialize)]
    pub struct MyContract {
        data: HashMap<u64, u64>
    }
    
  3. 定义 NEAR 将将其公开为智能合约方法的函数

    • 你可以为结构体定义任何方法,但只有公共方法将被公开为智能合约方法;
    • 方法需要使用 &self&mut selfself
    • 使用 #[near_bindgen] 宏装饰 impl 部分。这就是 M.A.G.I.C. (Macros-Auto-Generated Injected Code) 发生的地方
    • 如果你需要使用区块链接口,例如获取当前账户 ID,则可以使用 env::* 访问它;

    以下是一个智能合约方法的示例

    #[near_bindgen]
    impl MyContract {
       pub fn insert_data(&mut self, key: u64, value: u64) -> Option<u64> {
           self.data.insert(key)
       }
       pub fn get_data(&self, key: u64) -> Option<u64> {
           self.data.get(&key).cloned()
       }
    }
    

构建 Rust 合约

我们可以使用 rustc 构建合约

RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release

依赖关系

~2.5–3.5MB
~68K SLoC