From b4e22035a31dd1f1c676f49759924d8c404ebd65 Mon Sep 17 00:00:00 2001 From: undercover-cactus Date: Mon, 9 Mar 2026 14:33:43 +0100 Subject: [PATCH] fix: Register the snowbridge agent in the Dathaven Service instead of the operator node (#428) ## Summary This PR rename the `rewardsAgentOrigin`, `rewardsMessageOrigin`, etc... into a less specific less now that the Snowbrige Agent is also being used to relay slashing messages. This PR also have a fix to register the Agent address instead of the operator node address to check the sender of the message. Without this fix we could never relay rewards or execute slashing because we would get an error regarding the message. ## What changed * Removing the prefix `rewards` everytime we were refering the snowbridge agent (to clarify that the agent is not only being used by the reward feature) * Fix the deployment script to register the `agentAddress` as the required sender for relaying substrate message ## What is missing [ ] ~~Rename `onlyRewardsInitiator` and `rewardsInitiator` in the `DatahavenServiceManager.sol ` for something that would include slashing~~ This should be done in another PR. [x] Check the Testnet Deploy script to make sure it is using the agent address --------- Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com> --- contracts/config/anvil.json | 2 +- contracts/config/example.jsonc | 6 +- contracts/config/mainnet-ethereum.json | 2 +- contracts/config/stagenet-hoodi.json | 2 +- contracts/config/testnet-hoodi.json | 2 +- contracts/deployments/anvil-agent-info.json | 1 + contracts/deployments/anvil-rewards-info.json | 2 +- .../stagenet-hoodi-rewards-info.json | 2 +- contracts/script/deploy/Config.sol | 2 +- contracts/script/deploy/DeployBase.s.sol | 51 +++++++-------- contracts/script/deploy/DeployParams.s.sol | 3 +- operator/runtime/mainnet/src/configs/mod.rs | 6 +- .../mainnet/src/configs/runtime_params.rs | 4 +- operator/runtime/stagenet/src/configs/mod.rs | 16 ++--- .../stagenet/src/configs/runtime_params.rs | 4 +- operator/runtime/testnet/src/configs/mod.rs | 17 +++-- .../testnet/src/configs/runtime_params.rs | 4 +- test/.papi/descriptors/package.json | 2 +- test/.papi/metadata/datahaven.scale | Bin 632706 -> 632664 bytes test/cli/handlers/contracts/rewards-origin.ts | 58 +++++++++--------- test/cli/index.ts | 9 +-- .../parameters/datahaven-parameters.json | 2 +- test/e2e/suites/slash.test.ts | 18 +++++- test/utils/types.ts | 2 +- 24 files changed, 115 insertions(+), 102 deletions(-) create mode 100644 contracts/deployments/anvil-agent-info.json diff --git a/contracts/config/anvil.json b/contracts/config/anvil.json index 8e3796c3..4a134ced 100644 --- a/contracts/config/anvil.json +++ b/contracts/config/anvil.json @@ -35,7 +35,7 @@ "randaoCommitExpiration": 24, "minNumRequiredSignatures": 2, "startBlock": 1, - "rewardsMessageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000", + "messageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000", "initialValidatorSetId": 0, "initialValidatorHashes": [ "0xaeb47a269393297f4b0a3c9c9cfd00c7a4195255274cf39d83dabc2fcc9ff3d7", diff --git a/contracts/config/example.jsonc b/contracts/config/example.jsonc index e57c1ec7..aeef7cc4 100644 --- a/contracts/config/example.jsonc +++ b/contracts/config/example.jsonc @@ -99,9 +99,9 @@ /// Initial BEEFY block number. Set to latest finalized block by update-beefy-checkpoint. /// The BeefyClient will only accept BEEFY commitments with block numbers > startBlock. "startBlock": 1, - /// The origin linked to the Rewards Agent, the Agent contract who's allowed to submit - /// new reward merkle roots to the RewardsRegistry contract. - "rewardsMessageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000", + /// The origin linked to the Agent, the Agent contract who's allowed to submit + /// new reward merkle roots or slashes. + "messageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000", /// The BEEFY validator set ID for the initial validators. /// This is fetched from Beefy.ValidatorSetId on the DataHaven chain. "initialValidatorSetId": 0, diff --git a/contracts/config/mainnet-ethereum.json b/contracts/config/mainnet-ethereum.json index 5a0e13fb..28775dad 100644 --- a/contracts/config/mainnet-ethereum.json +++ b/contracts/config/mainnet-ethereum.json @@ -43,7 +43,7 @@ "randaoCommitExpiration": 24, "minNumRequiredSignatures": 16, "startBlock": 1, - "rewardsMessageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000", + "messageOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000", "initialValidatorSetId": 0, "initialValidatorHashes": [], "nextValidatorSetId": 1, diff --git a/contracts/config/stagenet-hoodi.json b/contracts/config/stagenet-hoodi.json index a79ac73a..40d80dbc 100644 --- a/contracts/config/stagenet-hoodi.json +++ b/contracts/config/stagenet-hoodi.json @@ -44,7 +44,7 @@ "randaoCommitExpiration": 24, "minNumRequiredSignatures": 3, "startBlock": 1303065, - "rewardsMessageOrigin": "0x56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd", + "messageOrigin": "0x56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd", "initialValidatorSetId": 2186, "initialValidatorHashes": [ "0x07ce4f2cd558f4d4b529a3362b6ff7d616ca0893b53252dc62829b8218ea5c10", diff --git a/contracts/config/testnet-hoodi.json b/contracts/config/testnet-hoodi.json index 1aa56fee..3396b7b4 100644 --- a/contracts/config/testnet-hoodi.json +++ b/contracts/config/testnet-hoodi.json @@ -44,7 +44,7 @@ "randaoCommitExpiration": 24, "minNumRequiredSignatures": 5, "startBlock": 1381173, - "rewardsMessageOrigin": "0xd0d6dbd1ffb401ef613f00e93cd5061ecec03ae35d2f820cd6754a5b5f020215", + "messageOrigin": "0xd0d6dbd1ffb401ef613f00e93cd5061ecec03ae35d2f820cd6754a5b5f020215", "initialValidatorSetId": 2303, "initialValidatorHashes": [ "0x0ec3102f334aba804c18b843e45ec874005587122a1b49273b1b04d6fd98b1a2", diff --git a/contracts/deployments/anvil-agent-info.json b/contracts/deployments/anvil-agent-info.json new file mode 100644 index 00000000..b0bc6882 --- /dev/null +++ b/contracts/deployments/anvil-agent-info.json @@ -0,0 +1 @@ +{"Agent": "0xac06641381166cf085281c45292147f833C622d7","AgentOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000"} \ No newline at end of file diff --git a/contracts/deployments/anvil-rewards-info.json b/contracts/deployments/anvil-rewards-info.json index ea1ee44d..c91dba57 100644 --- a/contracts/deployments/anvil-rewards-info.json +++ b/contracts/deployments/anvil-rewards-info.json @@ -1 +1 @@ -{"RewardsAgent": "0xac06641381166cf085281c45292147f833C622d7","RewardsAgentOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000"} \ No newline at end of file +{"RewardsAgent": "0xac06641381166cf085281c45292147f833C622d7","AgentOrigin": "0x0000000000000000000000000000000000000000000000000000000000000000"} \ No newline at end of file diff --git a/contracts/deployments/stagenet-hoodi-rewards-info.json b/contracts/deployments/stagenet-hoodi-rewards-info.json index 32bba16a..fc588b28 100644 --- a/contracts/deployments/stagenet-hoodi-rewards-info.json +++ b/contracts/deployments/stagenet-hoodi-rewards-info.json @@ -1 +1 @@ -{"RewardsAgent": "0x2E039a88838241d1Ac738cf2e3C5763ba12571e7","RewardsAgentOrigin": "0x56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd"} \ No newline at end of file +{"RewardsAgent": "0x2E039a88838241d1Ac738cf2e3C5763ba12571e7","AgentOrigin": "0x56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd"} \ No newline at end of file diff --git a/contracts/script/deploy/Config.sol b/contracts/script/deploy/Config.sol index 63558988..4d076407 100644 --- a/contracts/script/deploy/Config.sol +++ b/contracts/script/deploy/Config.sol @@ -12,7 +12,7 @@ contract Config { bytes32[] initialValidatorHashes; uint128 nextValidatorSetId; bytes32[] nextValidatorHashes; - bytes32 rewardsMessageOrigin; + bytes32 messageOrigin; } // AVS parameters diff --git a/contracts/script/deploy/DeployBase.s.sol b/contracts/script/deploy/DeployBase.s.sol index 64de00e4..145c54aa 100644 --- a/contracts/script/deploy/DeployBase.s.sol +++ b/contracts/script/deploy/DeployBase.s.sol @@ -123,7 +123,7 @@ abstract contract DeployBase is Script, DeployParams, Accounts { BeefyClient beefyClient, AgentExecutor agentExecutor, IGatewayV2 gateway, - address payable rewardsAgentAddress + address payable agentAddress ) = _deploySnowbridge(snowbridgeConfig); Logging.logFooter(); _logProgress(); @@ -132,14 +132,14 @@ abstract contract DeployBase is Script, DeployParams, Accounts { ( DataHavenServiceManager serviceManager, DataHavenServiceManager serviceManagerImplementation - ) = _deployDataHavenContracts(avsConfig, proxyAdmin, gateway); + ) = _deployDataHavenContracts(avsConfig, proxyAdmin, gateway, agentAddress); Logging.logFooter(); _logProgress(); // Final configuration (same for both modes) Logging.logHeader("FINAL CONFIGURATION"); - Logging.logContractDeployed("Rewards Agent Address", rewardsAgentAddress); + Logging.logContractDeployed("Agent Address", agentAddress); Logging.logFooter(); _logProgress(); @@ -150,11 +150,11 @@ abstract contract DeployBase is Script, DeployParams, Accounts { gateway, serviceManager, serviceManagerImplementation, - rewardsAgentAddress, + agentAddress, proxyAdmin ); - _outputRewardsAgentInfo(rewardsAgentAddress, snowbridgeConfig.rewardsMessageOrigin); + _outputAgentInfo(agentAddress, snowbridgeConfig.messageOrigin); } /** @@ -201,11 +201,11 @@ abstract contract DeployBase is Script, DeployParams, Accounts { // Create Agent Logging.logSection("Creating Snowbridge Agent"); vm.broadcast(_deployerPrivateKey); - gateway.v2_createAgent(config.rewardsMessageOrigin); - address payable rewardsAgentAddress = payable(gateway.agentOf(config.rewardsMessageOrigin)); - Logging.logContractDeployed("Rewards Agent", rewardsAgentAddress); + gateway.v2_createAgent(config.messageOrigin); + address payable agentAddress = payable(gateway.agentOf(config.messageOrigin)); + Logging.logContractDeployed("Rewards Agent", agentAddress); - return (beefyClient, agentExecutor, gateway, rewardsAgentAddress); + return (beefyClient, agentExecutor, gateway, agentAddress); } /** @@ -240,7 +240,8 @@ abstract contract DeployBase is Script, DeployParams, Accounts { function _deployDataHavenContracts( AVSConfig memory avsConfig, ProxyAdmin proxyAdmin, - IGatewayV2 gateway + IGatewayV2 gateway, + address agentAddress ) internal returns (DataHavenServiceManager, DataHavenServiceManager) { Logging.logHeader("DATAHAVEN CUSTOM CONTRACTS DEPLOYMENT"); @@ -269,7 +270,7 @@ abstract contract DeployBase is Script, DeployParams, Accounts { // Create service manager initialisation parameters struct ServiceManagerInitParams memory initParams = ServiceManagerInitParams({ avsOwner: avsConfig.avsOwner, - rewardsInitiator: avsConfig.rewardsInitiator, + rewardsInitiator: agentAddress, validatorsStrategiesAndMultipliers: strategiesAndMultipliers, gateway: address(gateway), validatorSetSubmitter: avsConfig.validatorSetSubmitter, @@ -313,38 +314,38 @@ abstract contract DeployBase is Script, DeployParams, Accounts { IGatewayV2 gateway, DataHavenServiceManager serviceManager, DataHavenServiceManager serviceManagerImplementation, - address rewardsAgent, + address agent, ProxyAdmin proxyAdmin ) internal virtual; /** - * @notice Output rewards agent info (shared across all deployment types) + * @notice Output agent info (shared across all deployment types) */ - function _outputRewardsAgentInfo( - address rewardsAgent, - bytes32 rewardsAgentOrigin + function _outputAgentInfo( + address agent, + bytes32 agentOrigin ) internal { - Logging.logHeader("REWARDS AGENT INFO"); - Logging.logContractDeployed("RewardsAgent", rewardsAgent); - Logging.logAgentOrigin("RewardsAgentOrigin", vm.toString(rewardsAgentOrigin)); + Logging.logHeader("AGENT INFO"); + Logging.logContractDeployed("Agent", agent); + Logging.logAgentOrigin("AgentOrigin", vm.toString(agentOrigin)); Logging.logFooter(); // Write to deployment file for future reference string memory network = _getNetworkName(); - string memory rewardsInfoPath = - string.concat(vm.projectRoot(), "/deployments/", network, "-rewards-info.json"); + string memory agentInfoPath = + string.concat(vm.projectRoot(), "/deployments/", network, "-agent-info.json"); // Create directory if it doesn't exist vm.createDir(string.concat(vm.projectRoot(), "/deployments"), true); // Create JSON with rewards info string memory json = "{"; - json = string.concat(json, '"RewardsAgent": "', vm.toString(rewardsAgent), '",'); - json = string.concat(json, '"RewardsAgentOrigin": "', vm.toString(rewardsAgentOrigin), '"'); + json = string.concat(json, '"Agent": "', vm.toString(agent), '",'); + json = string.concat(json, '"AgentOrigin": "', vm.toString(agentOrigin), '"'); json = string.concat(json, "}"); // Write to file - vm.writeFile(rewardsInfoPath, json); - Logging.logInfo(string.concat("Rewards info saved to: ", rewardsInfoPath)); + vm.writeFile(agentInfoPath, json); + Logging.logInfo(string.concat("Agent info saved to: ", agentInfoPath)); } } diff --git a/contracts/script/deploy/DeployParams.s.sol b/contracts/script/deploy/DeployParams.s.sol index eda4630f..c77f99b9 100644 --- a/contracts/script/deploy/DeployParams.s.sol +++ b/contracts/script/deploy/DeployParams.s.sol @@ -24,8 +24,7 @@ contract DeployParams is Script, Config { config.minNumRequiredSignatures = vm.parseJsonUint(configJson, ".snowbridge.minNumRequiredSignatures"); config.startBlock = vm.parseJsonUint(configJson, ".snowbridge.startBlock").toUint64(); - config.rewardsMessageOrigin = - vm.parseJsonBytes32(configJson, ".snowbridge.rewardsMessageOrigin"); + config.messageOrigin = vm.parseJsonBytes32(configJson, ".snowbridge.messageOrigin"); // Load validators from file or generate placeholder ones in dev mode bool isDevMode = keccak256(abi.encodePacked(vm.envOr("DEV_MODE", string("false")))) diff --git a/operator/runtime/mainnet/src/configs/mod.rs b/operator/runtime/mainnet/src/configs/mod.rs index 1499a9c5..0deeff2a 100644 --- a/operator/runtime/mainnet/src/configs/mod.rs +++ b/operator/runtime/mainnet/src/configs/mod.rs @@ -1518,7 +1518,7 @@ impl datahaven_runtime_common::rewards_adapter::RewardsSubmissionConfig for Main } fn rewards_agent_origin() -> H256 { - runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get() + runtime_params::dynamic_params::runtime_config::AgentOrigin::get() } fn strategies_and_multipliers() -> Vec<(H160, u128)> { @@ -1692,9 +1692,9 @@ impl datahaven_runtime_common::slashes_adapter::SlashesSubmissionConfig for Main runtime_params::dynamic_params::runtime_config::DatahavenServiceManagerAddress::get() } + // TODO: remove `slashes_` prefix and just call it `agent_origin` fn slashes_agent_origin() -> H256 { - runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get() - // TODO: Can we use the same as reward and just rename the config to `AgentOrigin` ? + runtime_params::dynamic_params::runtime_config::AgentOrigin::get() } fn strategies() -> Vec
{ diff --git a/operator/runtime/mainnet/src/configs/runtime_params.rs b/operator/runtime/mainnet/src/configs/runtime_params.rs index aa35f269..9d3cdeb3 100644 --- a/operator/runtime/mainnet/src/configs/runtime_params.rs +++ b/operator/runtime/mainnet/src/configs/runtime_params.rs @@ -48,9 +48,9 @@ pub mod dynamic_params { #[codec(index = 3)] #[allow(non_upper_case_globals)] - /// The RewardsAgentOrigin is the hash of the string "external_validators_rewards" + /// The AgentOrigin is the hash of the string "external_validators_rewards" /// TODO: Decide which agent origin we want to use. Currently for testing it's the zero hash - pub static RewardsAgentOrigin: H256 = H256::from_slice(&hex!( + pub static AgentOrigin: H256 = H256::from_slice(&hex!( "c505dfb2df107d106d08bd0f1a0acd10052ca9aa078629a4ccfd0c90c6e69b65" )); diff --git a/operator/runtime/stagenet/src/configs/mod.rs b/operator/runtime/stagenet/src/configs/mod.rs index 299554c6..60fee86c 100644 --- a/operator/runtime/stagenet/src/configs/mod.rs +++ b/operator/runtime/stagenet/src/configs/mod.rs @@ -1514,7 +1514,7 @@ impl datahaven_runtime_common::rewards_adapter::RewardsSubmissionConfig for Stag } fn rewards_agent_origin() -> H256 { - runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get() + runtime_params::dynamic_params::runtime_config::AgentOrigin::get() } fn strategies_and_multipliers() -> Vec<(H160, u128)> { @@ -1689,7 +1689,7 @@ impl datahaven_runtime_common::slashes_adapter::SlashesSubmissionConfig for Stag } fn slashes_agent_origin() -> H256 { - runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get() + runtime_params::dynamic_params::runtime_config::AgentOrigin::get() // TODO: Can we use the same as reward and just rename the config to `AgentOrigin` ? } @@ -1951,8 +1951,8 @@ mod tests { /// Test that the Rewards Agent ID (used for Snowbridge outbound messages from the rewards pallet) /// is correctly computed from the chain's genesis hash and the ExternalValidatorRewardsAccount. /// - /// This test verifies the value that should be set as `RewardsAgentOrigin` in runtime parameters - /// and as `rewardsMessageOrigin` in the AVS contract configuration. + /// This test verifies the value that should be set as `AgentOrigin` in runtime parameters + /// and as `messageOrigin` in the AVS contract configuration. /// /// The Agent ID is computed following Snowbridge's pattern for GlobalConsensus locations: /// blake2_256(SCALE_ENCODE("GlobalConsensus", ByGenesis(genesis_hash), compact_len, "AccountKey20", account_key)) @@ -1992,8 +1992,8 @@ mod tests { // Hash with blake2_256 let computed_agent_id = H256(blake2_256(&encoded)); - // Expected Agent ID - this value must match RewardsAgentOrigin in runtime_params.rs - // If this test fails, update RewardsAgentOrigin to match the computed value. + // Expected Agent ID - this value must match AgentOrigin in runtime_params.rs + // If this test fails, update AgentOrigin to match the computed value. let expected_agent_id = H256(hex_literal::hex!( "56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd" )); @@ -2003,8 +2003,8 @@ mod tests { expected_agent_id, "Computed Rewards Agent ID must match expected value.\n\ This value should be set as:\n\ - - RewardsAgentOrigin in runtime_params.rs\n\ - - rewardsMessageOrigin in AVS contract config\n\ + - AgentOrigin in runtime_params.rs\n\ + - messageOrigin in AVS contract config\n\ \n\ Rewards account: 0x{}\n\ Genesis hash: 0x{}\n\ diff --git a/operator/runtime/stagenet/src/configs/runtime_params.rs b/operator/runtime/stagenet/src/configs/runtime_params.rs index d7775020..dcf136c9 100644 --- a/operator/runtime/stagenet/src/configs/runtime_params.rs +++ b/operator/runtime/stagenet/src/configs/runtime_params.rs @@ -51,13 +51,13 @@ pub mod dynamic_params { #[codec(index = 3)] #[allow(non_upper_case_globals)] - /// The RewardsAgentOrigin is the Agent ID for the rewards pallet's outbound Snowbridge messages. + /// The AgentOrigin is the Agent ID for the rewards/slashes pallet's outbound Snowbridge messages. /// Computed as: blake2_256(SCALE_ENCODE("GlobalConsensus", ByGenesis(genesis_hash), interior)) /// where interior = SCALE_ENCODE("AccountKey20", ExternalValidatorRewardsAccount) /// /// For stagenet with genesis hash 0x72d0856fd339e09cb21df7bac8ac3120bd871e327ec0e1658395df68acef9bee /// and rewards account 0x6d6f646c64682f65767265770000000000000000 (from PalletId "dh/evrew"): - pub static RewardsAgentOrigin: H256 = H256::from_slice(&hex!( + pub static AgentOrigin: H256 = H256::from_slice(&hex!( "56490bd3f367447bfaf57bb18e7a45e1b2db7d538fe42098e87d2aa106c6afdd" )); diff --git a/operator/runtime/testnet/src/configs/mod.rs b/operator/runtime/testnet/src/configs/mod.rs index ccf9d48a..caca5de5 100644 --- a/operator/runtime/testnet/src/configs/mod.rs +++ b/operator/runtime/testnet/src/configs/mod.rs @@ -1518,7 +1518,7 @@ impl datahaven_runtime_common::rewards_adapter::RewardsSubmissionConfig for Test } fn rewards_agent_origin() -> H256 { - runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get() + runtime_params::dynamic_params::runtime_config::AgentOrigin::get() } fn strategies_and_multipliers() -> Vec<(H160, u128)> { @@ -1693,8 +1693,7 @@ impl datahaven_runtime_common::slashes_adapter::SlashesSubmissionConfig for Test } fn slashes_agent_origin() -> H256 { - runtime_params::dynamic_params::runtime_config::RewardsAgentOrigin::get() - // TODO: Can we use the same as reward and just rename the config to `AgentOrigin` ? + runtime_params::dynamic_params::runtime_config::AgentOrigin::get() } fn strategies() -> Vec
{ @@ -1973,8 +1972,8 @@ mod tests { /// Test that the Rewards Agent ID (used for Snowbridge outbound messages from the rewards pallet) /// is correctly computed from the chain's genesis hash and the ExternalValidatorRewardsAccount. /// - /// This test verifies the value that should be set as `RewardsAgentOrigin` in runtime parameters - /// and as `rewardsMessageOrigin` in the AVS contract configuration. + /// This test verifies the value that should be set as `AgentOrigin` in runtime parameters + /// and as `messageOrigin` in the AVS contract configuration. /// /// The Agent ID is computed following Snowbridge's pattern for GlobalConsensus locations: /// blake2_256(SCALE_ENCODE("GlobalConsensus", ByGenesis(genesis_hash), compact_len, "AccountKey20", account_key)) @@ -2014,8 +2013,8 @@ mod tests { // Hash with blake2_256 let computed_agent_id = H256(blake2_256(&encoded)); - // Expected Agent ID - this value must match RewardsAgentOrigin in runtime_params.rs - // If this test fails, update RewardsAgentOrigin to match the computed value. + // Expected Agent ID - this value must match AgentOrigin in runtime_params.rs + // If this test fails, update AgentOrigin to match the computed value. let expected_agent_id = H256(hex_literal::hex!( "d0d6dbd1ffb401ef613f00e93cd5061ecec03ae35d2f820cd6754a5b5f020215" )); @@ -2025,8 +2024,8 @@ mod tests { expected_agent_id, "Computed Rewards Agent ID must match expected value.\n\ This value should be set as:\n\ - - RewardsAgentOrigin in runtime_params.rs\n\ - - rewardsMessageOrigin in AVS contract config\n\ + - AgentOrigin in runtime_params.rs\n\ + - messageOrigin in AVS contract config\n\ \n\ Rewards account: 0x{}\n\ Genesis hash: 0x{}\n\ diff --git a/operator/runtime/testnet/src/configs/runtime_params.rs b/operator/runtime/testnet/src/configs/runtime_params.rs index 5753d215..40c89108 100644 --- a/operator/runtime/testnet/src/configs/runtime_params.rs +++ b/operator/runtime/testnet/src/configs/runtime_params.rs @@ -49,13 +49,13 @@ pub mod dynamic_params { #[codec(index = 3)] #[allow(non_upper_case_globals)] - /// The RewardsAgentOrigin is the Agent ID for the rewards pallet's outbound Snowbridge messages. + /// The AgentOrigin is the Agent ID for the rewards/slashes pallet's outbound Snowbridge messages. /// Computed as: blake2_256(SCALE_ENCODE("GlobalConsensus", ByGenesis(genesis_hash), interior)) /// where interior = SCALE_ENCODE("AccountKey20", ExternalValidatorRewardsAccount) /// /// For testnet with genesis hash 0xdbf403d348916fb0694485bc7f9c0d8c53fdf86664ebac019af209c090c3df99 /// and rewards account 0x6d6f646c64682f65767265770000000000000000 (from PalletId "dh/evrew"): - pub static RewardsAgentOrigin: H256 = H256::from_slice(&hex!( + pub static AgentOrigin: H256 = H256::from_slice(&hex!( "d0d6dbd1ffb401ef613f00e93cd5061ecec03ae35d2f820cd6754a5b5f020215" )); diff --git a/test/.papi/descriptors/package.json b/test/.papi/descriptors/package.json index d5f24906..5ad366a9 100644 --- a/test/.papi/descriptors/package.json +++ b/test/.papi/descriptors/package.json @@ -1,5 +1,5 @@ { - "version": "0.1.0-autogenerated.18296316742446681711", + "version": "0.1.0-autogenerated.15484599658830368838", "name": "@polkadot-api/descriptors", "files": [ "dist" diff --git a/test/.papi/metadata/datahaven.scale b/test/.papi/metadata/datahaven.scale index d0ecbe092134c6f09ec29777cb7151c9c7c39f20..1ad174a797dc11e0174c4289ff51aa16bb594ea0 100644 GIT binary patch delta 104 zcmZoVuXf{{+J+t{Asxr`)Vvb^qRjNnJQfB{Mn;{@Yn%ePfE25*zX*_uNqqekMHL5F hReO3kBM>tIF*6Xe05K~NvjH(X5OZu#59gE)00232A*lcW delta 146 zcmca{POa&@+J+t{1&^TA^2DN)V#oB { * blake2_256(SCALE_ENCODE(("GlobalConsensus", ByGenesis(genesis_hash), ("AccountKey20", account_key)))) * * NOTE: This computation follows Snowbridge's pattern but may need verification against - * the actual on-chain Agent ID. The preferred approach is to set RewardsAgentOrigin on + * the actual on-chain Agent ID. The preferred approach is to set AgentOrigin on * the chain and fetch it via this command. * * @param genesisHash - The chain's genesis hash (32 bytes, hex string with 0x prefix) @@ -116,36 +116,36 @@ const computeAgentId = async (genesisHash: Hex, accountKey20: Hex): Promise }; /** - * Fetches the RewardsAgentOrigin from the runtime parameters. + * Fetches the AgentOrigin from the runtime parameters. * * @param rpcUrl - WebSocket RPC endpoint of the DataHaven chain - * @returns The RewardsAgentOrigin as a hex string, or null if not set or zero + * @returns The AgentOrigin as a hex string, or null if not set or zero */ -const fetchRewardsAgentOrigin = async (rpcUrl: string): Promise => { +const fetchAgentOrigin = async (rpcUrl: string): Promise => { logger.info(`📡 Connecting to DataHaven chain at ${rpcUrl}...`); const { client: papiClient, typedApi: dhApi } = createPapiConnectors(rpcUrl); try { - logger.info("🔍 Fetching RewardsAgentOrigin from runtime parameters..."); + logger.info("🔍 Fetching AgentOrigin from runtime parameters..."); - // Query the Parameters pallet for RewardsAgentOrigin + // Query the Parameters pallet for AgentOrigin const parameter = await dhApi.query.Parameters.Parameters.getValue( { type: "RuntimeConfig", - value: { type: "RewardsAgentOrigin", value: undefined } + value: { type: "AgentOrigin", value: undefined } }, { at: "best" } ); if (!parameter) { - logger.info("â„šī¸ RewardsAgentOrigin parameter not found (using default)"); + logger.info("â„šī¸ AgentOrigin parameter not found (using default)"); return null; } // Extract the value from the parameter result // The parameter is wrapped in the RuntimeConfig enum variant - if (parameter.type === "RuntimeConfig" && parameter.value.type === "RewardsAgentOrigin") { + if (parameter.type === "RuntimeConfig" && parameter.value.type === "AgentOrigin") { const origin = parameter.value.value; if (origin) { const originHex = origin.asHex(); @@ -153,15 +153,15 @@ const fetchRewardsAgentOrigin = async (rpcUrl: string): Promise => { const zeroHash = "0x0000000000000000000000000000000000000000000000000000000000000000" as Hex; if (originHex === zeroHash) { - logger.info("â„šī¸ RewardsAgentOrigin is set to zero (placeholder)"); + logger.info("â„šī¸ AgentOrigin is set to zero (placeholder)"); return null; } - logger.success(`Found RewardsAgentOrigin: ${originHex}`); + logger.success(`Found AgentOrigin: ${originHex}`); return originHex as Hex; } } - logger.info("â„šī¸ RewardsAgentOrigin value not available"); + logger.info("â„šī¸ AgentOrigin value not available"); return null; } finally { papiClient.destroy(); @@ -193,9 +193,9 @@ const fetchGenesisHash = async (rpcUrl: string): Promise => { * Updates the config file with the rewards message origin. * * @param networkId - The network identifier (e.g., "hoodi", "stagenet-hoodi") - * @param rewardsMessageOrigin - The rewards message origin (Agent ID) + * @param messageOrigin - The rewards message origin (Agent ID) */ -const updateConfigFile = async (networkId: string, rewardsMessageOrigin: Hex): Promise => { +const updateConfigFile = async (networkId: string, messageOrigin: Hex): Promise => { const configFilePath = `../contracts/config/${networkId}.json`; const configFile = Bun.file(configFilePath); @@ -211,21 +211,21 @@ const updateConfigFile = async (networkId: string, rewardsMessageOrigin: Hex): P configJson.snowbridge = {}; } - const oldOrigin = configJson.snowbridge.rewardsMessageOrigin; - configJson.snowbridge.rewardsMessageOrigin = rewardsMessageOrigin; + const oldOrigin = configJson.snowbridge.messageOrigin; + configJson.snowbridge.messageOrigin = messageOrigin; await Bun.write(configFilePath, `${JSON.stringify(configJson, null, 2)}\n`); logger.success(`Config file updated: ${configFilePath}`); - if (oldOrigin !== rewardsMessageOrigin) { - logger.info(` rewardsMessageOrigin: ${oldOrigin ?? "unset"} -> ${rewardsMessageOrigin}`); + if (oldOrigin !== messageOrigin) { + logger.info(` messageOrigin: ${oldOrigin ?? "unset"} -> ${messageOrigin}`); } }; /** * Main handler for the update-rewards-origin command. - * Fetches or computes the RewardsAgentOrigin and updates the config file. + * Fetches or computes the AgentOrigin and updates the config file. */ export const updateRewardsOrigin = async (options: UpdateRewardsOriginOptions): Promise => { const networkId = buildNetworkId(options.chain, options.environment); @@ -246,17 +246,17 @@ export const updateRewardsOrigin = async (options: UpdateRewardsOriginOptions): printDivider(); try { - // Step 1: Try to fetch RewardsAgentOrigin from the chain - let rewardsMessageOrigin = await fetchRewardsAgentOrigin(options.rpcUrl); + // Step 1: Try to fetch AgentOrigin from the chain + let messageOrigin = await fetchAgentOrigin(options.rpcUrl); printDivider(); - if (rewardsMessageOrigin) { + if (messageOrigin) { // Use the value from the chain - logger.info("✅ Using RewardsAgentOrigin from chain runtime parameters"); + logger.info("✅ Using AgentOrigin from chain runtime parameters"); } else { // Compute the Agent ID from genesis hash and pallet account - logger.info("🔧 Computing RewardsAgentOrigin from genesis hash and pallet account..."); + logger.info("🔧 Computing AgentOrigin from genesis hash and pallet account..."); // Get genesis hash (from option or fetch from chain) const genesisHash = options.genesisHash @@ -272,22 +272,22 @@ export const updateRewardsOrigin = async (options: UpdateRewardsOriginOptions): // Compute the Agent ID logger.info("🔐 Computing Agent ID..."); logger.warn( - "âš ī¸ Note: Computed Agent ID may need verification. Prefer setting RewardsAgentOrigin on-chain." + "âš ī¸ Note: Computed Agent ID may need verification. Prefer setting AgentOrigin on-chain." ); - rewardsMessageOrigin = await computeAgentId(genesisHash, rewardsAccount); - logger.info(` Agent ID: ${rewardsMessageOrigin}`); + messageOrigin = await computeAgentId(genesisHash, rewardsAccount); + logger.info(` Agent ID: ${messageOrigin}`); } printDivider(); // Display the final value logger.info("📝 Rewards Message Origin:"); - logger.info(` ${rewardsMessageOrigin}`); + logger.info(` ${messageOrigin}`); printDivider(); // Update the config file - await updateConfigFile(networkId, rewardsMessageOrigin); + await updateConfigFile(networkId, messageOrigin); printDivider(); logger.success(`Rewards message origin updated successfully for ${networkId}`); diff --git a/test/cli/index.ts b/test/cli/index.ts index 1ed926ef..27763287 100644 --- a/test/cli/index.ts +++ b/test/cli/index.ts @@ -212,7 +212,7 @@ const contractsCommand = program - upgrade: Upgrade contracts by deploying new implementations - verify: Verify deployed contracts on block explorer - update-beefy-checkpoint: Fetch BEEFY authorities from a live chain and update config - - update-rewards-origin: Fetch or compute the RewardsAgentOrigin and update config + - update-rewards-origin: Fetch or compute the AgentOrigin and update config - update-metadata: Update the metadata URI of an existing AVS contract Common options: @@ -385,17 +385,14 @@ contractsCommand contractsCommand .command("update-rewards-origin") .description( - "Fetch or compute the RewardsAgentOrigin and update the config file with the rewards message origin" + "Fetch or compute the AgentOrigin and update the config file with the rewards message origin" ) .option("--chain ", "Target chain (hoodi, ethereum, anvil)") .option( "--environment ", "Deployment environment (stagenet, testnet, mainnet). Config and deployment files will be prefixed with this value." ) - .option( - "--rpc-url ", - "WebSocket RPC URL of the DataHaven chain to fetch RewardsAgentOrigin from" - ) + .option("--rpc-url ", "WebSocket RPC URL of the DataHaven chain to fetch AgentOrigin from") .option( "--genesis-hash ", "Chain genesis hash (32 bytes hex). If not provided, will be fetched from the chain." diff --git a/test/configs/parameters/datahaven-parameters.json b/test/configs/parameters/datahaven-parameters.json index ce875f03..0072a499 100644 --- a/test/configs/parameters/datahaven-parameters.json +++ b/test/configs/parameters/datahaven-parameters.json @@ -8,7 +8,7 @@ "value": null }, { - "name": "RewardsAgentOrigin", + "name": "AgentOrigin", "value": null }, { diff --git a/test/e2e/suites/slash.test.ts b/test/e2e/suites/slash.test.ts index c212cd90..7547a84c 100644 --- a/test/e2e/suites/slash.test.ts +++ b/test/e2e/suites/slash.test.ts @@ -3,8 +3,9 @@ import { $ } from "bun"; import { Binary, FixedSizeBinary } from "polkadot-api"; import { CROSS_CHAIN_TIMEOUTS, getPapiSigner, logger } from "utils"; import type { Address } from "viem"; +import { gatewayAbi } from "../../contract-bindings"; import { getContractInstance, parseDeploymentsFile } from "../../utils/contracts"; -import { waitForDataHavenEvent } from "../../utils/events"; +import { waitForDataHavenEvent, waitForEthereumEvent } from "../../utils/events"; import { waitFor } from "../../utils/waits"; import { BaseTestSuite } from "../framework"; @@ -122,6 +123,8 @@ describe("Should slash an operator", () => { }, 40000); it("use sudo to slash operator", async () => { + const { publicClient } = suite.getTestConnectors(); + // get era number const activeEra = await dhApi.query.ExternalValidators.ActiveEra.getValue(); @@ -168,6 +171,19 @@ describe("Should slash an operator", () => { throw new Error("SlashesMessageSent event not found"); } logger.info("Slashes message sent"); + + const fromBlock = await publicClient.getBlockNumber(); + const deployments = await parseDeploymentsFile(); + const _ethEvent = await waitForEthereumEvent({ + client: publicClient, + address: deployments.Gateway, + abi: gatewayAbi, + eventName: "SlashingComplete", + fromBlock: fromBlock > 0n ? fromBlock - 1n : fromBlock, + timeout: CROSS_CHAIN_TIMEOUTS.DH_TO_ETH_MS + }); + + logger.info("Got Ethereum event!"); }, 560000); it("should detect and slash an unresponsive validator (liveness)", async () => { diff --git a/test/utils/types.ts b/test/utils/types.ts index 695788ff..df4f8143 100644 --- a/test/utils/types.ts +++ b/test/utils/types.ts @@ -184,7 +184,7 @@ export const parseJsonToBeaconCheckpoint = (jsonInput: any): BeaconCheckpoint => const DATAHAVEN_PARAM_NAMES = [ "EthereumGatewayAddress", "RewardsUpdateSelector", - "RewardsAgentOrigin", + "AgentOrigin", "DatahavenServiceManagerAddress" ] as const;