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 日 |
4 在 #near-bindgen 中排名 #4
每月下载 55 次
在 2 个crate中使用(通过near-bindgen-macros)
68KB
1.5K SLoC
near-sdk
用于编写 NEAR 智能合约的 Rust 库。
之前被称为 near-bindgen
。
功能 | 先决条件 | 编写 Rust 合约 | 构建 Rust 合约 | 参考文档 | 贡献
发行说明
发行说明和未发布更改可以在 CHANGELOG 中找到
示例
使用 #[near_bindgen]
包装一个结构体,并生成与 NEAR 区块链兼容的智能合约
use near_sdk::{near_bindgen, env};
#[near_bindgen]
#[derive(Default, BorshDeserialize, BorshSerialize)]
#[borsh(crate = "near_sdk::borsh")]
pub struct StatusMessage {
records: HashMap<AccountId, 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: AccountId) -> Option<String> {
self.records.get(&account_id).cloned()
}
}
功能
单元测试
使用 near-sdk
,编写单元测试非常容易
#[test]
fn set_get_message() {
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 以查看跨合约调用的各种用法,包括在合约内部执行的 系统级操作,例如余额转移(其他系统级操作的示例包括:创建账户、创建/删除访问密钥、合约部署等)。
初始化方法
我们可以定义一个初始化方法,用于初始化合约的状态。代码 #[init]
验证合约尚未初始化(合约状态不存在),否则将引发恐慌。
#[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 {
near_sdk::env::panic_str("Contract should be initialized before the usage.")
}
}
你也可以使用 near_sdk::PanicOnDefault
辅助宏来禁止 Default
特性初始化。例如。
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
#[borsh(crate = "near_sdk::borsh")]
pub struct StatusMessage {
records: HashMap<String, String>,
}
可支付方法
我们可以允许方法在接受函数调用时接受代币转移。这样做是为了让合约能够定义在它们被使用时需要支付的代币费用。默认情况下,方法不是可支付的,如果有人尝试在调用期间向它们转移代币,则会引发恐慌。这是出于安全考虑,以防有人意外地在函数调用期间转移代币。
要声明一个可支付方法,只需使用 #[payable]
装饰器
#[payable]
pub fn my_method(&mut self) {
...
}
私有方法
通常,当合约需要远程跨合约调用的回调时,这个回调方法应由合约本身调用。这是为了避免其他人调用它并搞乱状态。常见的模式是使用断言来验证直接调用者(前一个账户 ID)与合约的账户(当前账户 ID)匹配。宏 #[private]
通过将其简化为一个单行宏来简化它,并提高可读性。
要声明一个私有方法,请使用 #[private]
装饰器
#[private]
pub fn my_method(&mut self) {
...
}
/// Which is equivalent to
pub fn my_method(&mut self ) {
if near_sdk::env::current_account_id() != near_sdk::env::predecessor_account_id() {
near_sdk::env::panic_str("Method my_method is private");
}
...
}
现在,只有合约自身的账户可以调用此方法,无论是直接调用还是通过承诺。
先决条件
要开发 Rust 合约,你需要
- 安装 Rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- 将 wasm 目标添加到您的工具链
rustup target add wasm32-unknown-unknown
编写 Rust 合约
你可以参考 examples/status-message 示例,它展示了一个简单的 Rust 合约。
一般工作流程如下
-
创建一个 crate 并配置
Cargo.toml
与 examples/status-message/Cargo.toml 中的配置类似; -
该 crate 需要有一个
pub
结构,该结构将代表智能合约本身- 该结构需要实现
Default
特性,NEAR 将使用它来在合约首次使用时创建初始状态 - 结构体还需要实现 NEAR 将用于保存/加载合约内部状态的
BorshSerialize
和BorshDeserialize
特性;
以下是一个智能合约结构的示例;
use near_sdk::{near_bindgen, env}; #[near_bindgen] #[derive(Default, BorshSerialize, BorshDeserialize)] #[borsh(crate = "near_sdk::borsh")] pub struct MyContract { data: HashMap<u64, u64> }
- 该结构需要实现
-
定义 NEAR 将公开为智能合约方法的函数;
- 您可以定义结构体的任何方法,但只有公共方法才会公开为智能合约方法;
- 方法需要使用
&self
、&mut self
或self
; - 使用
#[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 合约;
cargo-near;
这可以作为替代方案使用,同时允许构建并生成 abi;
# Install the near extension if you haven't already
cargo install cargo-near
# Builds the wasm contract and ABI into `target/near`
cargo near build --release
使用 cargo build;
RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release
使用可重复构建进行构建;
由于 WebAssembly 编译器将大量调试信息包含到二进制文件中,因此生成的二进制文件在不同机器上可能会有所不同。为了能够以可重复的方式编译二进制文件,我们添加了一个 Dockerfile,允许编译二进制文件。
使用 contract-builder;
NEAR 合约标准;
near-contract-standards
crate 为 NEAR 的合约标准提供了一组接口和实现;
版本控制;
语义版本控制;
此 crate 遵循 Cargo 的 semver 指南。
状态破坏性更改(任何数据类型的低级序列化格式)将不惜一切代价避免。如果发生此类更改,则将伴随一个主要版本,并带有编译器错误。如果您遇到一个没有这种情况的错误,请 打开一个 issue!
MSRV;
目前的最小支持 Rust 版本是 1.72
。如果需要发布一个需要增加 Rust 工具链的安全补丁版本,则无法保证会保持这一保证。
贡献;
如果您有兴趣进行贡献,请查看 贡献指南。
依赖项;
~1.5MB;
~36K SLoC;