ARTICLE DETAIL

资讯详情

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

Substrate contracts pallet 真实世界合约基准测试指南:benchmarks 目录与 ink!/solang ERC-20 宏基准剖析

Substrate contracts pallet 真实世界合约基准测试指南:benchmarks 目录与 ink!/solang ERC-20 宏基准剖析 区块链开发框架后端【免费下载链接】substrateSubstrate: The platform for blockchain innovators项目地址https://gitcode.com/gh_mirrors/su/substrate点击查看免费下载Substrate 的pallet-contracts智能合约模块在frame/contracts/benchmarks/目录中存放了两组用真实编程语言ink! 与 Solidity/solang编写并编译的 ERC-20 Wasm 合约。本文以该目录及其 README 为核心详细说明这些真实世界合约在 Substrate 合约基准测试体系中的定位——它们不参与权重weight标定而是专门服务于#[extra]宏基准测试用于在大体积 Wasm 模块场景下横向比较不同合约语言与不同执行引擎的差异。读完本文你将掌握benchmarks/目录每个文件的用途、对应基准测试的源码实现与调用链以及如何运行这些宏基准。一、目录概览真实世界合约在基准测试中的角色frame/contracts/benchmarks/目录下共包含 5 个文件文件说明ink_erc20.wasm用 ink! 3.0.0-rc4 编写的 ERC-20 合约编译产物基准测试实际消费的文件ink_erc20_test.wasm同合约的测试专用变体仅在基准测试以测试模式cfg(test)运行时被加载ink_erc20.json对应的 ink! 合约元数据metadata仅作信息参考solang_erc20.wasm用 Solidity 编写、由 Hyperledger solang 0.1.7 编译器产出的 ERC-20 合约基准测试实际消费的文件solang_erc20.json对应的 solang 合约元数据仅作信息参考根据 frame/contracts/benchmarks/README.md 的明确说明本目录的核心定位有两点真实世界real world合约这些不是为基准测试而手工构造的玩具 Wasm而是分别由 ink! 和 solang 两个生态产出的真实合约代码。用于宏基准macro benchmarks而非权重标定它们的用途不是像frame/contracts/src/benchmarking/mod.rs中其余基准那样计算 extrinsic 权重而是用来在更大的 Wasm 模块前提下比较不同的合约语言Rust 系 ink! vs Solidity 系 solang和执行引擎的表现差异。同时 README 特别强调目录中的 JSON 文件仅供信息参考并不参与基准测试的实际执行真正被消费的是.wasm二进制文件。二、这些合约如何被基准测试消费#[extra]与load_benchmark!从源码结构看本目录文件被src/benchmarking中标记为#[extra]的基准测试使用见 frame/contracts/src/benchmarking/mod.rs。Substrate 的frame-benchmarking宏体系中#[extra]基准不会进入权重生成流程而是作为额外补充基准存在这与 README 中不用于确定权重的描述完全吻合。加载 Wasm 文件的核心机制是load_benchmark!宏位于 frame/contracts/src/benchmarking/mod.rsmacro_rules! load_benchmark { ($name:expr) {{ #[cfg(not(test))] { include_bytes!(concat!(../../benchmarks/, $name, .wasm)) } #[cfg(test)] { include_bytes!(concat!(../../benchmarks/, $name, _test.wasm)) } }}; }该宏通过include_bytes!在编译期把 Wasm 二进制直接嵌入 runtime并针对基准测试运行与测试运行两种模式选择不同文件非测试构建加载ink_erc20.wasm测试构建cfg(test)加载ink_erc20_test.wasm。其注释解释了原因ink! 合约依赖的类型大小在测试环境下定义不同因此需要一份专门针对测试环境编译的变体而 solang 合约在这一方面约束更宽松不需要单独的测试版本这也解释了目录中为何没有solang_erc20_test.wasm。三、源码级实现ink_erc20_transfer基准ink_erc20_transfer是消费ink_erc20.wasm的#[extra]基准完整实现位于 frame/contracts/src/benchmarking/mod.rs// Execute one erc20 transfer using the ink! erc20 example contract. #[extra] #[pov_mode Measured] ink_erc20_transfer { let code load_benchmark!(ink_erc20); let data { let new: ([u8; 4], BalanceOfT) ([0x9b, 0xae, 0x9d, 0x5e], 1000u32.into()); new.encode() }; let instance Contract::T::new( WasmModule::from_code(code), data, )?; let data { let transfer: ([u8; 4], AccountIdOfT, BalanceOfT) ( [0x84, 0xa1, 0x5d, 0xa1], account::T::AccountId(receiver, 0, 0), 1u32.into(), ); transfer.encode() }; }: { ContractsT::bare_call( instance.caller, instance.account_id, 0u32.into(), Weight::MAX, None, data, DebugInfo::Skip, CollectEvents::Skip, Determinism::Enforced, ) .result?; }这段代码揭示了完整的调用链可以与ink_erc20.json中的元数据一一对应印证构造函数调用data中首 4 字节0x9b ae 9d 5e正是ink_erc20.json中new构造器的 selector参数为初始供给1000Balance类型即u128。部署Contract::T::new(...)与WasmModule::from_code(code)结合把真实 Wasm 模块部署为链上合约。from_code的实现见 frame/contracts/src/benchmarking/code.rs它会解析 Wasm 模块的导入段提取线性内存的初始页数与最大页数并计算代码哈希。转账调用data中0x84 a1 5d a1正是ink_erc20.json中transfer消息的 selector0x84a15da1携带接收方账户与转账额1。执行通过bare_call不经过 extrinsics 层、绕过签名的底层调用接口执行一次 ERC-20 转账使用Weight::MAX的无限 Gas并以Determinism::Enforced强制确定性执行。从元数据ink_erc20.json可知该合约还包含total_supply、balance_of、allowance、approve、transfer_from等标准 ERC-20 消息存储布局由total_supply、balancesink 的 stash/hashmap 结构与allowances组成错误类型为InsufficientBalance/InsufficientAllowance。基准选择transfer这一可变消息正好覆盖了余额读取、存储写入与事件Transfer派发的完整路径。四、源码级实现solang_erc20_transfer基准solang_erc20_transfer消费solang_erc20.wasm实现位于 frame/contracts/src/benchmarking/mod.rs// Execute one erc20 transfer using the open zeppelin erc20 contract compiled with solang. #[extra] #[pov_mode Measured] solang_erc20_transfer { let code include_bytes!(../../benchmarks/solang_erc20.wasm); let caller account::T::AccountId(instantiator, 0, 0); let mut balance [0u8; 32]; balance[0] 100; let data { let new: ([u8; 4], str, str, [u8; 32], AccountIdOfT) ( [0xa6, 0xf1, 0xf5, 0xe1], KSM, K, balance, caller.clone(), ); new.encode() }; let instance Contract::T::with_caller( caller, WasmModule::from_code(code), data, )?; balance[0] 1; let data { let transfer: ([u8; 4], AccountIdOfT, [u8; 32]) ( [0x6a, 0x46, 0x73, 0x94], account::T::AccountId(receiver, 0, 0), balance, ); transfer.encode() }; }: { ContractsT::bare_call( instance.caller, instance.account_id, 0u32.into(), Weight::MAX, None, data, DebugInfo::Skip, CollectEvents::Skip, Determinism::Enforced, ) .result?; }与 ink! 版本的关键差异点直接include_bytes!由于 solang 合约不需要测试变体这里直接内嵌solang_erc20.wasm未走load_benchmark!宏。构造参数不同selector0xa6 f1 f5 e1对应 solang_erc20.json 中new构造器合约名ERC20PresetFixedSupply参数为代币名KSM、符号K、initialSupply以 32 字节表示的 u256这里首字节为 100以及 owner 账户。u256 语义Solidity 的initialSupply类型为u256对应元数据中的 32 字节编码与 ink! 的u128形成鲜明对比。transfer 参数形态transfer的 selector 为0x6a 46 73 94第三个参数同样以 32 字节[u8; 32]编码数量首字节为 1体现了两种语言 ABI 编码方式的差异。显式指定部署者使用with_caller明确指定instantiator账户而非默认账户。两个基准放在一起恰好构成同一业务ERC-20 转账、两种语言、两套 ABI 编码的对照实验这正是 README 所述比较不同合约语言与执行引擎的直接落地。五、运行这些宏基准测试#[extra]基准的运行方式与普通权重基准相同只是需要加上--extra标志。源码注释中给出了可参考的调试命令见 frame/contracts/src/benchmarking/mod.rs原命令用于输出当前Schedule同样适用于运行本目录相关基准cargo run \ --features runtime-benchmarks \ -- benchmark pallet --extra --dev --executionnative \ -p pallet_contracts -e print_schedule --no-median-slopes --no-min-squares如需运行具体的宏基准可将-e后的参数替换为目标基准名如ink_erc20_transfer、solang_erc20_transfer并保留--extra。需要注意必须以--features runtime-benchmarks特性编译因为src/benchmarking/mod.rs整体以#![cfg(feature runtime-benchmarks)]守卫--executionnative确保以原生 runtime 执行print_schedule这类基准在非 std 环境下会直接返回错误这些基准依赖pallet_balances提供账户资金基准中通过caller_funding为调用者铸币因此运行 runtime 需要同时配置pallet-contracts与pallet-balances。此外src/benchmarking末尾的impl_benchmark_test_suite!宏frame/contracts/src/benchmarking/mod.rs会把上述基准含ink_erc20_transfer挂接到测试套件在测试模式下自动改用ink_erc20_test.wasm执行。六、指令级基准与沙箱宏基准之外的对照值得补充的是本目录的真实合约基准与src/benchmarking中的指令级基准instruction benchmarks形成互补。指令级基准如instr_i64const并不实例化完整合约而是通过 frame/contracts/src/benchmarking/sandbox.rs 中的Sandbox仅实例化 Wasm 执行环境——它使用EmptyEnv不导入任何 seal 函数执行合约的call导出函数并把 wasmi 引擎的燃料fuel设为u64::MAX以纯粹测量单个 Wasm 指令的执行成本。两者的分工可以概括为基准类别输入目的是否参与权重权重基准weight benchmarks程序化生成的 Wasm 模块WasmModule::dummy/sized标定各 extrinsic 与 seal API 的权重是指令级基准instruction benchmarks程序化生成的单指令模块生成每条 Wasm 指令的权重是宏基准macro benchmarks本目录真实世界合约ink!/solang ERC-20对比合约语言与执行引擎、验证大模块场景否#[extra]七、结论与进一步探索frame/contracts/benchmarks/是 Substrate 合约基准测试体系中真实世界验证一环它用 ink! 与 solang 两条技术栈编译出的同业务合约通过#[extra]宏基准在完整的沙箱执行路径部署 → 实例化 →bare_call中运行与程序化生成的合成基准互为印证。JSON 元数据文件则完整记录了合约 ABI、selector、存储布局与编译器信息是理解两个基准中硬编码字节序列如0x9bae9d5e、0x84a15da1、0xa6f1f5e1的权威参考。感兴趣的读者可以继续深入以下路径frame/contracts/benchmarks/ink_erc20.jsonink! ERC-20 完整 ABI 与存储布局frame/contracts/benchmarks/solang_erc20.jsonsolang ERC-20ERC20PresetFixedSupply完整 ABIframe/contracts/src/benchmarking/mod.rs全部基准实现、load_benchmark!宏与运行命令注释frame/contracts/src/benchmarking/code.rsWasmModule构造逻辑from_code、dummy、sizedframe/contracts/src/benchmarking/sandbox.rs指令级基准的无导入沙箱环境。赞分享区块链开发框架后端【免费下载链接】substrateSubstrate: The platform for blockchain innovators项目地址https://gitcode.com/gh_mirrors/su/substrate点击查看免费下载相关推荐Presto 宏基准测试完全指南基于 Benchto 的 presto-benchto-benchmarks 实战详解Presto 宏基准测试完全指南基于 Benchto 的 presto benchto benchmarks 实战详解 本指南以 Presto 仓库中的 pr大数据数据库后端给 Windows Terminal 装上会看时间的皮肤主题自动切换实战给 Windows Terminal 装上会看时间的皮肤主题自动切换实战 周五下午你盯着发白的终端背景皱了皱眉顺手打开「设置 个性化」把应用模式从浅色切区块链开发框架后端SciPy 性能基准测试完全指南基于 Airspeed Velocity 的 benchmarks 框架剖析SciPy 性能基准测试完全指南基于 Airspeed Velocity 的 benchmarks 框架剖析 导读 本文以 benchmarks/README科学计算数据科学高性能计算上一篇Obsidian文档搜索插件终极指南快速索引与智能过滤技巧下一篇Cloudflare Computer 的 Prose 写作规范从代码注释到提交信息的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表