十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Amadeus Rust 智能合约 SDK 完全实战指南:从环境搭建到测试网部署

Amadeus Rust 智能合约 SDK 完全实战指南:从环境搭建到测试网部署 Amadeus Rust 智能合约 SDK 完全实战指南从环境搭建到测试网部署【免费下载链接】node项目地址: https://gitcode.com/GitHub_Trending/node95/node本文是 Amadeus 区块链 Rust 智能合约 SDK 的实战技术指南基于仓库中的 contract_samples/rust/README.md 及其源码展开。你将学会如何配置 Rust 交叉编译环境、使用amadeus-cli构建并优化 Wasm 合约以及将 counter、deposit、coin、nft 四个示例合约完整部署到 Amadeus 测试网并调用验证。读完本文你将具备独立编写、构建、部署和测试 Amadeus Rust 智能合约的完整能力。一、Amadeus Rust SDK 概览Amadeus 区块链的智能合约以 WebAssemblyWasm形式运行开发者可以使用 Rust 编写合约再编译为wasm32-unknown-unknown目标。仓库中的amadeus-sdk位于 contract_samples/rust为合约开发提供了完整的运行时支撑包括无标准库no_std环境合约代码运行在受限的 Wasm 沙箱中无法依赖操作系统能力KV 持久化存储通过宿主导入函数读写链上键值数据上下文访问读取交易签名者、调用者、附加资产attachment等链上环境信息跨合约调用以call!宏发起对其他合约函数的调用数据编解码字节读取、Base58、十六进制与整数转换等工具。SDK 的全部对外能力通过 src/lib.rs、src/context.rs、src/storage.rs 与 src/encoding.rs 四个模块导出后续章节会逐一深入。二、环境准备Prerequisites1. 安装 Rust 并添加 Wasm 编译目标合约需要编译为 WebAssembly 目标请依次执行curl https://sh.rustup.rs -sSf | sh rustup update rustup target add wasm32-unknown-unknown说明wasm32-unknown-unknown是面向无操作系统 WebAssembly 环境的编译目标配合 rust-toolchain.toml 锁定的工具链版本可保证构建结果的一致性。2. 安装 amadeus-cliamadeus-cli是部署与交互的命令行工具通过 cargo 安装cargo install amadeus-cli安装完成后即可使用ama命令生成密钥对、构造交易并部署合约详见测试网部署章节。如需了解更完整的部署与测试流程可参考同仓库的 AssemblyScript 合约教程其中对amadeusd的用法有更详细的说明。三、构建智能合约1. 一键构建脚本仓库提供了build_and_validate.sh脚本一键完成四个示例合约的构建与校验./build_and_validate.sh从脚本内容build_and_validate.sh可以看到其核心流程分为两步第一步交叉编译四个示例合约cargo build --example counter --target wasm32-unknown-unknown --release cargo build --example deposit --target wasm32-unknown-unknown --release cargo build --example coin --target wasm32-unknown-unknown --release cargo build --example nft --target wasm32-unknown-unknown --release第二步调用主网校验接口验证 Wasm 合法性脚本将每个.wasm文件以application/octet-stream的二进制格式 POST 到主网校验接口https://mainnet-rpc.ama.one/api/contract/validate确认合约字节码符合链上执行要求如内存导入、导出函数签名等例如curl -X POST -H Content-Type: application/octet-stream \ --data-binary target/wasm32-unknown-unknown/release/examples/counter.wasm \ https://mainnet-rpc.ama.one/api/contract/validate2. 构建产物位置构建产物统一输出到target/wasm32-unknown-unknown/release/examples/即counter.wasm、deposit.wasm、coin.wasm、nft.wasm四个文件。这四个示例在 Cargo.toml 中均以crate-type [cdylib]声明确保链接为可被 Wasm 运行时加载的动态库形式。3. 构建配置要点Cargo.toml 中针对合约场景做了专门的发布配置优化[profile.release] opt-level z # 以体积优化为目标 lto true # 启用链接时优化消除死代码 codegen-units 1 # 单代码生成单元利于整体优化 strip true # 剥离符号表减小体积 panic abort # panic 直接中止避免 unwinding 开销panic abort与 SDK 中的自定义 panic handlersrc/lib.rs 中的#[panic_handler]相互配合合约 panic 后直接进入loop {}挂起由链上运行时判定执行失败从而杜绝 unwinding 在 Wasm 环境中的不可控行为。四、优化 Wasm 产物可选默认构建产物可能包含冗余代码可使用wasm-optBinaryen 工具集以-Oz级别做激进体积优化并显式开启 bulk memory 特性wasm-opt -Oz --enable-bulk-memory target/wasm32-unknown-unknown/release/examples/counter.wasm -o counter.wasm wasm-opt -Oz --enable-bulk-memory target/wasm32-unknown-unknown/release/examples/deposit.wasm -o deposit.wasm wasm-opt -Oz --enable-bulk-memory target/wasm32-unknown-unknown/release/examples/coin.wasm -o coin.wasm wasm-opt -Oz --enable-bulk-memory target/wasm32-unknown-unknown/release/examples/nft.wasm -o nft.wasm--enable-bulk-memory允许使用 Wasm 的 bulk memory 指令memory.copy/memory.fill这在合约频繁操作字节数组如read_bytes时能显著提升性能。优化后的counter.wasm等文件即为最终可部署的合约字节码。五、测试网部署与交互四个示例全流程完成构建后就可以在测试网上部署合约。以下流程全部基于原文档命令中出现的wallet.sk充当持有测试币的账户其余.sk为各合约的专属签名私钥文件。1. 准备工作创建钱包并领取测试币ama gen-sk wallet.sk # 生成钱包私钥文件 ama get-pk --sk wallet.sk # 由私钥导出公钥pk注意请将公钥填入测试网水龙头 https://mcp.ama.one/testnet-faucet 领取测试网 AMA后续所有转账操作都需要钱包持有足够的 AMA 作为手续费与转账资金。后续每个合约流程的模式是高度一致的均遵循转账手续费 → 部署合约 → 调用方法 → 查看结果的步骤其中--url https://testnet-rpc.ama.one指定测试网 RPC 节点。2. Counter计数器合约ama gen-sk counter.sk export COUNTER_PK$(ama get-pk --sk counter.sk) ama tx --sk wallet.sk --url https://testnet-rpc.ama.one Coin transfer [{b58: $COUNTER_PK}, 2000000000, AMA] ama deploy-tx --sk counter.sk counter.wasm --url https://testnet-rpc.ama.one ama tx --sk counter.sk --url https://testnet-rpc.ama.one $COUNTER_PK init [] curl https://testnet-rpc.ama.one/api/contract/view/$COUNTER_PK/get ama tx --sk wallet.sk --url https://testnet-rpc.ama.one $COUNTER_PK increment [5] curl https://testnet-rpc.ama.one/api/contract/view/$COUNTER_PK/get操作解读Coin transfer将 20 亿2000000000聪最小单位的 AMA 从钱包转给合约账户作为手续费资金deploy-tx部署counter.wasm部署后合约地址即$COUNTER_PKinit []调用合约的init方法完成初始化通过 RPC 只读接口GET /api/contract/view/{pk}/get读取get方法的返回值此时应为 0increment [5]传入参数 5 增加计数再次get应返回 5。3. Deposit存币/取币保险库合约ama gen-sk deposit.sk export DEPOSIT_PK$(ama get-pk --sk deposit.sk) ama tx --sk wallet.sk Coin transfer [{b58: $DEPOSIT_PK}, 2000000000, AMA] --url https://testnet-rpc.ama.one ama deploy-tx --sk deposit.sk deposit.wasm --url https://testnet-rpc.ama.one ama tx --sk wallet.sk $DEPOSIT_PK balance [AMA] --url https://testnet-rpc.ama.one ama tx --sk wallet.sk $DEPOSIT_PK deposit [] AMA 1500000000 --url https://testnet-rpc.ama.one ama tx --sk wallet.sk $DEPOSIT_PK balance [AMA] --url https://testnet-rpc.ama.one操作解读balance [AMA]查询钱包在保险库中 AMA 的余额deposit [] AMA 1500000000是带附件attachment的调用——AMA为附加的资产符号1500000000为附加的资产数量即将 15 亿聪 AMA 存入保险库再次查询balance应看到余额增加且存入的资产以vault:{caller}:{symbol}为键记录在链上 KV 存储中见 examples/deposit.rs 的vault_key函数。4. Coin代币铸造与流通合约ama gen-sk coin.sk export COIN_PK$(ama get-pk --sk coin.sk) ama tx --sk wallet.sk Coin transfer [{b58: $COIN_PK}, 2000000000, AMA] --url https://testnet-rpc.ama.one ama deploy-tx --sk coin.sk coin.wasm --url https://testnet-rpc.ama.one ama tx --sk wallet.sk $COIN_PK deposit [] AMA 1500000000 --url https://testnet-rpc.ama.one ama tx --sk wallet.sk $COIN_PK withdraw [AMA, 500000000] --url https://testnet-rpc.ama.one ama tx --sk wallet.sk $COIN_PK withdraw [AMA, 1000000000] --url https://testnet-rpc.ama.one操作解读init时合约通过跨合约调用Coin.create_and_mint铸造了 10 亿个 9 位小数的USDFAKE代币见 examples/coin.rs 中的encoding::coin_raw(1_000_000_000, 9)deposit将 AMA 存入保险库作为质押资金withdraw [AMA, 500000000]与withdraw [AMA, 1000000000]连续两次取出 5 亿与 10 亿聪 AMA验证余额充足性校验insufficient funds断言与取款转账逻辑。5. NFT非同质化代币合约# WARNING: AGENTIC collection 已存在请替换下面的名称 # 并同步修改 examples/nft.rs 文件修改后记得重新构建 nft.wasm ama gen-sk nft.sk export NFT_PK$(ama get-pk --sk nft.sk) ama tx --sk wallet.sk Coin transfer [{b58: $NFT_PK}, 2000000000, AMA] --url https://testnet-rpc.ama.one ama deploy-tx --sk nft.sk nft.wasm --url https://testnet-rpc.ama.one ama tx --sk wallet.sk $NFT_PK init [] --url https://testnet-rpc.ama.one ama tx --sk wallet.sk $NFT_PK claim [] --url https://testnet-rpc.ama.one ama tx --sk wallet.sk $NFT_PK view_nft [AGENTIC, 1] --url https://testnet-rpc.ama.one ama tx --sk wallet.sk $NFT_PK claim [] --url https://testnet-rpc.ama.one操作解读init调用Nft.create_collection创建名为AGENTIC的 NFT 集合claim每次调用会铸造 2 个固定编号为 2 的 NFT外加 1 个通过roll_dice()掷骰子得到的 16 随机编号 NFTview_nft [AGENTIC, 1]查询集合中编号 1 的 NFT 元数据返回 IPFS 上的元数据 URL。注意文档中的警告AGENTIC集合在测试网上已存在重复创建会失败。如需自行测试必须更换集合名称同时修改 examples/nft.rs 中的字符串并重新执行./build_and_validate.sh。六、源码级解读SDK 内部实现为了让读者不仅会跑而且懂原理下面结合 SDK 源码剖析合约运行时的关键机制。1. 合约入口no_std 与导出函数所有合约以#![no_std]、#![no_main]开头并通过#[no_mangle] pub extern C导出供链上调用的函数。以 examples/counter.rs 为例#![no_std] #![no_main] extern crate alloc; use amadeus_sdk::*; #[no_mangle] pub extern C fn init() { log(Init called during deployment of contract); kv_put(inited, true); } #[no_mangle] pub extern C fn increment(amount_ptr: i32) { let amount read_bytes(amount_ptr); let new_counter kv_increment(the_counter, amount); ret(new_counter); }关键点函数参数是以i32形式传入的内存指针指向链上运行时写入合约内存的长度 数据结构返回值则通过ret()写入 Wasm 内存供运行时读取。SDK 在 src/encoding.rs 中提供了read_bytes/read_string将指针解引用为 Rust 数据pub fn read_bytes(ptr: i32) - Vecu8 { unsafe { let len *(ptr as *const i32); // 前 4 字节为长度 let data (ptr 4) as *const u8; // 其后为数据 core::slice::from_raw_parts(data, len as usize).to_vec() } }2. KV 持久化存储storage 模块合约状态存储依赖宿主环境导入的 KV 原语SDK 在 src/storage.rs 中通过extern C声明了 7 个宿主导入函数extern C { fn import_kv_get(p: *const u8, l: usize) - i32; fn import_kv_exists(p: *const u8, l: usize) - i32; fn import_kv_get_prev(pp: *const u8, pl: usize, kp: *const u8, kl: usize) - i32; fn import_kv_get_next(pp: *const u8, pl: usize, kp: *const u8, kl: usize) - i32; fn import_kv_put(kp: *const u8, kl: usize, vp: *const u8, vl: usize); fn import_kv_increment(kp: *const u8, kl: usize, vp: *const u8, vl: usize) - i32; fn import_kv_delete(p: *const u8, l: usize); }并在此基础上封装了高层 APIAPI说明返回值kv_put(key, value)写入键值对无kv_getT(key)读取值并解码为FromKvBytes类型OptionT键不存在返回Nonekv_increment(key, amount)对键的值做增量运算amount 可为负更新后的值Stringkv_delete(key)删除键无kv_exists(key)键是否存在boolkv_get_prev(prefix, key)前缀扫描获取小于等于 key 的前一个键值(OptionVecu8, OptionVecu8)kv_get_next(prefix, key)前缀扫描获取大于等于 key 的后一个键值(OptionVecu8, OptionVecu8)其中kv_get通过类型系统完成解码任何实现了FromKvBytes的类型Vecu8及全部整数类型都能直接作为泛型参数整数解码复用 src/encoding.rs 中的bytes_to_i8/i16/.../u128这些函数将字节先转为 UTF-8 字符串再parse为整数非法格式会触发abort!宏。3. 上下文与跨合约调用context 模块src/context.rs 通过固定内存地址读取链上上下文信息pub fn seed() - Vecu8 { read_bytes(1100) } // 随机种子 pub fn entry_slot() - u64 { read_u64(2000) } pub fn entry_height() - u64 { read_u64(2010) } pub fn entry_epoch() - u64 { read_u64(2020) } pub fn tx_nonce() - u64 { read_u64(3000) } pub fn tx_signer() - Vecu8 { read_bytes(3100) } pub fn account_current() - Vecu8 { read_bytes(4000) } // 当前合约地址 pub fn account_caller() - Vecu8 { read_bytes(4100) } // 调用者地址 pub fn account_origin() - Vecu8 { read_bytes(4200) } // 原始发起者地址 pub fn attached_symbol() - Vecu8 { read_bytes(5000) } // 附加资产符号 pub fn attached_amount() - Vecu8 { read_bytes(5100) } // 附加资产数量合约开发中常用的两个组合读取附件get_attachment()检查 5000 地址处的 4 字节头是否为 0非 0 则返回(true, (symbol, amount))这正是 deposit/coin 合约处理带资调用的基础记录调用者account_caller()在 deposit 的vault_key中用于将每个用户的余额隔离存储vault:{caller}:{symbol}实现多用户共享合约账户下的独立账本。跨合约调用通过call!宏实现宏定义在 src/context.rscall!(contract, func, [arg1, arg2, ...]); // 普通调用 call!(contract, func, [arg1, ...], [extra_arg1, ...]); // 带附件调用其底层call函数会构造一张参数表[Count][Ptr][Len]...见build_table调用宿主导入的import_call并把返回的错误指针解码为Vecu8。示例中的典型用法call!(Coin, transfer, [account_caller(), withdraw_amount, withdraw_symbol])deposit 提款时把保险库中的币转回用户call!(Nft, mint, [account_caller(), 1, AGENTIC, random_token])NFT 铸造。4. 数据编解码encoding 模块src/encoding.rs 提供合约开发所需的全部编解码工具read_bytes/read_string读取指针指向的内存数据b58_encode/b58_decodeBase58 编码地址与公钥的标准表示形式hex_encode十六进制编码coin_raw(amount, decimals)将整数金额 小数位数转换为代币最小单位原始值如coin_raw(1_000_000_000, 9)表示 10 亿个 9 位小数代币即 1 个USDFAKE单位换算成最小粒度bytes_to_i8 ~ bytes_to_u128字节转整数带 UTF-8 校验与格式校验失败即abort!。5. 宏与运行时支撑lib.rssrc/lib.rs 定义了 SDK 的根设施assert!宏条件不满足时先log错误消息再执行core::arch::wasm32::unreachable()触发 Wasm trap从而回滚本次调用——deposit 合约中的amadeus_sdk::assert!(amount_i128 100, deposit amount less than 100)就是用它做金额下限校验abort!宏直接中止执行并回滚用于编解码失败等不可恢复错误b!宏将多个AsRef[u8]片段拼接为Vecu8如b!(vault:, account_caller(), :, symbol)Payloadtrait统一str/String/[u8]/Vecu8/整数类型到字节的转换是所有 KV 与日志 API 的参数抽象全局分配器使用dlmalloc::GlobalDlmalloc保证合约在 Wasm 环境下具备可用的动态内存分配Vec、String等依赖于此panic handler非测试构建下 panic 后死循环挂起交由链上判定失败。七、示例合约的工程实践要点将四个示例放在一起对比可以提炼出 Amadeus 合约开发的通用模式示例核心功能关键 SDK 用法状态存储键counter计数器、跨合约计数kv_put/kv_get/kv_increment、call!the_counter、initeddeposit多用户保险库存取get_attachment、kv_increment、call!转账vault:{caller}:{symbol}coin代币质押与提现coin_raw、assert!、call!铸造/转账vault:{caller}:{symbol}nftNFT 集合铸造与查询call!创建/铸造、seed()驱动的 PRNG链上Nft合约管理工程要点归纳参数一律以指针传入外部调用的每个参数都是i32内存指针需用read_bytes/read_string解引用用assert!/abort!做防御式校验不满足前置条件即触发 unreachable保证链上状态一致性用b!宏构造复合键实现按用户、按资产符号隔离的账本跨合约交互全部走call!无法直接读写其他合约的存储必须通过其导出的函数init负责部署期初始化在部署交易的init调用中完成集合创建、代币铸造等一次性逻辑。八、常见问题与排错提示AGENTIC集合已存在导致 NFT 部署失败更换集合名并同步修改 examples/nft.rs 后重新构建水龙头领取失败确保将ama get-pk --sk wallet.sk输出的公钥完整填入水龙头且领取的是测试网 AMA部署校验失败确认.wasm文件确实位于target/wasm32-unknown-unknown/release/examples/且未损坏可手动调用curl -X POST ... /api/contract/validate查看具体错误deposit 金额过小合约断言存款必须大于 100 最小单位转账时注意数值换算环境变量未生效每个终端会话都需要重新export COUNTER_PK$(ama get-pk --sk counter.sk)之类的变量或在同一会话内连续执行全部命令。结语通过本文你已经走通了 Amadeus Rust 智能合约的完整链路环境搭建 → 交叉编译 → Wasm 优化 → 测试网部署与交互并深入理解了 SDK 的 KV 存储、上下文读取、跨合约调用与编解码实现。四个示例合约覆盖了计数器、保险库、代币与 NFT 四类典型场景可作为开发自有合约的起点模板。相关完整源码与构建脚本均可在 contract_samples/rust 目录下查阅与复用。【免费下载链接】node项目地址: https://gitcode.com/GitHub_Trending/node95/node创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表