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

资讯详情

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

Aptos Move 字节码校验器计量测试(Metering Tests)运行指南:测量“复杂程序“被拒绝或接受的时间

Aptos Move 字节码校验器计量测试(Metering Tests)运行指南:测量“复杂程序“被拒绝或接受的时间 Aptos Move 字节码校验器计量测试Metering Tests运行指南测量复杂程序被拒绝或接受的时间【免费下载链接】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本文围绕仓库内 METER_TESTING.md 展开讲解如何在 Aptos Core 的 Move 字节码校验器测试套件中以计量metering测试模式运行测试观察一个复杂程序在校验器中被检测拒绝或被接受各自所耗费的时间。读者将掌握该测试命令的完整语义、输出信息的来源源码埋点、计量机制的底层实现Meter trait 与 BoundMeter、生产环境计量上限配置以及构造复杂程序测试用例的方法从而能够自行复现实验并读懂校验器的性能与复杂度控制行为。一、背景为什么字节码校验器需要计量测试Move 字节码校验器Bytecode Verifier在链上合约加载、交易执行前对模块与脚本进行多趟静态检查保证字节码满足类型安全、引用安全、资源安全等约束。攻击者可以构造结构上合法但计算量爆炸的程序例如大量循环回边 back edge、深层类型实例化来拖垮校验器因此校验器引入了计量metering机制给模块级、函数级分别设置可消耗的计量单位units上限一旦超出即判定程序过于复杂program too complex并拒绝。计量相关代码集中在 meter.rs而计量测试则位于bytecode-verifier-tests测试包。测试包中的用例会构造各种合法或非法的字节码样本其中一部分专门用于验证复杂程序能否在合理时间内被检测或接受——这正是 METER_TESTING.md 所要说明的测试方式。二、核心命令以计量模式运行测试套件METER_TESTING.md 全文给出了如下一条命令cargo test --release --featuresaddress32 -- --nocapture 1/dev/null文档原文描述为该测试套件可以用一种特殊方式运行以打印直到一个复杂程序被检测或被接受所经历的时间。即该命令并非普通的通过/失败断言运行而是让每个使用测试辅助入口的用例在验证结束后打印耗时与结果便于观察校验器面对复杂程序时的实际性能表现。2.1 命令逐段拆解片段含义cargo test运行 Cargo 测试作用于当前 cratebytecode-verifier-tests。在仓库根目录下等价于cargo test -p bytecode-verifier-tests --release --featuresaddress32 -- --nocapture 1/dev/null--release以 release 模式编译并运行。计量与耗时测量必须在优化构建下才具有参考意义否则 debug 构建的校验开销会显著放大测量值--featuresaddress32启用address32特性。测试源码中存在#[cfg(not(feature address32))]之类的条件编译见 constants_tests.rs该特性会切换与地址长度相关的测试期望。从源码结构看此特性由依赖链中的 crate如move-binary-format提供本测试包自身的 Cargo.toml 中仅声明了fuzzing特性--分隔符其后的参数全部传给测试二进制本身而非 cargo--nocapture告诉测试运行器不要捕获测试输出。计量测试的计时信息通过eprintln!直接写入 stderr必须关闭捕获才能看到1/dev/null将 stdout 重定向到/dev/null丢弃。因为计时信息走 stderr 通道1/dev/null不会屏蔽它反而能过滤掉测试运行器在 stdout 上输出的进度噪音让-- ...形式的计时行更易扫描2.2 运行前提该命令应在bytecode-verifier-tests测试包目录即third_party/move/move-bytecode-verifier/bytecode-verifier-tests下执行或在仓库根目录用-p bytecode-verifier-tests指定包名该包为内部测试包Cargo.toml 中publish false并依赖move-binary-format启用fuzzing特性、move-bytecode-verifier、move-bytecode-verifier-invalid-mutations、move-core-types、petgraph、proptest等由于涉及链上合约校验场景使用 32 字节地址address32与 Aptos 主网地址长度保持一致使测量更贴近生产。三、计时输出从何而来测试辅助入口的埋点运行上述命令后每个通过测试辅助函数触发校验的用例都会输出一行形如-- many_backedges: verification time: x.xxxms, result: 状态, size: Nkb这行输出由 verifier.rs 中的verify_module_with_config_for_test_with_version产生。该函数是面向测试的校验入口其核心逻辑为将模块序列化为字节检查是否超过MAX_MODULE_SIZE65355字节与链上 payload 大小约束一致用Instant::now()记录开始时间调用正式的verify_module_with_config执行完整校验通过eprintln!输出测试名、耗时毫秒保留 3 位小数、结果主状态码成功为Ok失败为对应的major_status以及模块序列化大小KB。verify_module_with_config_for_test与verify_module_with_config_for_test_with_version均由此辅助函数封装见 verifier.rs且仅在测试路径中使用。因此打印直到复杂程序被检测或被接受的时间正是这一埋点行为的体现对应当前用例被拒绝result为错误状态码即为检测耗时若校验通过result: Ok即为接受耗时。需要注意eprintln!写入的是stderr这正是命令中1/dev/null丢弃 stdout仍能看到计时行的原因--nocapture则是让这些输出不被测试框架吞掉的必要条件。四、计量机制原理Meter trait 与 BoundMeter要理解复杂程序如何被检测需要看计量模块 meter.rs 的核心抽象4.1 计量作用域Scopepub enum Scope { Module, // 模块级计量 Function, // 函数级计量 }计量分模块级与函数级两个维度分别有独立预算。4.2 Meter traitpub trait Meter { fn enter_scope(mut self, name: str, scope: Scope); fn transfer(mut self, from: Scope, to: Scope, factor: f32) - PartialVMResult(); fn add(mut self, scope: Scope, units: u128) - PartialVMResult(); fn add_items(mut self, scope: Scope, units_per_item: u128, items: usize) - PartialVMResult(); fn add_items_with_growth(mut self, scope: Scope, mut units_per_item: u128, items: usize, growth_factor: f32) - PartialVMResult(); }add向指定作用域累加计量单位超限即返回错误add_items按items数量一次性累加units_per_item * items0项时短路返回add_items_with_growth按增长因子逐项累加用于模拟呈指数膨胀的复杂度如泛型实例化transfer把一个作用域已计量的 N 个单位按factor折算后转入另一作用域。4.3 BoundMeter 与program too complexBoundMeter是默认的计量器实现持有模块与函数两个Bounds各自含名称、当前单位数、上限max。当累加后超过上限时返回错误见 meter.rsreturn Err(PartialVMError::new(StatusCode::CONSTRAINT_NOT_SATISFIED) .with_message(format!( program too complex (in {} with {} current {} new {} max), self.name, self.units, units, max )));这里使用CONSTRAINT_NOT_SATISFIED状态码并在消息中给出当前 新增 上限的具体数值便于定位是哪个作用域、哪个阶段超限。源码注释也说明该错误未来会切换为独立的PROGRAM_TOO_COMPLEX状态码当前沿用既有状态码是为避免潜在的协议回滚兼容问题。此外还有DummyMeter——所有方法均为空操作用于不需要计量的场景。五、生产环境计量上限VerifierConfig计量上限来自VerifierConfigverifier.rsmax_per_fun_meter_units: Optionu128单函数计量上限max_per_mod_meter_units: Optionu128单模块计量上限。VerifierConfig::default()中这两个字段默认为None不设上限而VerifierConfig::production()生产环境的近似配置将其设置为max_per_fun_meter_units: Some(1000 * 8000), // 8,000,000 单位 max_per_mod_meter_units: Some(1000 * 8000), // 8,000,000 单位见 verifier.rs。同时 production 配置还包含配置项值说明max_loop_depthSome(5)循环嵌套深度上限max_generic_instantiation_lengthSome(32)泛型实例化参数长度上限max_function_parametersSome(128)函数参数个数上限max_basic_blocksSome(1024)基本块数量上限max_basic_blocks_in_scriptSome(1024)脚本中基本块上限max_value_stack_size1024值栈大小上限与解释器一致max_type_nodesSome(128)类型节点数上限max_push_sizeSome(10000)单函数内 push 指令数上限max_struct_definitions/max_fields_in_struct/max_struct_variants200/30/90结构体规模限制max_function_definitionsSome(1000)模块内函数数上限max_function_return_values/max_type_depth128/20返回值个数与类型深度限制max_back_edges_per_function/max_back_edges_per_moduleNone不再使用注释明确指出回边约束已被计量metering取代这一配置说明在 production 模式下回边数量等结构性限制已让位于更通用的计量机制add_items_with_growth这类带增长因子的计量正是为了捕获回边数量线性增长、但校验工作量指数增长的程序形态。六、复杂程序如何构造many_backedges 测试示例计量测试的典型用例是 many_back_edges.rs 中的many_backedges测试。它按如下方式构造复杂程序定义MAX_BASIC_BLOCKS 1024、MAX_LOCALS 255、NUM_FUNCTIONS 16生成一个辅助函数returns_bool_and_u64返回(bool, u64)生成 16 个函数f1..f16每个函数体内先连续压入(MAX_BASIC_BLOCKS - MAX_LOCALS - 2)组LdTrue; BrTrue(0)制造大量回边与基本块再循环MAX_LOCALS次每次Call(returns_bool_and_u64)后StLoc(i)写入局部变量再BrTrue(0)让每个局部变量第一次可用时都伴随一个回边最后调用let result move_bytecode_verifier::verify_module_with_config_for_test( many_backedges, VerifierConfig::production(), m, ); assert_eq!(result.unwrap_err().major_status(), StatusCode::CONSTRAINT_NOT_SATISFIED);该用例断言这样一个包含大量回边与函数调用、但字节码本身结构合法的模块在 production 计量配置下必须被拒绝且错误状态码正是CONSTRAINT_NOT_SATISFIED即计量超限的 program too complex。同时由于走的是verify_module_with_config_for_test入口运行cargo test --release --featuresaddress32 -- --nocapture 1/dev/null时它会打印出该校验实际消耗的时间——这就是打印直到复杂程序被检测的时间的直观体现。类似的计量/复杂度测试还包括 many_back_edges.rs、limit_tests.rs、large_type_test.rs等单元测试位于 unit_tests 目录它们共同构成对校验器复杂度控制的回归防线。七、实际运行与结果解读建议运行命令在仓库根目录执行cargo test -p bytecode-verifier-tests --release --featuresaddress32 -- --nocapture 1/dev/null或进入third_party/move/move-bytecode-verifier/bytecode-verifier-tests目录后执行文档原命令。结果解读观察-- name: verification time: ...行——result: Ok表示该复杂程序被接受时间为接受耗时result: CONSTRAINT_NOT_SATISFIED表示被计量机制检测并拒绝时间为检测耗时可同时关注size列模块序列化 KB 数结合 payload 上限65355字节判断复杂度来自结构规模还是计算强度。对照实验将--release去掉对比 debug 构建的耗时或通过修改 verifier.rs 中production()的计量上限做敏感性分析注意仓库为只读此类实验建议在本地分支进行。适用范围本文命令与结论针对当前仓库third_party/move下的校验器实现生产网络实际采用的计量上限可能随版本演进请以仓库内VerifierConfig::production()与链上配置为准。八、小结METER_TESTING.md 用一条命令概括了字节码校验器测试套件中最重要的性能观测手段以 release address32--nocapture运行测试并把 stdout 丢弃让每个用例经verify_module_with_config_for_test_with_version打印的计时与状态行浮出水面。其背后是Metertrait 驱动的模块级/函数级计量、BoundMeter的program too complex超限拒绝以及VerifierConfig::production()中 800 万单位的计量预算。对于关注 Move 虚拟机安全性与性能的开发者而言这套测试既能验证复杂度攻击防护的有效性也能为调整校验器预算提供量化依据。【免费下载链接】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),仅供参考
返回列表