From f07afda0b07a15b16719b83df7f5dd9ee0e7bde5 Mon Sep 17 00:00:00 2001 From: Gonza Montiel Date: Thu, 5 Jun 2025 17:00:03 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8F=97=EF=B8=8F=20=20run=20execut?= =?UTF-8?q?ion=20relayer=20=20(#73)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## This PR includes: - Running the execution relayer on the CLI - Modifying the Payload generation in the `DataHavenServiceManager.sol` - Modified the `EigenLayerMessageProcessor` to work with the ValidatorSet update message, but for this change we are loosing the generic message type (it was the only way to make it work so far). - Adds a `--no-wait` argument to the cli launch and stop commands to bootstrap faster. ### Testing the Snowbridge message encoding / decoding - Added`MessageEncoding.t.sol` is documented and explains how to generate bin data to use in the rust test. - Added a Rust unit test to `EigenLayerMessageProcessor` to compare the message encoding/decoding taking the bytes from a file (previously generated with some mock data). Specifically, we want that: https://github.com/Moonsong-Labs/datahaven/blob/3cbca0db6d0bcc6cd6969b13b214a27465460b45/contracts/src/libraries/DataHavenSnowbridgeMessages.sol#L78-L85 Generates the right bytes encoding for https://github.com/Moonsong-Labs/datahaven/blob/0e2c9cd518ada0893f1759eee229976fb5a90495/operator/primitives/bridge/src/lib.rs#L51 If the test passes, it's very likely that the CLI will also pass, if not, then we might wanna check something else is missing. ### Breaking change ⚠️ For compatibility reasons with Snowbridge contracts (they call specific extrinsics of specific pallets), I had to rename: - `InboundQueueV2` -> `EthereumInboundQueueV2` - `OutboundQueueV2` -> `EthereumOutboundQueueV2` ## For follow up PRs: - Add an automated way of generating the Solidity bytes fo testing, so we don't need to maintain the MessageEncoding.t.sol and generate the binary data manually. ## Summary by CodeRabbit - **New Features** - Added support for the "execution" relayer type in relay configuration, parsing, and CLI launch utilities. - Introduced a Solidity test contract for encoding and logging validator set messages. - Added a comprehensive "start:all" script to streamline launching and setup processes. - **Enhancements** - Improved message encoding for validator set updates, aligning with new struct field names and message formats. - Updated relay configuration schema and validation to support execution relayers and OFAC settings. - Increased beacon datastore capacity and adjusted relay scheduling parameters in configuration files. - **Refactor** - Renamed runtime type aliases for inbound/outbound queues to more descriptive names across mainnet, stagenet, and testnet. - Centralized and streamlined validator set update logic in CLI utilities. - Centralized message decoding logic and improved visibility of message fields in Rust components. - **Bug Fixes** - Improved error handling and decoding logic for message processing in Rust components. - **Tests** - Added Rust and Solidity tests for message encoding and processing validation. - **Chores** - Updated dependencies and feature flags in Rust project configuration. --------- Co-authored-by: Facundo Farall <37149322+ffarall@users.noreply.github.com> --- contracts/src/DataHavenServiceManager.sol | 2 +- .../libraries/DataHavenSnowbridgeMessages.sol | 45 ++++++-- contracts/test/MessageEncoding.t.sol | 44 +++++++ operator/Cargo.lock | 1 + operator/primitives/bridge/Cargo.toml | 2 + operator/primitives/bridge/src/lib.rs | 26 ++++- .../test_data/receive_validators_message.bin | Bin 0 -> 119 bytes operator/runtime/mainnet/src/configs/mod.rs | 19 +-- operator/runtime/mainnet/src/lib.rs | 4 +- operator/runtime/stagenet/src/configs/mod.rs | 19 +-- operator/runtime/stagenet/src/lib.rs | 4 +- operator/runtime/testnet/src/configs/mod.rs | 19 +-- operator/runtime/testnet/src/lib.rs | 94 ++++++++++++++- test/bun.lockb | Bin 0 -> 271040 bytes test/cli/handlers/launch/index.ts | 4 +- test/cli/handlers/launch/relayer.ts | 109 +++++++++++------- test/cli/handlers/launch/validator.ts | 70 ++++++----- test/configs/snowbridge/execution-relay.json | 1 - test/package.json | 1 + test/utils/parser.ts | 87 +++++++++++--- 20 files changed, 414 insertions(+), 137 deletions(-) create mode 100644 contracts/test/MessageEncoding.t.sol create mode 100644 operator/primitives/bridge/test_data/receive_validators_message.bin create mode 100755 test/bun.lockb diff --git a/contracts/src/DataHavenServiceManager.sol b/contracts/src/DataHavenServiceManager.sol index 62a7e83f..b03bef29 100644 --- a/contracts/src/DataHavenServiceManager.sol +++ b/contracts/src/DataHavenServiceManager.sol @@ -118,7 +118,7 @@ contract DataHavenServiceManager is ServiceManagerBase, IDataHavenServiceManager newValidatorSet[i] = validatorEthAddressToSolochainAddress[currentValidatorSet[i]]; } DataHavenSnowbridgeMessages.NewValidatorSetPayload memory newValidatorSetPayload = - DataHavenSnowbridgeMessages.NewValidatorSetPayload({newValidatorSet: newValidatorSet}); + DataHavenSnowbridgeMessages.NewValidatorSetPayload({validators: newValidatorSet}); DataHavenSnowbridgeMessages.NewValidatorSet memory newValidatorSetMessage = DataHavenSnowbridgeMessages.NewValidatorSet({ nonce: 0, diff --git a/contracts/src/libraries/DataHavenSnowbridgeMessages.sol b/contracts/src/libraries/DataHavenSnowbridgeMessages.sol index b3bfb8ad..1bf7a126 100644 --- a/contracts/src/libraries/DataHavenSnowbridgeMessages.sol +++ b/contracts/src/libraries/DataHavenSnowbridgeMessages.sol @@ -5,6 +5,18 @@ pragma solidity ^0.8.27; import {ScaleCodec} from "snowbridge/src/utils/ScaleCodec.sol"; library DataHavenSnowbridgeMessages { + // Message ID. This is not expected to change and comes from the runtime. + // See EigenLayerMessageProcessor in primitives/bridge/src/lib.rs. + bytes4 constant EL_MESSAGE_ID = 0x70150038; + + enum Message { + V0 + } + + enum OutboundCommandV1 { + ReceiveValidators + } + /** * @title New Validator Set Snowbridge Message * @notice A struct representing a new validator set to be sent as a message through Snowbridge. @@ -25,13 +37,12 @@ library DataHavenSnowbridgeMessages { /** * @title New Validator Set Snowbridge Message Payload * @notice A struct representing the payload of a new validator set message. - * !IMPORTANT: The fields in this struct are placeholder until we have the actual message format - * ! defined in the DataHaven solochain. + * This mimics the message format defined in the InboundQueueV2 pallet of the DataHaven + * solochain. */ struct NewValidatorSetPayload { - /// @notice The new validator set. This should be interpreted as the list of - /// validator addresses in the DataHaven network. - bytes32[] newValidatorSet; + /// @notice The list of validators in the DataHaven network. + bytes32[] validators; } /** @@ -57,13 +68,23 @@ library DataHavenSnowbridgeMessages { function scaleEncodeNewValidatorSetMessagePayload( NewValidatorSetPayload memory payload ) public pure returns (bytes memory) { - // Encode all fields into a buffer. - bytes memory accum = hex""; - for (uint256 i = 0; i < payload.newValidatorSet.length; i++) { - accum = bytes.concat(accum, payload.newValidatorSet[i]); + uint32 validatorsLen = uint32(payload.validators.length); + bytes32[] memory validatorSet = payload.validators; + // TODO: This shouldn't be hardcoded, but set to the corresponding epoch of this validator set. + uint48 epoch = 0; + bytes memory validatorsFlattened; + for (uint32 i = 0; i < validatorSet.length; i++) { + validatorsFlattened = + bytes.concat(validatorsFlattened, abi.encodePacked(validatorSet[i])); } - // Encode number of validator addresses, followed by encoded validator addresses. - return - bytes.concat(ScaleCodec.checkedEncodeCompactU32(payload.newValidatorSet.length), accum); + + return bytes.concat( + EL_MESSAGE_ID, + bytes1(uint8(Message.V0)), + bytes1(uint8(OutboundCommandV1.ReceiveValidators)), + ScaleCodec.encodeCompactU32(validatorsLen), + validatorsFlattened, + ScaleCodec.encodeU64(uint64(epoch)) + ); } } diff --git a/contracts/test/MessageEncoding.t.sol b/contracts/test/MessageEncoding.t.sol new file mode 100644 index 00000000..8a884c5f --- /dev/null +++ b/contracts/test/MessageEncoding.t.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.27; + +import {Test} from "forge-std/Test.sol"; +import {console} from "forge-std/console.sol"; +import {DataHavenSnowbridgeMessages} from "../src/libraries/DataHavenSnowbridgeMessages.sol"; + +// This test is used to encode the receive validators message and log the hex string. +// The hex string is then used to generate the .bin file for the Rust test. +// To generate the .bin file, run: +// forge test --match-test testEncodeReceiveValidatorsMessageAndLog +// Then, copy the hex string and paste it into the Rust test file. +// Then, run: +// cargo test --test decode_receive_validators_message_from_file_correctly +// The test should pass. +contract MessageEncodingTest is Test { + function testEncodeReceiveValidatorsMessageAndLog() public pure { + // Mock Data - + uint64 mockNonce = 12345; + bytes32 mockTopic = 0x123456789012345678901234567890123456789012345678901234567890abcd; + + bytes32[] memory mockValidators = new bytes32[](2); + mockValidators[0] = 0x0000000000000000000000000000000000000000000000000000000000000001; + mockValidators[1] = 0x0000000000000000000000000000000000000000000000000000000000000002; + // uint64 mockEpoch = 0; // This is hardcoded to 0 in the Solidity function's payload part + + DataHavenSnowbridgeMessages.NewValidatorSetPayload memory newValidatorSetPayload = + DataHavenSnowbridgeMessages.NewValidatorSetPayload({validators: mockValidators}); + // epoch is implicitly 0 in scaleEncodeNewValidatorSetMessagePayload + + DataHavenSnowbridgeMessages.NewValidatorSet memory newValidatorSetMessage = + DataHavenSnowbridgeMessages.NewValidatorSet({ + nonce: mockNonce, + topic: mockTopic, + payload: newValidatorSetPayload + }); + + bytes memory encodedMessage = + DataHavenSnowbridgeMessages.scaleEncodeNewValidatorSetMessage(newValidatorSetMessage); + + console.log("Encoded NewValidatorSet message (hex):"); + console.logBytes(encodedMessage); // This will print the hex string + } +} diff --git a/operator/Cargo.lock b/operator/Cargo.lock index da0b1ee7..0d51450a 100644 --- a/operator/Cargo.lock +++ b/operator/Cargo.lock @@ -2821,6 +2821,7 @@ version = "0.1.0" dependencies = [ "frame-support", "frame-system", + "hex", "pallet-external-validators", "parity-scale-codec", "snowbridge-core 0.2.0", diff --git a/operator/primitives/bridge/Cargo.toml b/operator/primitives/bridge/Cargo.toml index 8f1a1317..b87aad6e 100644 --- a/operator/primitives/bridge/Cargo.toml +++ b/operator/primitives/bridge/Cargo.toml @@ -15,6 +15,7 @@ parity-scale-codec = { workspace = true } snowbridge-core = { workspace = true } snowbridge-inbound-queue-primitives = { workspace = true } sp-std = { workspace = true } +hex = { workspace = true } [features] default = ["std"] @@ -25,4 +26,5 @@ std = [ "parity-scale-codec/std", "pallet-external-validators/std", "sp-std/std", + "snowbridge-inbound-queue-primitives/std", ] diff --git a/operator/primitives/bridge/src/lib.rs b/operator/primitives/bridge/src/lib.rs index afe74204..e10cd01c 100644 --- a/operator/primitives/bridge/src/lib.rs +++ b/operator/primitives/bridge/src/lib.rs @@ -5,15 +5,17 @@ use parity_scale_codec::DecodeAll; use snowbridge_inbound_queue_primitives::v2::{Message as SnowbridgeMessage, MessageProcessor}; use sp_std::vec::Vec; -pub const EL_MESSAGE_ID: [u8; 4] = [112, 21, 0, 56]; +// Message ID. This is not expected to change and its arbitrary bytes defined here. +// It should match the EL_MESSAGE_ID in DataHavenSnowbridgeMessages.sol +pub const EL_MESSAGE_ID: [u8; 4] = [112, 21, 0, 56]; // 0x70150038 #[derive(Encode, Decode)] pub struct Payload where T: pallet_external_validators::Config, { - message: Message, - message_id: [u8; 4], + pub message: Message, + pub message_id: [u8; 4], } #[derive(Encode, Decode)] @@ -38,6 +40,20 @@ where /// EigenLayer Message Processor pub struct EigenLayerMessageProcessor(PhantomData); +impl EigenLayerMessageProcessor +where + T: pallet_external_validators::Config, +{ + pub fn decode_message(mut payload: &[u8]) -> Result, DispatchError> { + let decode_result = Payload::::decode_all(&mut payload); + if let Ok(payload) = decode_result { + Ok(payload) + } else { + Err(DispatchError::Other("unable to parse the message payload")) + } + } +} + impl MessageProcessor for EigenLayerMessageProcessor where T: pallet_external_validators::Config, @@ -50,7 +66,7 @@ where network: _, } => return false, }; - let decode_result = Payload::::decode_all(&mut payload.as_slice()); + let decode_result = Self::decode_message(payload.as_slice()); if let Ok(payload) = decode_result { payload.message_id == EL_MESSAGE_ID } else { @@ -69,7 +85,7 @@ where network: _, } => return Err(DispatchError::Other("Invalid Message")), }; - let decode_result = Payload::::decode_all(&mut payload.as_slice()); + let decode_result = Self::decode_message(payload.as_slice()); let message = if let Ok(payload) = decode_result { payload.message } else { diff --git a/operator/primitives/bridge/test_data/receive_validators_message.bin b/operator/primitives/bridge/test_data/receive_validators_message.bin new file mode 100644 index 0000000000000000000000000000000000000000..23741a0e13ebb58f6d508559686949580e74eac2 GIT binary patch literal 119 ncmcCCU;qOlldy^jIEmF~3q%<#7#KJpigA*RIAtIbOfY!>k^&5Z literal 0 HcmV?d00001 diff --git a/operator/runtime/mainnet/src/configs/mod.rs b/operator/runtime/mainnet/src/configs/mod.rs index 212a825a..cc9a304b 100644 --- a/operator/runtime/mainnet/src/configs/mod.rs +++ b/operator/runtime/mainnet/src/configs/mod.rs @@ -27,11 +27,12 @@ mod runtime_params; use super::{ deposit, AccountId, Babe, Balance, Balances, BeefyMmrLeaf, Block, BlockNumber, - EthereumBeaconClient, EvmChainId, ExternalValidators, ExternalValidatorsRewards, Hash, - Historical, ImOnline, MessageQueue, Nonce, Offences, OriginCaller, OutboundCommitmentStore, - OutboundQueueV2, PalletInfo, Preimage, Runtime, RuntimeCall, RuntimeEvent, RuntimeFreezeReason, - RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, SessionKeys, Signature, System, - Timestamp, EXISTENTIAL_DEPOSIT, SLOT_DURATION, STORAGE_BYTE_FEE, SUPPLY_FACTOR, UNIT, VERSION, + EthereumBeaconClient, EthereumOutboundQueueV2, EvmChainId, ExternalValidators, + ExternalValidatorsRewards, Hash, Historical, ImOnline, MessageQueue, Nonce, Offences, + OriginCaller, OutboundCommitmentStore, PalletInfo, Preimage, Runtime, RuntimeCall, + RuntimeEvent, RuntimeFreezeReason, RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, + SessionKeys, Signature, System, Timestamp, EXISTENTIAL_DEPOSIT, SLOT_DURATION, + STORAGE_BYTE_FEE, SUPPLY_FACTOR, UNIT, VERSION, }; use codec::{Decode, Encode}; use datahaven_runtime_common::{ @@ -532,7 +533,7 @@ parameter_types! { impl pallet_message_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = OutboundQueueV2; + type MessageProcessor = EthereumOutboundQueueV2; #[cfg(feature = "runtime-benchmarks")] type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor; @@ -698,7 +699,7 @@ impl snowbridge_pallet_system::Config for Runtime { // Implement the Snowbridge System v2 config trait impl snowbridge_pallet_system_v2::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type OutboundQueue = OutboundQueueV2; + type OutboundQueue = EthereumOutboundQueueV2; type FrontendOrigin = EnsureRootWithSuccess; type GovernanceOrigin = EnsureRootWithSuccess; type WeightInfo = (); @@ -956,10 +957,10 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt } fn validate(message: Self::Message) -> Result { - OutboundQueueV2::validate(&message) + EthereumOutboundQueueV2::validate(&message) } fn deliver(message: Self::Ticket) -> Result { - OutboundQueueV2::deliver(message) + EthereumOutboundQueueV2::deliver(message) } } diff --git a/operator/runtime/mainnet/src/lib.rs b/operator/runtime/mainnet/src/lib.rs index 5736a67c..821ba9d2 100644 --- a/operator/runtime/mainnet/src/lib.rs +++ b/operator/runtime/mainnet/src/lib.rs @@ -322,10 +322,10 @@ mod runtime { pub type EthereumBeaconClient = snowbridge_pallet_ethereum_client; #[runtime::pallet_index(61)] - pub type InboundQueueV2 = snowbridge_pallet_inbound_queue_v2; + pub type EthereumInboundQueueV2 = snowbridge_pallet_inbound_queue_v2; #[runtime::pallet_index(62)] - pub type OutboundQueueV2 = snowbridge_pallet_outbound_queue_v2; + pub type EthereumOutboundQueueV2 = snowbridge_pallet_outbound_queue_v2; #[runtime::pallet_index(63)] pub type SnowbridgeSystem = snowbridge_pallet_system; diff --git a/operator/runtime/stagenet/src/configs/mod.rs b/operator/runtime/stagenet/src/configs/mod.rs index 0e80adab..105463be 100644 --- a/operator/runtime/stagenet/src/configs/mod.rs +++ b/operator/runtime/stagenet/src/configs/mod.rs @@ -27,11 +27,12 @@ mod runtime_params; use super::{ deposit, AccountId, Babe, Balance, Balances, BeefyMmrLeaf, Block, BlockNumber, - EthereumBeaconClient, EvmChainId, ExternalValidators, ExternalValidatorsRewards, Hash, - Historical, ImOnline, MessageQueue, Nonce, Offences, OriginCaller, OutboundCommitmentStore, - OutboundQueueV2, PalletInfo, Preimage, Runtime, RuntimeCall, RuntimeEvent, RuntimeFreezeReason, - RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, SessionKeys, Signature, System, - Timestamp, EXISTENTIAL_DEPOSIT, SLOT_DURATION, STORAGE_BYTE_FEE, SUPPLY_FACTOR, UNIT, VERSION, + EthereumBeaconClient, EthereumOutboundQueueV2, EvmChainId, ExternalValidators, + ExternalValidatorsRewards, Hash, Historical, ImOnline, MessageQueue, Nonce, Offences, + OriginCaller, OutboundCommitmentStore, PalletInfo, Preimage, Runtime, RuntimeCall, + RuntimeEvent, RuntimeFreezeReason, RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, + SessionKeys, Signature, System, Timestamp, EXISTENTIAL_DEPOSIT, SLOT_DURATION, + STORAGE_BYTE_FEE, SUPPLY_FACTOR, UNIT, VERSION, }; use codec::{Decode, Encode}; use datahaven_runtime_common::{ @@ -531,7 +532,7 @@ parameter_types! { impl pallet_message_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = OutboundQueueV2; + type MessageProcessor = EthereumOutboundQueueV2; #[cfg(feature = "runtime-benchmarks")] type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor; @@ -699,7 +700,7 @@ impl snowbridge_pallet_system::Config for Runtime { // Implement the Snowbridge System v2 config trait impl snowbridge_pallet_system_v2::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type OutboundQueue = OutboundQueueV2; + type OutboundQueue = EthereumOutboundQueueV2; type FrontendOrigin = EnsureRootWithSuccess; type GovernanceOrigin = EnsureRootWithSuccess; type WeightInfo = (); @@ -917,10 +918,10 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt } fn validate(message: Self::Message) -> Result { - OutboundQueueV2::validate(&message) + EthereumOutboundQueueV2::validate(&message) } fn deliver(message: Self::Ticket) -> Result { - OutboundQueueV2::deliver(message) + EthereumOutboundQueueV2::deliver(message) } } diff --git a/operator/runtime/stagenet/src/lib.rs b/operator/runtime/stagenet/src/lib.rs index 56893b20..7d35c34b 100644 --- a/operator/runtime/stagenet/src/lib.rs +++ b/operator/runtime/stagenet/src/lib.rs @@ -322,10 +322,10 @@ mod runtime { pub type EthereumBeaconClient = snowbridge_pallet_ethereum_client; #[runtime::pallet_index(61)] - pub type InboundQueueV2 = snowbridge_pallet_inbound_queue_v2; + pub type EthereumInboundQueueV2 = snowbridge_pallet_inbound_queue_v2; #[runtime::pallet_index(62)] - pub type OutboundQueueV2 = snowbridge_pallet_outbound_queue_v2; + pub type EthereumOutboundQueueV2 = snowbridge_pallet_outbound_queue_v2; #[runtime::pallet_index(63)] pub type SnowbridgeSystem = snowbridge_pallet_system; diff --git a/operator/runtime/testnet/src/configs/mod.rs b/operator/runtime/testnet/src/configs/mod.rs index a21828a4..ca9686be 100644 --- a/operator/runtime/testnet/src/configs/mod.rs +++ b/operator/runtime/testnet/src/configs/mod.rs @@ -27,11 +27,12 @@ mod runtime_params; use super::{ deposit, AccountId, Babe, Balance, Balances, BeefyMmrLeaf, Block, BlockNumber, - EthereumBeaconClient, EvmChainId, ExternalValidators, ExternalValidatorsRewards, Hash, - Historical, ImOnline, MessageQueue, Nonce, Offences, OriginCaller, OutboundCommitmentStore, - OutboundQueueV2, PalletInfo, Preimage, Runtime, RuntimeCall, RuntimeEvent, RuntimeFreezeReason, - RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, SessionKeys, Signature, System, - Timestamp, EXISTENTIAL_DEPOSIT, SLOT_DURATION, STORAGE_BYTE_FEE, SUPPLY_FACTOR, UNIT, VERSION, + EthereumBeaconClient, EthereumOutboundQueueV2, EvmChainId, ExternalValidators, + ExternalValidatorsRewards, Hash, Historical, ImOnline, MessageQueue, Nonce, Offences, + OriginCaller, OutboundCommitmentStore, PalletInfo, Preimage, Runtime, RuntimeCall, + RuntimeEvent, RuntimeFreezeReason, RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, + SessionKeys, Signature, System, Timestamp, EXISTENTIAL_DEPOSIT, SLOT_DURATION, + STORAGE_BYTE_FEE, SUPPLY_FACTOR, UNIT, VERSION, }; use codec::{Decode, Encode}; use datahaven_runtime_common::{ @@ -531,7 +532,7 @@ parameter_types! { impl pallet_message_queue::Config for Runtime { type RuntimeEvent = RuntimeEvent; #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = OutboundQueueV2; + type MessageProcessor = EthereumOutboundQueueV2; #[cfg(feature = "runtime-benchmarks")] type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor; @@ -697,7 +698,7 @@ impl snowbridge_pallet_system::Config for Runtime { // Implement the Snowbridge System v2 config trait impl snowbridge_pallet_system_v2::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type OutboundQueue = OutboundQueueV2; + type OutboundQueue = EthereumOutboundQueueV2; type FrontendOrigin = EnsureRootWithSuccess; type GovernanceOrigin = EnsureRootWithSuccess; type WeightInfo = (); @@ -955,10 +956,10 @@ impl pallet_external_validators_rewards::types::SendMessage for RewardsSendAdapt } fn validate(message: Self::Message) -> Result { - OutboundQueueV2::validate(&message) + EthereumOutboundQueueV2::validate(&message) } fn deliver(message: Self::Ticket) -> Result { - OutboundQueueV2::deliver(message) + EthereumOutboundQueueV2::deliver(message) } } diff --git a/operator/runtime/testnet/src/lib.rs b/operator/runtime/testnet/src/lib.rs index 4e99e62d..a20bad9b 100644 --- a/operator/runtime/testnet/src/lib.rs +++ b/operator/runtime/testnet/src/lib.rs @@ -322,10 +322,10 @@ mod runtime { pub type EthereumBeaconClient = snowbridge_pallet_ethereum_client; #[runtime::pallet_index(61)] - pub type InboundQueueV2 = snowbridge_pallet_inbound_queue_v2; + pub type EthereumInboundQueueV2 = snowbridge_pallet_inbound_queue_v2; #[runtime::pallet_index(62)] - pub type OutboundQueueV2 = snowbridge_pallet_outbound_queue_v2; + pub type EthereumOutboundQueueV2 = snowbridge_pallet_outbound_queue_v2; #[runtime::pallet_index(63)] pub type SnowbridgeSystem = snowbridge_pallet_system; @@ -1091,3 +1091,93 @@ impl_runtime_apis! { } } } + +#[cfg(test)] +mod tests { + use super::*; + use codec::Encode; + use dhp_bridge::InboundCommand; + use dhp_bridge::{Message, Payload, EL_MESSAGE_ID}; + use snowbridge_inbound_queue_primitives::v2::{Message as SnowbridgeMessage, MessageProcessor}; + use sp_core::H256; + + const MOCK_NONCE: u64 = 12345u64; + const MOCK_VALIDATORS_HEX: [&str; 2] = [ + "0000000000000000000000000000000000000000000000000000000000000001", + "0000000000000000000000000000000000000000000000000000000000000002", + ]; + const MOCK_EXTERNAL_INDEX: u64 = 0u64; + + fn hex_to_bytes32(hex_str: &str) -> [u8; 32] { + let mut arr = [0u8; 32]; + hex::decode_to_slice(hex_str, &mut arr).expect("Failed to decode hex string to bytes32"); + arr + } + + #[test] + fn test_eigenlayer_message_processor() { + // Create mock validators + let validators: Vec = MOCK_VALIDATORS_HEX + .iter() + .map(|s| hex_to_bytes32(s).into()) + .collect(); + + // Create a mock message payload + let message = Message::V1(dhp_bridge::InboundCommand::ReceiveValidators { + validators: validators.clone(), + external_index: MOCK_EXTERNAL_INDEX, + }); + + let payload = Payload:: { + message, + message_id: EL_MESSAGE_ID, + }; + + // Create a mock Snowbridge message + let snowbridge_message = SnowbridgeMessage { + xcm: snowbridge_inbound_queue_primitives::v2::Payload::Raw(payload.encode()), + gateway: H160::default(), + nonce: MOCK_NONCE, + origin: H160::default(), + assets: vec![], + claimer: None, + value: 0u128, + execution_fee: 0u128, + relayer_fee: 0u128, + }; + + // Test can_process_message + let mock_account = H256::from_slice(&[1u8; 32]); + assert!( + dhp_bridge::EigenLayerMessageProcessor::::can_process_message( + &mock_account, + &snowbridge_message + ), + "Message should be processable" + ); + + let payload = match &snowbridge_message.xcm { + snowbridge_inbound_queue_primitives::v2::Payload::Raw(payload) => payload, + _ => panic!("Invalid Message"), + }; + + let decoded_result = + dhp_bridge::EigenLayerMessageProcessor::::decode_message(payload.as_slice()); + + let message = if let Ok(payload) = decoded_result { + payload.message + } else { + panic!("unable to parse the message payload"); + }; + + match message { + Message::V1(InboundCommand::ReceiveValidators { + validators, + external_index, + }) => { + assert_eq!(validators, validators); + assert_eq!(external_index, MOCK_EXTERNAL_INDEX); + } + } + } +} diff --git a/test/bun.lockb b/test/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..13057c99d35ad41e7af39ddad1955444b0f415be GIT binary patch literal 271040 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 literal 0 HcmV?d00001 diff --git a/test/cli/handlers/launch/index.ts b/test/cli/handlers/launch/index.ts index 85d96c2d..61d3ebff 100644 --- a/test/cli/handlers/launch/index.ts +++ b/test/cli/handlers/launch/index.ts @@ -8,7 +8,7 @@ import { launchKurtosis } from "./kurtosis"; import { LaunchedNetwork } from "./launchedNetwork"; import { launchRelayers } from "./relayer"; import { performSummaryOperations } from "./summary"; -import { performValidatorOperations } from "./validator"; +import { performValidatorOperations, performValidatorSetUpdate } from "./validator"; // Non-optional properties determined by having default values export interface LaunchOptions { @@ -93,6 +93,8 @@ const launchFunction = async (options: LaunchOptions, launchedNetwork: LaunchedN setParameters: options.setParameters }); + await performValidatorSetUpdate(options, launchedNetwork.elRpcUrl, contractsDeployed); + await performSummaryOperations(options, launchedNetwork); const fullEnd = performance.now(); const fullMinutes = ((fullEnd - timeStart) / (1000 * 60)).toFixed(1); diff --git a/test/cli/handlers/launch/relayer.ts b/test/cli/handlers/launch/relayer.ts index 3afe6e91..5f346376 100644 --- a/test/cli/handlers/launch/relayer.ts +++ b/test/cli/handlers/launch/relayer.ts @@ -40,6 +40,7 @@ const RELAYER_CONFIG_DIR = "tmp/configs"; const RELAYER_CONFIG_PATHS = { BEACON: path.join(RELAYER_CONFIG_DIR, "beacon-relay.json"), BEEFY: path.join(RELAYER_CONFIG_DIR, "beefy-relay.json"), + EXECUTION: path.join(RELAYER_CONFIG_DIR, "execution-relay.json"), SOLOCHAIN: path.join(RELAYER_CONFIG_DIR, "solochain-relay.json") }; const INITIAL_CHECKPOINT_FILE = "dump-initial-checkpoint.json"; @@ -146,6 +147,15 @@ export const launchRelayers = async (options: LaunchOptions, launchedNetwork: La type: "substrate", value: SUBSTRATE_FUNDED_ACCOUNTS.CHARLETH.privateKey } + }, + { + name: "relayer-⚙️", + type: "execution", + config: RELAYER_CONFIG_PATHS.EXECUTION, + pk: { + type: "substrate", + value: SUBSTRATE_FUNDED_ACCOUNTS.BALTATHAR.privateKey + } } ]; @@ -179,51 +189,60 @@ export const launchRelayers = async (options: LaunchOptions, launchedNetwork: La ); switch (type) { - case "beacon": - { - const cfg = parseRelayConfig(json, type); - cfg.source.beacon.endpoint = `http://host.docker.internal:${ethHttpPort}`; - cfg.source.beacon.stateEndpoint = `http://host.docker.internal:${ethHttpPort}`; - cfg.source.beacon.datastore.location = "/data"; - cfg.sink.parachain.endpoint = `ws://${substrateNodeId}:${substrateWsPort}`; + case "beacon": { + const cfg = parseRelayConfig(json, type); + cfg.source.beacon.endpoint = `http://host.docker.internal:${ethHttpPort}`; + cfg.source.beacon.stateEndpoint = `http://host.docker.internal:${ethHttpPort}`; + cfg.source.beacon.datastore.location = "/data"; + cfg.sink.parachain.endpoint = `ws://${substrateNodeId}:${substrateWsPort}`; - await Bun.write(outputFilePath, JSON.stringify(cfg, null, 4)); - logger.success(`Updated beacon config written to ${outputFilePath}`); - } + await Bun.write(outputFilePath, JSON.stringify(cfg, null, 4)); + logger.success(`Updated beacon config written to ${outputFilePath}`); break; - case "beefy": - { - const cfg = parseRelayConfig(json, type); - cfg.source.polkadot.endpoint = `ws://${substrateNodeId}:${substrateWsPort}`; - cfg.sink.ethereum.endpoint = `ws://host.docker.internal:${ethWsPort}`; - cfg.sink.contracts.BeefyClient = beefyClientAddress; - cfg.sink.contracts.Gateway = gatewayAddress; - await Bun.write(outputFilePath, JSON.stringify(cfg, null, 4)); - logger.success(`Updated beefy config written to ${outputFilePath}`); - } + } + case "beefy": { + const cfg = parseRelayConfig(json, type); + cfg.source.polkadot.endpoint = `ws://${substrateNodeId}:${substrateWsPort}`; + cfg.sink.ethereum.endpoint = `ws://host.docker.internal:${ethWsPort}`; + cfg.sink.contracts.BeefyClient = beefyClientAddress; + cfg.sink.contracts.Gateway = gatewayAddress; + await Bun.write(outputFilePath, JSON.stringify(cfg, null, 4)); + logger.success(`Updated beefy config written to ${outputFilePath}`); break; - case "solochain": - { - const cfg = parseRelayConfig(json, type); - cfg.source.ethereum.endpoint = `ws://host.docker.internal:${ethWsPort}`; - cfg.source.solochain.endpoint = `ws://${substrateNodeId}:${substrateWsPort}`; - cfg.source.contracts.BeefyClient = beefyClientAddress; - cfg.source.contracts.Gateway = gatewayAddress; - cfg.source.beacon.endpoint = `http://host.docker.internal:${ethHttpPort}`; - cfg.source.beacon.stateEndpoint = `http://host.docker.internal:${ethHttpPort}`; - cfg.source.beacon.datastore.location = datastorePath; - cfg.sink.ethereum.endpoint = `ws://host.docker.internal:${ethWsPort}`; - cfg.sink.contracts.Gateway = gatewayAddress; - await Bun.write(outputFilePath, JSON.stringify(cfg, null, 4)); - logger.success(`Updated solochain config written to ${outputFilePath}`); - } + } + case "execution": { + const cfg = parseRelayConfig(json, type); + cfg.source.ethereum.endpoint = `ws://host.docker.internal:${ethWsPort}`; + cfg.source.beacon.endpoint = `http://host.docker.internal:${ethHttpPort}`; + cfg.source.beacon.stateEndpoint = `http://host.docker.internal:${ethHttpPort}`; + cfg.source.beacon.datastore.location = "/data"; + cfg.sink.parachain.endpoint = `ws://${substrateNodeId}:${substrateWsPort}`; + cfg.source.contracts.Gateway = gatewayAddress; + await Bun.write(outputFilePath, JSON.stringify(cfg, null, 4)); + logger.success(`Updated execution config written to ${outputFilePath}`); break; + } + case "solochain": { + const cfg = parseRelayConfig(json, type); + cfg.source.ethereum.endpoint = `ws://host.docker.internal:${ethWsPort}`; + cfg.source.solochain.endpoint = `ws://${substrateNodeId}:${substrateWsPort}`; + cfg.source.contracts.BeefyClient = beefyClientAddress; + cfg.source.contracts.Gateway = gatewayAddress; + cfg.source.beacon.endpoint = `http://host.docker.internal:${ethHttpPort}`; + cfg.source.beacon.stateEndpoint = `http://host.docker.internal:${ethHttpPort}`; + cfg.source.beacon.datastore.location = datastorePath; + cfg.sink.ethereum.endpoint = `ws://host.docker.internal:${ethWsPort}`; + cfg.sink.contracts.Gateway = gatewayAddress; + await Bun.write(outputFilePath, JSON.stringify(cfg, null, 4)); + logger.success(`Updated solochain config written to ${outputFilePath}`); + break; + } } } invariant(options.relayerImageTag, "❌ Relayer image tag not defined"); - await initEthClientPallet(options, launchedNetwork); + await initEthClientPallet(options, launchedNetwork, datastorePath); for (const { config, name, type, pk, secondaryPk } of relayersToStart) { try { @@ -250,10 +269,10 @@ export const launchRelayers = async (options: LaunchOptions, launchedNetwork: La ]; const volumeMounts: string[] = ["-v", `${hostConfigFilePath}:${containerConfigFilePath}`]; + const hostDatastorePath = path.resolve(datastorePath); + const containerDatastorePath = "/data"; - if (type === "beacon") { - const hostDatastorePath = path.resolve(datastorePath); - const containerDatastorePath = "/data"; + if (type === "beacon" || type === "execution") { volumeMounts.push("-v", `${hostDatastorePath}:${containerDatastorePath}`); } @@ -262,7 +281,7 @@ export const launchRelayers = async (options: LaunchOptions, launchedNetwork: La type, "--config", config, - type === "beacon" ? "--substrate.private-key" : "--ethereum.private-key", + `--${pk.type}.private-key`, pk.value ]; @@ -366,11 +385,13 @@ const waitBeefyReady = async ( * * @param options - Launch options containing the relayer binary path. * @param launchedNetwork - An instance of LaunchedNetwork to interact with the running network. + * @param datastorePath - The path to the datastore directory. * @throws If there's an error generating the beacon checkpoint or submitting it to Substrate. */ export const initEthClientPallet = async ( options: LaunchOptions, - launchedNetwork: LaunchedNetwork + launchedNetwork: LaunchedNetwork, + datastorePath: string ) => { logger.debug("Initialising eth client pallet"); // Poll the beacon chain until it's ready every 10 seconds for 5 minutes @@ -393,9 +414,11 @@ export const initEthClientPallet = async ( launchedNetwork.networkName, "❌ Docker network name not found in LaunchedNetwork instance" ); + const datastoreHostPath = path.resolve(datastorePath); const command = `docker run \ -v ${beaconConfigHostPath}:${beaconConfigContainerPath}:ro \ -v ${checkpointHostPath}:${checkpointContainerPath} \ + -v ${datastoreHostPath}:/data \ --name generate-beacon-checkpoint \ --workdir /app \ --add-host host.docker.internal:host-gateway \ @@ -409,7 +432,9 @@ export const initEthClientPallet = async ( const initialCheckpointFile = Bun.file(INITIAL_CHECKPOINT_PATH); const initialCheckpointRaw = await initialCheckpointFile.text(); const initialCheckpoint = parseJsonToBeaconCheckpoint(JSON.parse(initialCheckpointRaw)); - await initialCheckpointFile.delete(); + if (initialCheckpointFile.delete) { + await initialCheckpointFile.delete(); + } logger.trace("Initial checkpoint:"); logger.trace(initialCheckpoint.toJSON()); diff --git a/test/cli/handlers/launch/validator.ts b/test/cli/handlers/launch/validator.ts index 872e6a4c..4e59ca4a 100644 --- a/test/cli/handlers/launch/validator.ts +++ b/test/cli/handlers/launch/validator.ts @@ -62,37 +62,49 @@ export const performValidatorOperations = async ( await setupValidators({ rpcUrl: networkRpcUrl }); + } +}; - // If not specified, prompt for update - let shouldUpdateValidatorSet = options.updateValidatorSet; - if (shouldUpdateValidatorSet === undefined) { - shouldUpdateValidatorSet = await confirmWithTimeout( - "Do you want to update the validator set on the substrate chain?", - true, - 10 - ); - } else { - logger.info( - `🏳️ Using flag option: ${shouldUpdateValidatorSet ? "will update" : "will not update"} validator set` - ); - } - - if (shouldUpdateValidatorSet) { - if (!contractsDeployed) { - logger.warn( - "⚠️ Updating validator set but contracts were not deployed in this CLI run. Could have unexpected results." - ); - } - - await updateValidatorSet({ - rpcUrl: networkRpcUrl - }); - } else { - logger.info("👍 Skipping validator set update"); - printDivider(); - } +/** + * Performs the validator set update operation based on user options + * This function is now separate so it can be called after relayers are set up + * + * @param options - CLI options for the validator set update + * @param networkRpcUrl - RPC URL for the Ethereum network + * @param contractsDeployed - Flag indicating if contracts were deployed in this CLI run + * @returns Promise resolving when the operation is complete + */ +export const performValidatorSetUpdate = async ( + options: LaunchOptions, + networkRpcUrl: string, + contractsDeployed: boolean +) => { + // If not specified, prompt for update + let shouldUpdateValidatorSet = options.updateValidatorSet; + if (shouldUpdateValidatorSet === undefined) { + shouldUpdateValidatorSet = await confirmWithTimeout( + "Do you want to update the validator set on the substrate chain?", + true, + 10 + ); } else { - logger.info("👍 Skipping validator setup"); + logger.info( + `🏳️ Using flag option: ${shouldUpdateValidatorSet ? "will update" : "will not update"} validator set` + ); + } + + if (shouldUpdateValidatorSet) { + if (!contractsDeployed) { + logger.warn( + "⚠️ Updating validator set but contracts were not deployed in this CLI run. Could have unexpected results." + ); + } + + await updateValidatorSet({ + rpcUrl: networkRpcUrl + }); + } else { + logger.info("👍 Skipping validator set update"); printDivider(); } }; diff --git a/test/configs/snowbridge/execution-relay.json b/test/configs/snowbridge/execution-relay.json index 7649b471..091c7482 100644 --- a/test/configs/snowbridge/execution-relay.json +++ b/test/configs/snowbridge/execution-relay.json @@ -6,7 +6,6 @@ "contracts": { "Gateway": "" }, - "channel-id": "", "beacon": { "endpoint": "http://127.0.0.1:9596", "stateEndpoint": "http://127.0.0.1:9596", diff --git a/test/package.json b/test/package.json index 07b0e85d..ff5a59c6 100644 --- a/test/package.json +++ b/test/package.json @@ -17,6 +17,7 @@ "start:e2e:local": "LOG_LEVEL=debug bun start:e2e:ci --bd", "start:e2e:ci": "bun cli launch --datahaven --no-build-datahaven --launch-kurtosis --deploy-contracts --fund-validators --setup-validators --update-validator-set --relayer --clean-network", "start:e2e:minrelayer": "bun cli launch --relayer --deploy-contracts --no-setup-validators --no-update-validator-set --no-fund-validators --datahaven", + "start:all": "bun cli launch --datahaven --build-datahaven --launch-kurtosis --deploy-contracts --fund-validators --setup-validators --update-validator-set --relayer --blockscout --verified --clean-network --set-parameters", "stop:docker:datahaven": "docker rm -f $(docker ps -aq --filter name='^datahaven-') 2>/dev/null || true; docker network rm datahaven-net || true", "stop:docker:relayer": "docker rm -f $(docker ps -aq --filter name='^snowbridge-relayer-') 2>/dev/null || true", "stop:e2e": "bun cli stop --all", diff --git a/test/utils/parser.ts b/test/utils/parser.ts index 36e8e498..692a297e 100644 --- a/test/utils/parser.ts +++ b/test/utils/parser.ts @@ -105,9 +105,59 @@ export const SolochainRelayConfigSchema = z.object({ apiKey: z.string() }) }); + export type SolochainRelayConfig = z.infer; -export type RelayerType = "beefy" | "beacon" | "solochain"; +export const ExecutionRelayConfigSchema = z.object({ + source: z.object({ + ethereum: z.object({ + endpoint: z.string() + }), + contracts: z.object({ + Gateway: z.string() + }), + beacon: z.object({ + endpoint: z.string(), + stateEndpoint: z.string(), + spec: z.object({ + syncCommitteeSize: z.number(), + slotsInEpoch: z.number(), + epochsPerSyncCommitteePeriod: z.number(), + forkVersions: z.object({ + deneb: z.number(), + electra: z.number() + }) + }), + datastore: z.object({ + location: z.string(), + maxEntries: z.number() + }) + }) + }), + sink: z.object({ + parachain: z.object({ + endpoint: z.string(), + maxWatchedExtrinsics: z.number(), + headerRedundancy: z.number() + }) + }), + instantVerification: z.boolean(), + schedule: z.object({ + id: z.number().nullable(), + totalRelayerCount: z.number(), + sleepInterval: z.number() + }), + ofac: z + .object({ + enabled: z.boolean(), + apiKey: z.string() + }) + .optional() +}); + +export type ExecutionRelayConfig = z.infer; + +export type RelayerType = "beefy" | "beacon" | "solochain" | "execution"; /** * Parse beacon relay configuration @@ -143,28 +193,39 @@ function parseSolochainConfig(config: unknown): SolochainRelayConfig { } /** - * Type Guard to check if a config object is a BeaconRelayConfig + * Parse execution relay configuration */ -export function isBeaconConfig( - config: BeaconRelayConfig | BeefyRelayConfig -): config is BeaconRelayConfig { - return "beacon" in config.source; +function parseExecutionConfig(config: unknown): ExecutionRelayConfig { + const result = ExecutionRelayConfigSchema.safeParse(config); + if (result.success) { + return result.data; + } + throw new Error(`Failed to parse config as ExecutionRelayConfig: ${result.error.message}`); } export function parseRelayConfig(config: unknown, type: "beacon"): BeaconRelayConfig; export function parseRelayConfig(config: unknown, type: "beefy"): BeefyRelayConfig; +export function parseRelayConfig(config: unknown, type: "execution"): ExecutionRelayConfig; export function parseRelayConfig(config: unknown, type: "solochain"): SolochainRelayConfig; export function parseRelayConfig( config: unknown, type: RelayerType -): BeaconRelayConfig | BeefyRelayConfig | SolochainRelayConfig; +): BeaconRelayConfig | BeefyRelayConfig | ExecutionRelayConfig | SolochainRelayConfig; + export function parseRelayConfig( config: unknown, type: RelayerType -): BeaconRelayConfig | BeefyRelayConfig | SolochainRelayConfig { - return type === "beacon" - ? parseBeaconConfig(config) - : type === "beefy" - ? parseBeefyConfig(config) - : parseSolochainConfig(config); +): BeaconRelayConfig | BeefyRelayConfig | ExecutionRelayConfig | SolochainRelayConfig { + switch (type) { + case "beacon": + return parseBeaconConfig(config); + case "beefy": + return parseBeefyConfig(config); + case "execution": + return parseExecutionConfig(config); + case "solochain": + return parseSolochainConfig(config); + default: + throw new Error(`Unknown relayer type: ${type}`); + } }