Anvil fork 端点身份校验:anvil_reset 与 anvil_setRpcUrl 的原子化实现解析 Anvil fork 端点身份校验anvil_reset 与 anvil_setRpcUrl 的原子化实现解析【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundryFoundry 的 Anvil 以 fork 模式拉取远端链状态时仅凭 RPC URL 判断端点没变并不可靠。本文解析 Anvil 的 fork 端点身份校验机制anvil_reset 重置与 anvil_setRpcUrl 替换两条路径如何以 ForkEndpointIdentity 为基准严格比对执行上下文并用 staged 提交保证校验与生效的原子性。URL 未变为什么不能证明端点没变⚠️ 三类故障在只做 URL 字符串比较的实现中都可能发生同 URL 换了节点。远端端点重启、切换数据目录甚至被替换成另一个 Anvil 实例后URL 不变但链 ID、硬分叉、网络画像都可能不同。旧 fork 磁盘缓存仍会被复用产生状态污染。reset 期间上下文漂移。fork 重置分构建替换快照与正式提交两个阶段。若远端在这两阶段之间更换了执行配置按旧快照提交就会得到一个与预期不符的 fork。自环 fork。把 Anvil 自身的 RPC 端点当作 fork 源再执行 reset形成自引用。这条 patch 堵住的就是 URL 级假象远端执行上下文execution context一旦发生权威变化两条路径都拒绝提交旧缓存同步作废。身份数据本身见 fork.rs 的ForkEndpointIdentity。ForkEndpointIdentity 权威性判定hardfork 决定权威身份端点身份不是 URL 哈希而是一组描述远端执行上下文的字段定义在crates/anvil/src/eth/backend/fork.rs#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) struct ForkEndpointIdentity { pub(crate) execution_chain_id: u64, pub(crate) source_chain_id: u64, pub(crate) network: OptionNetworkVariant, pub(crate) network_profile: OptionNetworkConfigs, pub(crate) hardfork: OptionFoundryHardfork, pub(crate) instance_id: OptionB256, pub(crate) source_fork_block_number: Optionu64, pub(crate) source_fork_block_hash: OptionB256, }字段含义execution_chain_id端点实际执行的链 IDsource_chain_idfork 数据来源链的 IDnetwork/network_profile网络变体与配置画像用于跨网络家族判定hardfork端点上报的硬分叉非None时身份才具有权威性instance_id端点实例 ID可识别是不是我自己source_fork_block_number/source_fork_block_hashfork 锚定区块的高度与哈希权威性只有一个判据见 fork.rsimpl ForkEndpointIdentity { /// Returns whether this identity was reported by an Anvil endpoint. pub(crate) const fn is_authoritative(self) - bool { self.hardfork.is_some() } /// Returns whether two endpoints expose the same fork execution context. pub(crate) fn context_eq(self, other: Self) - bool { self.execution_chain_id other.execution_chain_id self.source_chain_id other.source_chain_id // 其余字段逐一比较刻意排除 instance_id } }hardfork只有在远端成功响应anvil_nodeInfo时才会被填充所以is_authoritative实际在问这个身份是端点亲口上报的还是推测出来的。context_eq排除instance_id意味着同一上下文的新实例允许接管但上下文本身不能变。探测策略与它配套AnvilNodeInfoProbeconfig.rs在首次成功响应前把探测失败视为可选能力不可用一旦识别出 Anvil此后任何探测失败都作为错误返回防止端点被重置时被静默掩盖。anvil_reset 与 anvil_setRpcUrl 的校验管线解析、比对、staged 原子提交两条路径共用一条三步管线解析真实身份、比对上下文、原子提交。第一步解析真实身份。anvil_setRpcUrl的 handler 在 api.rs。新 URL 不允许沿用旧端点留下的身份提示// A new URL replaces an offline discovery hint. Resolve the actual source identity so // unsupported networks cannot be hidden behind the previous endpoints hint. validation_config.fork_chain_id None; let (provider, endpoint_identity) validation_config .replacement_fork_provider( url, expected_identity, block_number, block_hash, self.instance_id(), ) .await?;replacement_fork_provider定义于crates/anvil/src/config.rs它会实际探测新端点并解析出真实身份。fork_chain_id None清空旧提示避免不支持的网络藏在旧端点的离线数据后面。anvil_reset 走stage_fork_resetmem/mod.rs在调用方显式提供了 URL 时做同样的清空再经setup_fork_db_config解析出staged_client_config.endpoint_identity。第二步比对上下文。校验项分四类缓存身份变更检测ForkCacheSource::authoritative_identity_changed_at_same_url判断同一 URL 上权威身份是否变化仅当新旧身份至少一侧权威时才启用严格比对匿名 RPC 端点保留原有缓存行为。跨网络家族拒绝与自环拒绝核心段见 mem/mod.rslet target_networks staged_client_config.endpoint_identity.network_profile.unwrap_or_default(); if !staged_config.has_explicit_network_selection() !self.networks.supports_fork_source(target_networks) { return Err(RpcError::invalid_params(format!( cannot reset Anvil across network families ({} - {}); start a new \ instance with matching network configuration, self.execution_profile_name(), target_networks.execution_profile_name() )) .into()); }紧随其后的自环检查在instance_id Some(serving_instance_id)时直接拒绝错误信息为 cannot reset Anvil to its own RPC endpoint。 3. fork 区块头校验取远端 fork 区块其 header 哈希与解析到的block_hash不一致时返回Ok(None)放弃。 4. 提交前二次验证fork_urls_match_contextcrates/anvil/src/config.rs再次核对 URL、身份、区块号与哈希专门拦截验证与提交之间的远端漂移不一致同样返回Ok(None)。第三步原子提交。 anvil_setRpcUrl 全程持有reset_lock提交阶段再叠加lifecycle_lock与 mining 锁一次性写入provider、fork_urls、endpoint_identity并同步node_config.fork_endpoint_is_anvil。anvil_reset 的粒度更细新 forkClientFork、新 DB、新缓存租约先以 staged 内存重置流程StagedMemoryReset见crates/anvil/src/eth/backend/mem/mod.rs#L249完整构建并验证运行中后端全程不动任何一步走Err或Ok(None)都调用rollback_staged_fork_cache回滚不存在半切换状态。维度anvil_setRpcUrlanvil_reset身份来源replacement_fork_provider实时解析新 URLsetup_fork_db_config解析 缓存来源比对特有校验清空旧fork_chain_id提示缓存身份变更、跨网络家族、自环、区块头哈希、二次核对失败行为Err直接返回不写任何配置Err或Ok(None)staged DB 与缓存租约整体回滚提交范围provider / fork_urls / 身份 / node_config整份替换fork、DB、存储缓存fork 缓存命名空间失效身份变了缓存必须作废ForkCacheSourcemem/mod.rs记录最近一次提交 fork 的来源rpc_urlendpoint_identity。当同 URL 权威身份变化命中时stage_fork_reset做三件事新 DB 清空为状态快照clear_into_state_snapshot仅回写新 fork 区块头不继承旧端点的任何存储。把旧、新两侧命名空间都加入失效列表。ForkCacheNamespace按source_chain_id定位缓存目录文件名是storage-{keccak256(url)}.json。缓存只按 URL 哈希寻址这正是URL 未变、身份已变时缓存必须显式作废的原因。在flush_old_cache为真时置位discard_old_cached_state提交阶段原子地失效命名空间并丢弃旧缓存状态。只要 hardfork、链 ID 或网络画像任一变化同一 URL 下的旧缓存即被排除在复用范围外。回归证据测试用例验证了什么test_endpoint_identitymem/mod.rs分别构造匿名身份与权威身份指定 hardfork 与实例 ID验证身份比较与缓存来源判定在不同实例 ID 下的行为。config.rs 的两处断言锁定权威性规则匿名身份is_authoritative() false权威身份为true。api.rs 的替换测试断言替换后身份与替换前context_eq而instance_id更新为新目标实例验证上下文保持、实例切换语义。对使用者这条改动的收益是确定的远端节点被替换、reset 期间执行配置变化、或误把 Anvil 指向自己时Anvil 会拒绝产生污染状态而不是静默继续。对维护者ForkEndpointIdentity把端点是谁从 URL 字符串升级为可比较的数据结构校验与提交被 staged 形态隔离。严格与原子各管一段前者保证校验不被旧提示和缓存欺骗后者保证校验结果要么整体生效、要么整体回滚。【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundry创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考