区块链存储Web3【免费下载链接】datahavenAn EVM compatible Substrate chain, powered by StorageHub and secured by EigenLayer项目地址https://gitcode.com/gh_mirrors/da/datahaven点击查看免费下载导读本文围绕 DataHaven 仓库中 operator/pallets/system/README.md 所定义的Ethereum Systemsnowbridge-pallet-systempallet 展开说明它如何在 Substrate 链上提供一组管理以太坊侧功能的治理函数——典型如创建 Agent桥接代理与创建 Channel桥接通道。读完本文你将掌握该 pallet 的五个治理外部调用Extrinsic、Agent/Channel 的创世初始化流程、定价参数与代币注册机制、运行时迁移逻辑以及它在 DataHaven 运行时中的实际接线方式可直接据此理解链上桥的治理入口。一、Pallet 定位Substrate 侧的以太坊控制面原文文档对 pallet 的定位描述极为凝练Contains management functions to manage functions on Ethereum. For example, creating agents and channels.在源码中它的完整定义位于 operator/pallets/system/src/lib.rscrate 名snowbridge-pallet-systemPallet 名EthereumSystem文件头部注释将其概括为Governance API for controlling the Ethereum side of the bridge也就是说这个 pallet 本身不直接与以太坊交互而是作为控制面把治理决策升级 Gateway 合约、切换运行模式、调整定价、注册代币等编码成 Snowbridge 出站消息Command通过出站队列OutboundQueue投递到以太坊侧的 Gateway 合约执行。它是桥的 Substrate 端管理入口。从仓库结构看该 pallet 是 Snowbridge 桥体系在 DataHaven一个由 StorageHub 驱动、EigenLayer 保护的 EVM 兼容 Substrate 链中的 fork 与集成组件与其配套的还有出站队列 palletsnowbridge-pallet-outbound-queue与 v2 版本operator/pallets/system-v2。二、两个核心抽象Agent 与 Channel2.1 Agent以太坊侧的执行代理Agent 是以太坊 Gateway 合约管理的桥接代理实体通常对应一个 XCM Location。pallet 用AgentId32 字节标识 agent并把注册关系存进Agents存储项/// The set of registered agents #[pallet::storage] #[pallet::getter(fn agents)] pub type AgentsT: Config StorageMap_, Twox64Concat, AgentId, (), OptionQuery;见 operator/pallets/system/src/lib.rs#L217-L220AgentId 由 XCMLocation通过T::AgentIdOfConvertLocationtrait 实现确定性推导而来核心函数是pub fn agent_id_ofT: Config(location: Location) - ResultH256, DispatchError { T::AgentIdOf::convert_location(location).ok_or(Error::T::LocationConversionFailed.into()) }见 operator/pallets/system/src/lib.rs#L72-L75单元测试 operator/pallets/system/src/tests.rs#L10-L20 对Location::here()断言了固定 AgentId 值印证了该映射的确定性与稳定性。2.2 ChannelAgent 名下的投递通道Channel 是消息投递的基本单位一个 Channel 归属于某个 Agent并绑定对应的平行链 ID/// The set of registered channels #[pallet::storage] #[pallet::getter(fn channels)] pub type ChannelsT: Config StorageMap_, Twox64Concat, ChannelId, Channel, OptionQuery;见 operator/pallets/system/src/lib.rs#L222-L225Channel记录结构为{ agent_id, para_id }。pallet 通过StaticLookup与Contains两个 trait 实现暴露给出站队列使用lib.rs#L540-L552出站队列据此校验某个 ChannelId 是否已注册。2.3 创世初始化Agent 与 Channel 从哪来Agent 与 Channel 并不是凭空创建的而是在创世genesis阶段由initialize(para_id, asset_hub_para_id)一次性建立lib.rs#L455-L494共建立四组关系实体说明AssetHub Agent Channel由ParentThen(Parachain(asset_hub_para_id))位置派生 AgentIdChannelId 直接取asset_hub_para_id用于资产跨链BridgeHub Agent由Location::here()本链自身派生作为治理通道的归属 AgentPRIMARY_GOVERNANCE_CHANNEL主治理通道发送升级、运行模式、定价等治理消息SECONDARY_GOVERNANCE_CHANNEL辅治理通道发送代币注册等消息创世配置通过GenesisConfig { para_id, asset_hub_para_id }注入lib.rs#L242-L258并提供了幂等的初始化判定pub(crate) fn is_initialized() - bool { let primary_exists Channels::T::contains_key(PRIMARY_GOVERNANCE_CHANNEL); let secondary_exists Channels::T::contains_key(SECONDARY_GOVERNANCE_CHANNEL); primary_exists secondary_exists }见 operator/pallets/system/src/lib.rs#L496-L501三、治理外部调用Extrinsics详解pallet 共提供5 个外部调用全部要求Root治理来源且投递费用豁免Fee required: No。每个调用的权重均标记为DispatchClass::Operational。3.1upgrade升级 Gateway 合约调用索引0参数impl_address: H160、impl_code_hash: H256、initializer: OptionInitializer校验impl_address与impl_code_hash均不得为零地址/零哈希否则报InvalidUpgradeParameters行为封装Command::Upgrade经PRIMARY_GOVERNANCE_CHANNEL发送若有initializer将其params做 blake2_256 哈希随事件公布事件Upgrade { impl_address, impl_code_hash, initializer_params_hash }见 operator/pallets/system/src/lib.rs#L271-L302测试 tests.rs#L22-L70 验证了upgrade_as_root、upgrade_with_params带 256 字节 initializer 参数、maximum_required_gas成功路径以及upgrade_as_signed_fails签名来源直接BadOrigin。3.2set_operating_mode切换 Gateway 运行模式调用索引1参数mode: OperatingModeOperatingMode来自出站队列原语枚举如Normal/RejectingOutboundMessages行为封装Command::SetOperatingMode经主治理通道发送事件SetOperatingMode { mode }见 operator/pallets/system/src/lib.rs#L304-L3193.3set_pricing_parameters桥双侧定价调用索引2参数params: PricingParametersOfTPricingParameters含四要素exchange_rate汇率、fee_per_gas以太坊 gas 单价、rewards { local, remote }本地/远端奖励、multiplier乘数先params.validate()非法即报InvalidPricingParameters随后写入本地存储并把exchange_rate、delivery_cost取T::InboundDeliveryCost、multiplier封装为Command::SetPricingParameters发往以太坊事件PricingParametersChanged { params }见 operator/pallets/system/src/lib.rs#L321-L347测试 tests.rs#L96-L159 系统性地覆盖了非法场景rewards.local 0、exchange_rate 0、fee_per_gas 0、rewards.remote 0均被拒绝。3.4set_token_transfer_fees代币转账费用调用索引9参数create_asset_xcm: u128、transfer_asset_xcm: u128、register_token: U256语义前两者为 AssetHub 上创建资产类与储备转账的 XCM 执行成本DOT 计价register_token为以太坊侧注册新代币的 Ether 费用校验三个值必须均大于 0且register_token meth(100)——代码注释说明这是为了让注册足够昂贵以阻止垃圾注册约至少 100 美元事件SetTokenTransferFees { ... }见 operator/pallets/system/src/lib.rs#L349-L3923.5register_token注册为以太坊上的包装 ERC20调用索引10参数location: BoxVersionedLocation、metadata: AssetMetadataname/symbol/decimals流程do_register_token见 lib.rs#L503-L537将资产位置从本链视角reanchor到以太坊上下文reanchored(ethereum_location, T::UniversalLocation::get())失败报LocationConversionFailed由重锚定后的位置算出token_id写入NativeToForeignId/ForeignToNativeId双向映射已存在则跳过封装Command::RegisterForeignToken经辅治理通道发送触发RegisterToken { location, foreign_token_id }事件。测试 tests.rs#L235-L308 用五组真实资产用例DOT、GLMR、USDT、KSM、KAR验证了输入本链视角位置 → 输出重锚定位置与稳定 token_id的完整映射tests.rs#L310-L329 则验证以太坊原生资产位置已含GlobalConsensus(Ethereum)注册会因无法再次重锚定而报LocationConversionFailed。四、消息发送与费用机制所有外部调用最终都汇入私有方法sendlib.rs#L426-L452fn send(channel_id: ChannelId, command: Command, pays_fee: PaysFeeT) - DispatchResult { let message Message { id: None, channel_id, command }; let (ticket, fee) T::OutboundQueue::validate(message).map_err(|err| Error::T::Send(err))?; // 按 PaysFee 变体决定是否扣费、扣多少 // 扣费路径T::Token::transfer(payer, TreasuryAccount, fee, Preservation::Preserve) T::OutboundQueue::deliver(ticket).map_err(|err| Error::T::Send(err))?; Ok(()) }PaysFee是三态枚举lib.rs#L85-L97Yes(account)本地 远端费用全额从指定账户扣除Partial(account)仅扣本地费用No不扣费治理消息走此路径。扣费所得转入T::TreasuryAccount金库账户。值得注意的细节收费与治理分离——五个治理调用都传PaysFee::No但 pallet 的 trait 设计SiblingOrigin、Token、TreasuryAccount、DefaultPricingParameters、InboundDeliveryCost为未来收费型调用如注册代币向调用方收费预留了完整通路。五、存储布局与 Runtime API5.1 存储项一览存储项类型用途AgentsStorageMapAgentId, ()已注册 Agent 集合ChannelsStorageMapChannelId, Channel已注册通道及归属PricingParametersStorageValuePricingParameters桥定价参数默认取DefaultPricingParametersForeignToNativeIdStorageMapTokenId, Location以太坊 token_id → 本链资产位置NativeToForeignIdStorageMapLocation, TokenId本链资产位置 → 以太坊 token_id见 operator/pallets/system/src/lib.rs#L217-L240后两张映射还通过MaybeEquivalenceTokenId, Locationtrait 暴露给桥的其他组件做双向换算lib.rs#L560-L567。5.2 Runtime API链上查询 AgentId仓库中另有一个配套的 runtime-api crateoperator/pallets/system/runtime-api/src/lib.rs其 README 说明Provides an API for looking up an agent ID on Ethereum即提供链上查询接口sp_api::decl_runtime_apis! { pub trait ControlApi { fn agent_id(location: VersionedLocation) - OptionAgentId; } }对应实现位于 operator/pallets/system/src/api.rs把VersionedLocation反序列化为Location后调用agent_id_of转换失败返回None。外部工具如 RPC 客户端可据此从任意 XCM 位置解析出以太坊侧的 AgentId。六、运行时升级迁移Migrationpallet 声明存储版本STORAGE_VERSION 1见 operator/pallets/system/src/migration.rs#L21并带两段可组合的迁移v0InitializeOnUpgrademigration.rs#L23-L86 运行时升级时若检测到is_initialized() false则自动执行initialize(BridgeHubParaId, AssetHubParaId)将存量链此前未运行该系统 pallet补齐 Agent 与通道已初始化则跳过并仅记日志。配合try-runtime提供pre_upgrade/post_upgrade前后校验。v1FeePerGasMigrationmigration.rs#L88-L222 将PricingParameters.fee_per_gas上调70%常量GAS_INCREASE_PERCENTAGE 70。背景是该桥消息命令从 v1 的AgentExecute::TransferToken演进到 v2 的UnlockNativeToken后 gas 消耗曲线变化需要调高单价以维持远端费用可覆盖原水平。post_upgrade用ConstantGasMeter::maximum_gas_used_at_most/maximum_dispatch_gas_used_at_most分别重算 v1/v2 远端费用并断言不高于迁移前。最终通过VersionedMigration0, 1, ...组合为FeePerGasMigrationV0ToV1migration.rs#L224-L231。七、测试与基准正确性如何被保障单元测试operator/pallets/system/src/tests.rs围绕三类性质展开来源约束五个调用在非 Root 来源下均BadOrigin如upgrade_as_signed_fails、set_token_transfer_fees_root_only参数校验无效定价参数、零值转账费用均被assert_noop!拒绝映射正确性多资产注册用例验证 reanchor 与双向 token 映射Ethereum 原生资产注册失败用例验证边界。基准测试operator/pallets/system/src/benchmarking.rs为upgrade假设 256 字节 initializer 参数、set_operating_mode、set_pricing_parameters、set_token_transfer_fees、register_token五个调用提供#[benchmark]实现并通过impl_benchmark_test_suite!在 mock 环境直接回放验证产出权重由T::WeightInfo引用mock 中用()占位运行时中替换为mainnet_weights::snowbridge_pallet_system::WeightInfo。测试基础设施见 operator/pallets/system/src/mock.rsmock 运行时注册了EthereumSystem、OutboundQueue、MessageQueue等 palletSiblingOrigin采用EnsureXcmAllowSiblingsOnly仅允许兄弟平行链来源创建 AgentAgentIdOf使用snowbridge_core::AgentIdOf并注入定价参数默认值PricingParameters { exchange_rate: 1/400, fee_per_gas: 20 gwei, rewards: { local: DOT, remote: 1 meth }, multiplier: 4/3 }与InboundDeliveryCost。八、在 DataHaven 运行时中的接线DataHaven 各运行时mainnet/stagenet/testnet通过impl snowbridge_pallet_system::Config完成接线以 mainnet 为例operator/runtime/mainnet/src/configs/mod.rs#L1110-L1125OutboundQueue DoNothingOutboundQueue从源码结构看mainnet 运行时当前将该 pallet 的出站队列配置为 no-op 实现validate恒返回零费用 ticket、deliver返回H256::zero()见 mod.rs#L1090-L1108即治理消息发送侧在本地运行时被占位SiblingOrigin EnsureRootWithSuccessAccountId, RootLocationAgent 创建来源限定为 RootAgentIdOf AgentIdOf、Token Balances、TreasuryAccount、DefaultPricingParameters、InboundDeliveryCost、UniversalLocation、EthereumLocation等由运行时参数提供WeightInfo使用生成的snowbridge_pallet_system::WeightInfoRuntime。同一运行时还并列配置了 v2 版本snowbridge_pallet_system_v2mod.rs#L1127-L1136其OutboundQueue EthereumOutboundQueueV2说明 v1 与 v2 体系在运行时中分层共存v1 负责既有治理语义v2 对接新一代出站队列。九、小结与进一步阅读Ethereum System pallet 是 DataHaven/Snowbridge 桥体系中Substrate 侧治理以太坊的唯一入口它以AgentXCM 位置派生与Channel消息投递单位为核心抽象通过创世初始化建立治理通道以五个 root-only 外部调用驱动 Gateway 合约的升级、模式切换、定价调整与代币注册并配套稳定的存储映射、运行时查询 API、幂等迁移与完整测试/基准体系。想继续深入可按以下路径阅读仓库源码pallet 主实现operator/pallets/system/src/lib.rs运行时升级迁移operator/pallets/system/src/migration.rs单元测试operator/pallets/system/src/tests.rs基准测试operator/pallets/system/src/benchmarking.rsRuntime API 定义与实现operator/pallets/system/runtime-api/src/lib.rs 与 operator/pallets/system/src/api.rs运行时集成示例operator/runtime/mainnet/src/configs/mod.rs#L1110-L1136v2 演进版本operator/pallets/system-v2/README.md赞分享区块链存储Web3【免费下载链接】datahavenAn EVM compatible Substrate chain, powered by StorageHub and secured by EigenLayer项目地址https://gitcode.com/gh_mirrors/da/datahaven点击查看免费下载相关推荐DataHaven 中的 Snowbridge System Pallet V2掌控以太坊侧网关的治理、升级与代币注册DataHaven 中的 Snowbridge System Pallet V2掌控以太坊侧网关的治理、升级与代币注册 导读 本文聚焦 DataHaven 节区块链存储Web3DataHaven 的 Ethereum System Runtime API 深度指南在 Substrate 运行时中查询 Ethereum 上的 Agent IDDataHaven 的 Ethereum System Runtime API 深度指南在 Substrate 运行时中查询 Ethereum 上的 Agen区块链存储Web3上一篇BiliTools深度测评从入门到精通的全场景解决方案下一篇IDM试用期问题解决方案从原理到实践的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
