ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Aptos 自动气体校准工具 aptos-gas-calibration 完全指南:从 Move 样本到 Native 函数气体参数

2026/9/17 8:19:15 拓冰建站 浏览量
Aptos 自动气体校准工具 aptos-gas-calibration 完全指南:从 Move 样本到 Native 函数气体参数 Aptos 自动气体校准工具 aptos-gas-calibration 完全指南从 Move 样本到 Native 函数气体参数【免费下载链接】aptos-coreAptos is a layer 1 blockchain built to support the widespread use of blockchain through better technology and user experience.项目地址: https://gitcode.com/GitHub_Trending/ap/aptos-coreAptos 链上交易的 Gas 成本由 Move 字节码指令与 Native 函数的气体参数Gas Parameters决定而这些参数需要精确标定才能既防滥用又不损害可用性。本文基于aptos-move/aptos-gas-calibration目录下的官方 README 及其 Rust 实现系统讲解 Aptos Automated Gas Calibration 的工作原理、Move Sample 与 Calibration Function 的编写规范、CLI 用法以及最小二乘求解背后的线性代数细节。读完本文你将掌握如何为新的 Native 函数编写校准样本、运行校准流程并读懂输出中的气体成本与线性依赖诊断信息。工具定位为什么需要自动气体校准Aptos Gas 计价体系区分两种计量方式详见aptos-move/aptos-gas-calibration/src/measurements.rs的注释Regular Gas Meter常规气体计量器生产环境中实际使用的计量器负责记录 Calibration Function 的真实运行时间Abstract Gas Meter抽象气体计量器配合aptos-abstract-gas-usagecrate 使用记录抽象气体用量Abstract Gas Usage即每个气体参数被调用了多少次。Aptos Automated Gas Calibration 正是围绕这两种计量器设计的工具它让任何人都可以通过编写Move Sample甚至 Move 汇编来校准Native Functions与Move 字节码指令的气体参数。工具会同时收集真实运行时间与抽象气体用量两类数据构建线性方程组并求解最终输出每个气体参数的成本。术语速查术语含义User编写 Move Native Functions 的任何人Move Sample位于samples目录下的一个 Move 包packageAbstract Gas Usage记录某个气体参数被调用的次数Calibration Function用于追踪运行时间与抽象气体用量的函数系统的高层工作流程原文档给出了 7 步流程与源码main.rs中main()函数的执行顺序一一对应User 实现 Native 函数及其对应的气体公式Gas Formula编写一个 Move Sample 和若干 Calibration Function测定 Calibration Function 的抽象气体用量以构造气体公式测定 Calibration Function 的运行时间构造一个线性方程对samples目录下的所有 Move Sample 重复第 3、4 步用线性代数方法求解整个线性方程组向 User 输出结果气体参数成本或异常值/无法求解的气体参数。从源码看main.rs中的主流程依次执行compile_and_run()收集测量数据→expand_terms()/aggregate_terms()展开并合并同类项→convert_to_matrix_format()转为矩阵格式→build_coefficient_matrix()/build_constant_matrix()构造系数矩阵与常数矩阵→least_squares()最小二乘求解并输出相关函数分别在 measurements.rs、solve.rs 与 math_interface.rs 中定义。创建 Move Sample在/samples目录下新建一个 Move 项目即对应一个待校准的 Move Samplemkdir MY-PROJECT cd MY-PROJECT cargo run -p aptos -- move init --name MY-PROJECT仓库中已内置一个最简样本 samples/empty其Empty.move展示了最基础的校准函数module empty::empty { public entry fun calibrate_empty_test() { return } }工具在运行时会自动扫描samples目录下的所有顶层 Move 包measurements.rs中的compile_and_run_samples()遍历samples下的每个子目录用aptos-framework的BuiltPackage::build()编译再逐个模块反序列化、扫描校准函数并执行。编写你的第一个 Calibration Function命名与可见性规则Calibration Function 必须同时满足两个条件使用entry关键字标记即可作为交易入口函数名以calibrate_前缀开头。//// 合法 public entry fun calibrate() {} public entry fun calibrate_another_txn() {} public entry fun calibrate123() {} //// 非法 public fun calibrate() {} public fun test_my_txn() {} public entry fun calibrate_addition(_x: u64, _y: u64) {}第三个非法示例很有讲究Calibration Function 目前只允许无参数或单个Signer类型参数。这在源码 measurements_helpers.rs 的list_entrypoints()中有严格校验工具会检查函数的参数签名若首个参数不是Signer类型会直接报错 Failed: only supports 1 parameter that is a signer type at the moment.。因此如果需要在样本中传递迭代次数等参数请像下文示例那样把实现细节放在普通函数里再由无参的entry函数去调用。预期出错的函数_should_error后缀如果某个 Calibration Function 预期会执行失败例如校验某个指令的失败路径请用_should_error后缀标注//// 合法 public entry fun calibrate_my_test_should_error() {} public entry fun calibrate_should_error() {} //// 非法 public entry fun should_error_calibrate() {} public entry fun calibrate_test_error() {} public entry fun calibrate_test_should_error_() {}注意上述非法写法仍是会被执行的合法 Calibration Function只是工具不会把它当作预期报错的函数若其真的报错会按普通失败处理——即后缀位置必须精确地以_should_error结尾。源码中的筛选逻辑在list_entrypoints()中工具会基于编译后的模块CompiledModule逐个检查函数定义不是entry的函数直接跳过函数名不以常量PREFIX即calibrate_定义于 measurements_helpers.rs开头则跳过再与--pattern参数做完全限定名地址::模块::函数的子串匹配最后校验参数签名是否满足条件。这也是为什么我的函数没有被运行类问题最可能的排查点。命令行用法在aptos-move/aptos-gas-calibration目录下运行cargo run --release -- --help Automated Gas Calibration to calibrate Move bytecode and Native Functions Usage: aptos-gas-calibration [OPTIONS] Options: -p, --pattern PATTERN Specific tests to run that match a pattern [default: ] -i, --iterations ITERATIONS Number of iterations to run each Calibration Function [default: 20] -m, --max_execution_time MAX_EXECUTION_TIME Maximum execution time in milliseconds [default: 300] -h, --help Print help三个核心参数在 main.rs 中通过clap解析其含义如下参数默认值作用-p, --pattern空字符串只运行完全限定名匹配该模式的校准函数为空则运行全部-i, --iterations20每个 Calibration Function 重复执行的次数用于获得稳定的运行时间测量-m, --max_execution_time300毫秒假定单笔交易允许的最大执行时间直接参与运行时间 → InternalGas的换算其中max_execution_time的意义很关键在 solve.rs 的convert_to_internal_gas_cost()中工具读取链上交易的max_execution_gas来自TransactionGasParameters::initial()按下式计算每微秒对应的 InternalGas 数量one_microsec_per_internal_gas (max_execution_gas / max_execution_time) / 1000随后把最小二乘解单位为微秒乘以该系数得到最终以 InternalGas 计价的每个气体参数成本。也就是说max_execution_time实际上是把运行时间映射到链上 Gas 预算的换算基准。实战示例校准 blake2b_256原文档以哈希 Native 函数aptos_hash::blake2b_256为例展示了 Move 语言级别的完整校准样本public fun calibrate_blake2b_256_impl(num_iterations: u64) { let i 0; let msg babcdefghijkl while i num_iterations { // This is what I want to calibrate: aptos_hash::blake2b_256(msg); aptos_hash::blake2b_256(msg); aptos_hash::blake2b_256(msg); aptos_hash::blake2b_256(msg); aptos_hash::blake2b_256(msg); aptos_hash::blake2b_256(msg); aptos_hash::blake2b_256(msg); aptos_hash::blake2b_256(msg); aptos_hash::blake2b_256(msg); aptos_hash::blake2b_256(msg); i 1; } } public entry fun calibrate_blake2b_256_x500() { calibrate_blake2b_256_impl(50); } public entry fun calibrate_blake2b_256_x1000() { calibrate_blake2b_256_impl(100); } public entry fun calibrate_blake2b_256_x5000() { calibrate_blake2b_256_impl(500); }这个示例体现了好的 Calibration Function的三个要点目标操作被反复调用blake2b_256在循环体内被调用 10 次让测量对象累积足够多的执行次数避免单次调用的噪声淹没信号整体运行时间足够长循环让函数持续执行一段时间使计时更准确采样多个长度分别提供 500、1000、5000 三个数据点内部是 50/100/500 次迭代 × 每次 10 次哈希调用让系统能在不同负载下采样从而拟合出最佳直线line of best fit。工具随后会用两种计量器分别测量exec_func_record_running_time()配合GasMeterType::UnmeteredGasMeter记录真实运行微秒数exec_abstract_usage()记录抽象气体公式二者共同构成一个线性方程的常数项与系数行。深入源码从测量到求解的完整链路1. 编译与执行measurements.rscompile_and_run()统一处理两条样本路径Move 语言样本samples通过BuiltPackage::build()编译整个 Move 包再调用record_gas_usage()以发布包 → 签名交易 → 依次执行各校准函数的方式测量Move 汇编样本samples_masm使用move-asm的assembler::assemble()将.masm文件汇编成模块executor.add_module()发布后直接执行各入口函数。对每个校准函数工具都会记录三元组数据方程名模块::函数、运行时间微秒存入regular_meter、抽象气体公式存入abstract_meter封装在GasMeasurements结构体中。2. 构造方程组main.rs math_interface.rs每条抽象气体公式本质上是若干个气体参数 × 各自调用次数的线性组合。expand_terms()展开公式后aggregate_terms()合并同类项得到每个气体参数被调用的总次数convert_to_matrix_format()再将其标准化为行向量。于是系数矩阵 A每一行对应一个 Calibration Function每一列对应一个气体参数元素是该函数中该参数的调用次数见 solve.rs 的build_coefficient_matrix()常数矩阵 b每一行对应该函数的实测运行时间build_constant_matrix()。整体构成形如A·x b的超定方程组方程数通常多于未知数。3. 最小二乘求解math.rs由于测量存在噪声方程组通常无精确解math.rs 的compute_least_square_solutions()采用标准正规方程法求最小二乘解x_hat (Aᵀ·A)⁻¹ · Aᵀ·b实现细节先计算AᵀA与Aᵀb检查AᵀA是否可逆is_invertible()若可逆则直接求逆得到最小二乘解x_hat。4. 异常值检测与结果输出math.rs solve.rs拿到x_hat后get_computed_time_and_outliers()会把最小二乘解代回方程组算出每个校准函数的计算运行时间与实际运行时间比较。源码中定义了容差常量MARGIN_OF_ERROR 0.2即 20%相对误差超过 20% 的样本被标记为Outlier其余样本正常展示。输出形式如下正常结果- 模块::函数 | Computed xxxµs vs. Actual xxxµs | Error xxx异常值列表格式相同但单独归类到Outliers are:段落如果AᵀA不可逆工具无法直接求逆会走report_undetermined_gas_params()分支对增广矩阵做行最简阶梯形RREF源码自带带部分主元选择的rref()实现找出线性无关变量与自由变量向你报告无法确定的气体参数详见下文 FAQ。5. 换算为内部气体成本solve.rs最后convert_to_internal_gas_cost()按前述公式把微秒单位的解换算为 InternalGas输出形式为气体参数名 数值。Move 汇编级校准samples_masm当目标是字节码指令本身而非 Native 函数时可以用 Move 汇编编写样本。仓库samples_masm下按指令类别组织了大量示例ld加载指令、operations算术/位运算、operations-bool布尔运算、branch、cast、vector、borrow、struct、generics、global-operations等另有function/gen.py、generics/gen.py这类代码生成脚本用于批量生成不同规模/不同参数组合的汇编样本。以 samples_masm/ld/ldu8.masm 为例原文档 FAQ 中专门点名推荐的好样本其结构清晰展示了同一操作、多个采样长度的标准范式module 0xcafe::LdU8 public fun calibrate_ldu8_impl(l0: u64) local l1: u64 ld_u64 0 st_loc l1 l1: copy_loc l1 copy_loc l0 lt br_false l0 move_loc l1 ld_u64 1 add st_loc l1 ld_u8 1 ld_u8 2 ... ld_u8 10 pop ... branch l1 l0: ret entry public fun calibrate_ldu8_x100() ld_u64 10 call calibrate_ldu8_impl ret entry public fun calibrate_ldu8_x500() ld_u64 50 call calibrate_ldu8_impl ret entry public fun calibrate_ldu8_x1000() ld_u64 100 call calibrate_ldu8_impl ret要点解读用0xcafe这样的固定模块地址发布模块真正的负载10 条ld_u8放在普通函数calibrate_ldu8_impl中通过循环计数器l0控制重复次数三个entry函数分别以 10 / 50 / 100 次循环调用实现对应 100 / 500 / 1000 个采样数据点从而让运行时间随指令次数线性增长的关系能被最小二乘准确拟合。类似的还有 samples_masm/operations/mul.masm乘法指令采样点 x10/x50/x100/x300/x600、samples_masm/bootstrap/core-loop.masmmove_loc/st_loc移动本地变量指令采样点 x10/x50/x100/x300等均遵循循环 多次重复目标指令 多档采样长度的同一范式。常见问题 FAQ需要提供多少个 Calibration Function为了让系统能求出每个气体参数的确定值Calibration Function 的数量至少要与待求解的气体参数中线性独立的样本数一样多。例如若一个函数调用会用到CALL_BASE、CALL_PER_ARG、CALL_PER_LOCAL三个气体参数则至少需要 3 个 Calibration Function它们各自以不同方式组合这三个参数从而形成 3 个线性独立的方程。如何写出好的 Calibration Function好的 Calibration Function 应该运行很多次迭代参考 samples_masm/ld/ldu8.masm让系统记录到有代表性的气体用量。核心思路是在不同长度处采样数据点逼近一条最佳拟合直线。例如ldu8.masm中就有 100、500、1000 三个迭代档位的数据点。档位越多、跨度越大拟合越稳定。气体参数是如何计算的对每个 Calibration Function工具分别测定抽象气体用量与运行时间形成一个线性方程所有 Calibration Function 合起来构成线性方程组然后计算最小二乘解Least Squares Solution。若方程组对应的矩阵不可逆工具会报告无法确定的气体参数或气体参数的线性相关组合具体数学实现在 src/math.rs注意该文件位于aptos-move/aptos-gas-calibration/src/math.rs。若矩阵可逆则用户可以看到全部气体参数值以及各样本的运行时间与异常值。看到 linearly dependent variables 而不是气体成本怎么办如果输出类似linearly dependent variables are: - gas parameter: HASH_BLAKE2B_256_BASE - gas parameter: HASH_BLAKE2B_256_PER_BYTE通常有两种原因Calibration Function 数量不足上例有两个气体参数至少需要两个线性独立的Calibration Function太多 Calibration Function 线性相关即各函数的输入规模、迭代次数设置得过于雷同导致方程彼此成比例。解决办法是改用不同的输入大小和不同的迭代次数重新编写样本制造出线性独立的方程。从源码看当AᵀA不可逆时工具会对增广矩阵做 RREF行最简阶梯形逐行扫描找出线性无关的主元变量其余即被报告为线性相关变量若某列根本没有主元则会以free variables are:的形式报告自由变量。小结Aptos Automated Gas Calibration 把为字节码指令和 Native 函数定价这一原本高度专业的工作抽象成了写样本 → 跑工具 → 读结果的三步流程Move 开发者只需遵循entrycalibrate_前缀、_should_error后缀、无参或单 Signer 参数等少量约定工具便会自动完成编译、双计量器测量、线性方程组构建与最小二乘求解最终输出可直接落地的 InternalGas 成本而面对不可解情形它也会通过线性代数诊断明确指出是样本数量不足还是线性相关引导用户改进样本设计。对于正在为 Aptos 新增 Native 函数或研究 Gas 计费模型的开发者而言samples 与 samples_masm 中的现成样本是最好的起点README 与 src 下的实现则是理解其内部原理的完整参考。【免费下载链接】aptos-coreAptos is a layer 1 blockchain built to support the widespread use of blockchain through better technology and user experience.项目地址: https://gitcode.com/GitHub_Trending/ap/aptos-core创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考