From 6e6492bfdf0b9755b8b689350eb5cd42cd7d0e6e Mon Sep 17 00:00:00 2001 From: David Dunn <26876072+doubledup@users.noreply.github.com> Date: Tue, 18 Oct 2022 15:06:56 +0200 Subject: [PATCH] SNO-305: Ethereum -> Parachain: bundle messages by address (#699) * SNO-324: Enable multiple accounts in outbound channel contract (#685) * Track nonces by source address * Remove principal from basic outbound channel * Update relayer bindings * Track nonces by origin address * Fix outbound channel tests * SNO-325: Enable multiple accounts in inbound channel pallet (#687) * Add origin field to message decoding * Track nonces by message origin * Include origin address in basic channel message id * Update basic inbound fixture data * Add note about updating inbound channel test data * Mention message data encoding in comment * Update test data in envelope test * Remove channel id from message id * s/origin/user/g * Swap the order of source & user * Reword test data generation section * s/value/nonce * Use named fields in MessageId enum * Switch to Twox64Concat hasher This prevents accidental expensive lookups while remaining relatively fast vs Blake2_128 and resistant to attacks that cause prefix collisions, thanks to the security of keccak used to create the Ethereum address. * Remove rogue print statement * SNO-326: Forward messages by address in relayer (#695) * Remove redundant slice * Add initial address filtering * Remove extra nonce var * Clean up basic channel address config * Rename parachain relayer account config * Remove unused method * Fix up comments * Add default eth addresses for basic channel * Improve map log readability * Fix parachain writer error messages * Bump lodestar version in example command * Switch to default eth account for E2E script * Increase default timeout from 6m 40s to 25m This helps with some of the longer running tests that are timing out when given 400s. * Rename mapping to nonce * Rename origin to account in basic outbound channel * Remove principal from outbound channel contract * Rename user to account in basic inbound channel * Fix event account field rename in test --- ethereum/.envrc-example | 1 - ethereum/contracts/BasicOutboundChannel.sol | 35 ++--- ethereum/deploy/20-configure-channels.ts | 6 - ethereum/test/test_basic_outbound_channel.js | 9 +- parachain/README.md | 26 ++++ .../basic-channel/src/inbound/envelope.rs | 45 +++--- .../pallets/basic-channel/src/inbound/mod.rs | 6 +- .../pallets/basic-channel/src/inbound/test.rs | 64 +++++---- .../incentivized-channel/src/inbound/mod.rs | 2 +- parachain/primitives/core/src/types.rs | 16 +-- relayer/chain/chain.go | 9 +- relayer/contracts/basic/outbound.go | 133 ++++++------------ relayer/relays/beacon/config/config.go | 26 +++- .../beacon/message/ethereum-listener.go | 26 ++-- relayer/relays/beacon/message/message.go | 65 ++++++--- .../relays/beacon/writer/parachain-writer.go | 25 ++-- relayer/relays/parachain/beefy-listener.go | 26 ++-- relayer/relays/parachain/config.go | 4 +- test/.envrc-example | 1 - test/README.md | 2 +- test/config/beacon-relay.json | 3 +- test/config/parachain-relay.json | 2 +- test/package.json | 2 +- test/scripts/start-services.sh | 20 +-- 24 files changed, 289 insertions(+), 265 deletions(-) diff --git a/ethereum/.envrc-example b/ethereum/.envrc-example index 59d90cfa1eb20..bb67bd66c2cd7 100644 --- a/ethereum/.envrc-example +++ b/ethereum/.envrc-example @@ -4,7 +4,6 @@ export INFURA_PROJECT_ID= export ETHERSCAN_API_KEY= # Basic Channel -export BASIC_CHANNEL_PRINCIPAL=0x0000000000000000000000000000000000000042 export BASIC_CHANNEL_SOURCE_ID=0 # Incentivized Channel diff --git a/ethereum/contracts/BasicOutboundChannel.sol b/ethereum/contracts/BasicOutboundChannel.sol index ecf016b3b3548..601eff90471e9 100644 --- a/ethereum/contracts/BasicOutboundChannel.sol +++ b/ethereum/contracts/BasicOutboundChannel.sol @@ -11,14 +11,11 @@ contract BasicOutboundChannel is OutboundChannel, ChannelAccess, AccessControl { // Governance contracts will administer using this role. bytes32 public constant CONFIG_UPDATE_ROLE = keccak256("CONFIG_UPDATE_ROLE"); - uint64 public nonce; - - // Only messages originating from this account will - // be allowed through the channel. - address public principal; + mapping(address => uint64) public nonce; event Message( address source, + address account, uint64 nonce, bytes payload ); @@ -30,13 +27,11 @@ contract BasicOutboundChannel is OutboundChannel, ChannelAccess, AccessControl { // Once-off post-construction call to set initial configuration. function initialize( address _configUpdater, - address _principal, address[] memory defaultOperators ) external onlyRole(DEFAULT_ADMIN_ROLE) { // Set initial configuration grantRole(CONFIG_UPDATE_ROLE, _configUpdater); - principal = _principal; for (uint i = 0; i < defaultOperators.length; i++) { _authorizeDefaultOperator(defaultOperators[i]); } @@ -55,29 +50,15 @@ contract BasicOutboundChannel is OutboundChannel, ChannelAccess, AccessControl { _revokeDefaultOperator(operator); } - // Update the principal. - function setPrincipal(address _principal) external onlyRole(CONFIG_UPDATE_ROLE) { - principal = _principal; - } - /** * @dev Sends a message across the channel * - * Submission is a privileged action involving two parties: The operator and the origin. - * Apps (aka operators) need to be authorized by the `origin` to submit messages via this channel. - * - * Furthermore, this channel restricts the origin to a single account, that of the principal. - * In essence this ensures that only the principal account can send messages via this channel. - * - * For pre-production testing, the restriction to the principal account can be bypassed by using - * `setPrincipal` to set the principal to the address 0x0000000000000000000000000000000000000042. + * Submission is a privileged action involving two parties: The operator and the origin (called account here). + * Apps (aka operators) need to be authorized by the `account` to submit messages via this channel. */ - function submit(address _origin, bytes calldata _payload) external override { - require(isOperatorFor(msg.sender, _origin), "Caller is unauthorized"); - if (principal != address(0x0000000000000000000000000000000000000042)) { - require(_origin == principal, "Origin is not an authorized principal"); - } - nonce = nonce + 1; - emit Message(msg.sender, nonce, _payload); + function submit(address _account, bytes calldata _payload) external override { + require(isOperatorFor(msg.sender, _account), "Caller is unauthorized"); + nonce[_account] = nonce[_account] + 1; + emit Message(msg.sender, _account, nonce[_account], _payload); } } diff --git a/ethereum/deploy/20-configure-channels.ts b/ethereum/deploy/20-configure-channels.ts index 06b361962d656..438167c1250f5 100644 --- a/ethereum/deploy/20-configure-channels.ts +++ b/ethereum/deploy/20-configure-channels.ts @@ -7,11 +7,6 @@ module.exports = async ({ }: HardhatRuntimeEnvironment) => { let [deployer] = await getUnnamedAccounts(); - if (!("BASIC_CHANNEL_PRINCIPAL" in process.env)) { - throw "Missing BASIC_CHANNEL_PRINCIPAL in environment config" - } - const principal = process.env.BASIC_CHANNEL_PRINCIPAL - if (!("INCENTIVIZED_CHANNEL_FEE" in process.env)) { throw "Missing INCENTIVIZED_CHANNEL_FEE in environment config" } @@ -41,7 +36,6 @@ module.exports = async ({ }, "initialize", deployer, - principal, [dotApp.address, ethApp.address, erc20App.address], ); diff --git a/ethereum/test/test_basic_outbound_channel.js b/ethereum/test/test_basic_outbound_channel.js index a9404966eaa57..515d89e8f616a 100644 --- a/ethereum/test/test_basic_outbound_channel.js +++ b/ethereum/test/test_basic_outbound_channel.js @@ -1,6 +1,5 @@ const BasicOutboundChannel = artifacts.require("BasicOutboundChannel"); -const Web3Utils = require("web3-utils"); const ethers = require("ethers"); const BigNumber = web3.BigNumber; @@ -26,8 +25,7 @@ describe("BasicOutboundChannel", function () { describe("send", function () { beforeEach(async function () { this.channel = await BasicOutboundChannel.new(); - const principal = "0x0000000000000000000000000000000000000042" - await this.channel.initialize(owner, principal, [appAddress]).should.be.fulfilled; + await this.channel.initialize(owner, [appAddress]).should.be.fulfilled; }); it("should send messages out with the correct event and fields", async function () { @@ -38,9 +36,10 @@ describe("BasicOutboundChannel", function () { ).should.be.fulfilled; const log = tx.receipt.rawLogs[0]; - const event = iface.decodeEventLog('Message(address,uint64,bytes)', log.data, log.topics); + const event = iface.decodeEventLog('Message(address,address,uint64,bytes)', log.data, log.topics); log.address.should.be.equal(this.channel.address); + event.account.should.be.equal(origin) event.source.should.be.equal(appAddress); event.nonce.eq(ethers.BigNumber.from(1)).should.be.true; event.payload.should.be.equal(testPayload) @@ -66,7 +65,7 @@ describe("BasicOutboundChannel", function () { ).should.be.fulfilled; const log = tx3.receipt.rawLogs[0]; - const event = iface.decodeEventLog('Message(address,uint64,bytes)', log.data, log.topics); + const event = iface.decodeEventLog('Message(address,address,uint64,bytes)', log.data, log.topics); event.nonce.eq(ethers.BigNumber.from(3)).should.be.true; }); diff --git a/parachain/README.md b/parachain/README.md index 82622a7c6807c..5008e21394416 100644 --- a/parachain/README.md +++ b/parachain/README.md @@ -65,6 +65,32 @@ For an example configuration, consult the [setup script](/~https://github.com/Snow To run the parachain tests locally, use `cargo test --release`. For the full suite of tests, use `cargo test --release --features runtime-benchmarks`. +### Updating test data for inbound channel unit tests + +To regenerate the test data, use a test with multiple `submit` calls in `ethereum/test/test_{basic,incentivized}_outbound_channel.js`. +For each encoded log you want to create, find a transaction object `tx` returned from a `submit` call, then run this: + +```javascript +const rlp = require("rlp"); +const rawLog = tx.receipt.rawLogs[0]; +const encodedLog = rlp.encode([rawLog.address, rawLog.topics, rawLog.data]).toString("hex"); +console.log(`encodedLog: ${encodedLog}`); +``` + +To decode the event from a `rawLog` to inspect the event data: + +```javascript +const iface = new ethers.utils.Interface(BasicOutboundChannel.abi); +const decodedEventLog = iface.decodeEventLog( + 'Message(address,address,uint64,bytes)', + rawLog.data, + rawLog.topics, +); +console.log(`decoded rawLog.data: ${JSON.stringify(decodedEventLog)}`); +``` + +Set the contract object and event signature based on the log you want to decode. + ## Chain metadata There is an internal tool `snowbridge-query-events` which is used to read specific events from the parachain. It is a used by our offchain message relayers. diff --git a/parachain/pallets/basic-channel/src/inbound/envelope.rs b/parachain/pallets/basic-channel/src/inbound/envelope.rs index b8a6945f6f32e..f77054937c5fe 100644 --- a/parachain/pallets/basic-channel/src/inbound/envelope.rs +++ b/parachain/pallets/basic-channel/src/inbound/envelope.rs @@ -6,8 +6,9 @@ use sp_std::{convert::TryFrom, prelude::*}; // Used to decode a raw Ethereum log into an [`Envelope`]. static EVENT_ABI: &Event = &Event { - signature: "Message(address,uint64,bytes)", + signature: "Message(address,address,uint64,bytes)", inputs: &[ + Param { kind: ParamKind::Address, indexed: false }, Param { kind: ParamKind::Address, indexed: false }, Param { kind: ParamKind::Uint(64), indexed: false }, Param { kind: ParamKind::Bytes, indexed: false }, @@ -22,6 +23,8 @@ pub struct Envelope { pub channel: H160, /// The application on Ethereum where the message originated from. pub source: H160, + /// The account on Ethereum that authorized the source to send the message. + pub account: H160, /// A nonce for enforcing replay protection and ordering. pub nonce: u64, /// The inner payload generated from the source application. @@ -44,8 +47,13 @@ impl TryFrom for Envelope { _ => return Err(EnvelopeDecodeError), }; + let account = match iter.next().ok_or(EnvelopeDecodeError)? { + Token::Address(account) => account, + _ => return Err(EnvelopeDecodeError), + }; + let nonce = match iter.next().ok_or(EnvelopeDecodeError)? { - Token::Uint(value) => value.low_u64(), + Token::Uint(nonce) => nonce.low_u64(), _ => return Err(EnvelopeDecodeError), }; @@ -54,7 +62,7 @@ impl TryFrom for Envelope { _ => return Err(EnvelopeDecodeError), }; - Ok(Self { channel: log.address, source, nonce, payload }) + Ok(Self { channel: log.address, account, source, nonce, payload }) } } @@ -63,17 +71,16 @@ mod tests { use super::*; use hex_literal::hex; - const LOG: [u8; 284] = hex!( + const LOG: [u8; 251] = hex!( " - f901199430d2da52e36f80b17fe2694a5e4900b81cf26344e1a0779b38144a38 - cfc4351816442048b17fe24ba2b0e0c63446b576e8281160b15bb8e000000000 - 0000000000000000abe98e5ef4dc7a5c4f317823986fe48649f0edbb00000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000006000000000 - 000000000000000000000000000000000000000000000000000000541ed28b61 - 269a6d3d28d07b1fd834ebe4e703368ed43593c715fdd31c61141abd04a99fd6 - 822c8558854ccde39a5684e7a56da27d00010000000000000000000000000000 - 00000000000000000000000000000000000000000000000000000000 + f8f99486d9ac0bab011917f57b9e9607833b4340f9d4f8e1a0daab80e8986999 + 7d1cabbe1122788e90fe72b9234ff97a9217dcbb5126f3562fb8c00000000000 + 0000000000000089b4ab1ef20763630df9743acf155865600daff20000000000 + 0000000000000004e00e6d2e9ea1e2af553de02a5172120bfa5c3e0000000000 + 0000000000000000000000000000000000000000000000000000010000000000 + 0000000000000000000000000000000000000000000000000000800000000000 + 0000000000000000000000000000000000000000000000000000206172626974 + 726172792d7061796c6f6164000000000000000000000000000000 " ); @@ -85,14 +92,12 @@ mod tests { assert_eq!( envelope, Envelope { - channel: hex!["30d2da52e36f80b17fe2694a5e4900b81cf26344"].into(), - source: hex!["abe98e5ef4dc7a5c4f317823986fe48649f0edbb"].into(), - nonce: 0, + channel: hex!["86d9ac0bab011917f57b9e9607833b4340f9d4f8"].into(), + source: hex!["89b4ab1ef20763630df9743acf155865600daff2"].into(), + account: hex!["04e00e6d2e9ea1e2af553de02a5172120bfa5c3e"].into(), + nonce: 1, payload: hex!( - " - 1ed28b61269a6d3d28d07b1fd834ebe4e703368ed43593c715fdd31c61141abd - 04a99fd6822c8558854ccde39a5684e7a56da27d000100000000000000000000 - 0000000000000000000000000000000000000000" + "6172626974726172792d7061796c6f6164000000000000000000000000000000" ) .into(), } diff --git a/parachain/pallets/basic-channel/src/inbound/mod.rs b/parachain/pallets/basic-channel/src/inbound/mod.rs index b0a0edba4c022..ab953a161f226 100644 --- a/parachain/pallets/basic-channel/src/inbound/mod.rs +++ b/parachain/pallets/basic-channel/src/inbound/mod.rs @@ -66,7 +66,7 @@ pub mod pallet { pub type SourceChannel = StorageValue<_, H160, ValueQuery>; #[pallet::storage] - pub type Nonce = StorageValue<_, u64, ValueQuery>; + pub type Nonce = StorageMap<_, Twox64Concat, H160, u64, ValueQuery>; #[pallet::storage] pub type LatestVerifiedBlockNumber = StorageValue<_, u64, ValueQuery>; @@ -108,7 +108,7 @@ pub mod pallet { } // Verify message nonce - >::try_mutate(|nonce| -> DispatchResult { + >::try_mutate(envelope.account, |nonce| -> DispatchResult { if envelope.nonce != *nonce + 1 { Err(Error::::InvalidNonce.into()) } else { @@ -117,7 +117,7 @@ pub mod pallet { } })?; - let message_id = MessageId::new(ChannelId::Basic, envelope.nonce); + let message_id = MessageId::Basic { account: envelope.account, nonce: envelope.nonce }; T::MessageDispatch::dispatch(envelope.source, message_id, &envelope.payload); >::set(block_number); diff --git a/parachain/pallets/basic-channel/src/inbound/test.rs b/parachain/pallets/basic-channel/src/inbound/test.rs index e861b156d1a81..82183a16bde10 100644 --- a/parachain/pallets/basic-channel/src/inbound/test.rs +++ b/parachain/pallets/basic-channel/src/inbound/test.rs @@ -20,7 +20,7 @@ use snowbridge_ethereum::{Header as EthereumHeader, Log, U256}; use hex_literal::hex; -use crate::{inbound as basic_inbound_channel, inbound::Error}; +use crate::{inbound as basic_inbound_channel, inbound::Error, inbound::envelope::Envelope}; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -118,8 +118,14 @@ pub fn new_tester_with_config( ext } +fn parse_origin(message: Message) -> H160 { + let (log, _) = MockVerifier::verify(&message).map_err(|err| { println!("mock verify: {:?}", err); err }).unwrap(); + let envelope = Envelope::try_from(log).map_err(|err| { println!("envelope: {:?}", err); err }).unwrap(); + envelope.account +} + // The originating channel address for the messages below -const SOURCE_CHANNEL_ADDR: [u8; 20] = hex!["2d02f2234d0B6e35D8d8fD77705f535ACe681327"]; +const SOURCE_CHANNEL_ADDR: [u8; 20] = hex!["86d9ac0bab011917f57b9e9607833b4340f9d4f8"]; // Ethereum Log: // address: 0xe4ab635d0bdc5668b3fcb4eaee1dec587998f4af (outbound channel contract) @@ -128,17 +134,16 @@ const SOURCE_CHANNEL_ADDR: [u8; 20] = hex!["2d02f2234d0B6e35D8d8fD77705f535ACe68 // source: 0x8f5acf5f15d4c3d654a759b96bb674a236c8c0f3 (ETH bank contract) // nonce: 1 // payload ... -const MESSAGE_DATA_0: [u8; 284] = hex!( +const MESSAGE_DATA_0: [u8; 251] = hex!( " - f90119942d02f2234d0b6e35d8d8fd77705f535ace681327e1a0779b38144a38 - cfc4351816442048b17fe24ba2b0e0c63446b576e8281160b15bb8e000000000 - 00000000000000000a42cba2b7960a0ce216ade5d6a82574257023d800000000 - 0000000000000000000000000000000000000000000000000000000100000000 - 0000000000000000000000000000000000000000000000000000006000000000 - 000000000000000000000000000000000000000000000000000000570c018213 - dae5f9c236beab905c8305cb159c5fa1aae500d43593c715fdd31c61141abd04 - a99fd6822c8558854ccde39a5684e7a56da27d0000d9e9ac2d78030000000000 - 00000000000000000000000000000000000000000000000000000000 + f8f99486d9ac0bab011917f57b9e9607833b4340f9d4f8e1a0daab80e8986999 + 7d1cabbe1122788e90fe72b9234ff97a9217dcbb5126f3562fb8c00000000000 + 0000000000000089b4ab1ef20763630df9743acf155865600daff20000000000 + 0000000000000004e00e6d2e9ea1e2af553de02a5172120bfa5c3e0000000000 + 0000000000000000000000000000000000000000000000000000010000000000 + 0000000000000000000000000000000000000000000000000000800000000000 + 0000000000000000000000000000000000000000000000000000206172626974 + 726172792d7061796c6f6164000000000000000000000000000000 " ); @@ -149,17 +154,16 @@ const MESSAGE_DATA_0: [u8; 284] = hex!( // source: 0x8f5acf5f15d4c3d654a759b96bb674a236c8c0f3 (ETH bank contract) // nonce: 1 // payload ... -const MESSAGE_DATA_1: [u8; 284] = hex!( +const MESSAGE_DATA_1: [u8; 251] = hex!( " - f90119942d02f2234d0b6e35d8d8fd77705f535ace681327e1a0779b38144a38 - cfc4351816442048b17fe24ba2b0e0c63446b576e8281160b15bb8e000000000 - 00000000000000000a42cba2b7960a0ce216ade5d6a82574257023d800000000 - 0000000000000000000000000000000000000000000000000000000200000000 - 0000000000000000000000000000000000000000000000000000006000000000 - 000000000000000000000000000000000000000000000000000000570c018213 - dae5f9c236beab905c8305cb159c5fa1aae500d43593c715fdd31c61141abd04 - a99fd6822c8558854ccde39a5684e7a56da27d0000d9e9ac2d78030000000000 - 00000000000000000000000000000000000000000000000000000000 + f8f99486d9ac0bab011917f57b9e9607833b4340f9d4f8e1a0daab80e8986999 + 7d1cabbe1122788e90fe72b9234ff97a9217dcbb5126f3562fb8c00000000000 + 0000000000000089b4ab1ef20763630df9743acf155865600daff20000000000 + 0000000000000004e00e6d2e9ea1e2af553de02a5172120bfa5c3e0000000000 + 0000000000000000000000000000000000000000000000000000020000000000 + 0000000000000000000000000000000000000000000000000000800000000000 + 0000000000000000000000000000000000000000000000000000206172626974 + 726172792d7061796c6f6164000000000000000000000000000000 " ); @@ -200,8 +204,10 @@ fn test_submit() { data: Default::default(), }, }; - assert_ok!(BasicInboundChannel::submit(origin.clone(), message_1)); - let nonce: u64 = >::get(); + assert_ok!(BasicInboundChannel::submit(origin.clone(), message_1.clone())); + + let event_origin = parse_origin(message_1); + let nonce: u64 = >::get(event_origin.clone()); assert_eq!(nonce, 1); // Submit message 2 @@ -213,8 +219,10 @@ fn test_submit() { data: Default::default(), }, }; - assert_ok!(BasicInboundChannel::submit(origin.clone(), message_2)); - let nonce: u64 = >::get(); + assert_ok!(BasicInboundChannel::submit(origin.clone(), message_2.clone())); + + let event_origin_2 = parse_origin(message_2); + let nonce: u64 = >::get(event_origin_2.clone()); assert_eq!(nonce, 2); }); } @@ -235,7 +243,9 @@ fn test_submit_with_invalid_nonce() { }, }; assert_ok!(BasicInboundChannel::submit(origin.clone(), message.clone())); - let nonce: u64 = >::get(); + + let event_origin = parse_origin(message.clone()); + let nonce: u64 = >::get(event_origin); assert_eq!(nonce, 1); // Submit the same again diff --git a/parachain/pallets/incentivized-channel/src/inbound/mod.rs b/parachain/pallets/incentivized-channel/src/inbound/mod.rs index d0186ad2f85b1..a1384b3810ace 100644 --- a/parachain/pallets/incentivized-channel/src/inbound/mod.rs +++ b/parachain/pallets/incentivized-channel/src/inbound/mod.rs @@ -152,7 +152,7 @@ pub mod pallet { Self::handle_fee(envelope.fee, &relayer); - let message_id = MessageId::new(ChannelId::Incentivized, envelope.nonce); + let message_id = MessageId::Incentivized { nonce: envelope.nonce }; T::MessageDispatch::dispatch(envelope.source, message_id, &envelope.payload); >::set(block_number); diff --git a/parachain/primitives/core/src/types.rs b/parachain/primitives/core/src/types.rs index 28af2976928ae..321a63438a8ec 100644 --- a/parachain/primitives/core/src/types.rs +++ b/parachain/primitives/core/src/types.rs @@ -3,20 +3,14 @@ use codec::{Decode, Encode}; use enum_iterator::IntoEnumIterator; use frame_support::{scale_info::TypeInfo, RuntimeDebug}; -use sp_core::H256; +use sp_core::{H160, H256}; use sp_runtime::DigestItem; use sp_std::vec::Vec; #[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub struct MessageId { - pub channel_id: ChannelId, - pub nonce: u64, -} - -impl MessageId { - pub fn new(channel_id: ChannelId, nonce: u64) -> Self { - Self { channel_id, nonce } - } +pub enum MessageId { + Basic { account: H160, nonce: u64 }, + Incentivized { nonce: u64 }, } pub type MessageNonce = u64; @@ -30,7 +24,7 @@ pub enum ChannelId { /// A message relayed from Ethereum. #[derive(PartialEq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct Message { - /// The raw message data. + /// The raw RLP-encoded message data. pub data: Vec, /// Input to the message verifier pub proof: Proof, diff --git a/relayer/chain/chain.go b/relayer/chain/chain.go index c9eef32fe88ad..140c8778281ef 100644 --- a/relayer/chain/chain.go +++ b/relayer/chain/chain.go @@ -3,13 +3,16 @@ package chain +import "github.com/ethereum/go-ethereum/common" + type Message interface{} // Message from ethereum type EthereumOutboundMessage struct { - Call string - Args []interface{} - Nonce uint64 + Call string + Args []interface{} + Origin common.Address + Nonce uint64 } type Header struct { diff --git a/relayer/contracts/basic/outbound.go b/relayer/contracts/basic/outbound.go index 21c052fcf8db9..b865ea6e44f58 100644 --- a/relayer/contracts/basic/outbound.go +++ b/relayer/contracts/basic/outbound.go @@ -30,7 +30,7 @@ var ( // BasicOutboundChannelMetaData contains all meta data concerning the BasicOutboundChannel contract. var BasicOutboundChannelMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"Message\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"OperatorAuthorized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"OperatorRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CONFIG_UPDATE_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"authorizeDefaultOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"authorizeOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_configUpdater\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_principal\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"defaultOperators\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_origin\",\"type\":\"address\"}],\"name\":\"isOperatorFor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"principal\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"revokeDefaultOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"revokeOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_principal\",\"type\":\"address\"}],\"name\":\"setPrincipal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_origin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_payload\",\"type\":\"bytes\"}],\"name\":\"submit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"Message\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"OperatorAuthorized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"OperatorRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CONFIG_UPDATE_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"authorizeDefaultOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"authorizeOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_configUpdater\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"defaultOperators\",\"type\":\"address[]\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_operator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_origin\",\"type\":\"address\"}],\"name\":\"isOperatorFor\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"revokeDefaultOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"revokeOperator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_payload\",\"type\":\"bytes\"}],\"name\":\"submit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } // BasicOutboundChannelABI is the input ABI used to generate the binding from. @@ -334,12 +334,12 @@ func (_BasicOutboundChannel *BasicOutboundChannelCallerSession) IsOperatorFor(_o return _BasicOutboundChannel.Contract.IsOperatorFor(&_BasicOutboundChannel.CallOpts, _operator, _origin) } -// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// Nonce is a free data retrieval call binding the contract method 0x70ae92d2. // -// Solidity: function nonce() view returns(uint64) -func (_BasicOutboundChannel *BasicOutboundChannelCaller) Nonce(opts *bind.CallOpts) (uint64, error) { +// Solidity: function nonce(address ) view returns(uint64) +func (_BasicOutboundChannel *BasicOutboundChannelCaller) Nonce(opts *bind.CallOpts, arg0 common.Address) (uint64, error) { var out []interface{} - err := _BasicOutboundChannel.contract.Call(opts, &out, "nonce") + err := _BasicOutboundChannel.contract.Call(opts, &out, "nonce", arg0) if err != nil { return *new(uint64), err @@ -351,49 +351,18 @@ func (_BasicOutboundChannel *BasicOutboundChannelCaller) Nonce(opts *bind.CallOp } -// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// Nonce is a free data retrieval call binding the contract method 0x70ae92d2. // -// Solidity: function nonce() view returns(uint64) -func (_BasicOutboundChannel *BasicOutboundChannelSession) Nonce() (uint64, error) { - return _BasicOutboundChannel.Contract.Nonce(&_BasicOutboundChannel.CallOpts) +// Solidity: function nonce(address ) view returns(uint64) +func (_BasicOutboundChannel *BasicOutboundChannelSession) Nonce(arg0 common.Address) (uint64, error) { + return _BasicOutboundChannel.Contract.Nonce(&_BasicOutboundChannel.CallOpts, arg0) } -// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// Nonce is a free data retrieval call binding the contract method 0x70ae92d2. // -// Solidity: function nonce() view returns(uint64) -func (_BasicOutboundChannel *BasicOutboundChannelCallerSession) Nonce() (uint64, error) { - return _BasicOutboundChannel.Contract.Nonce(&_BasicOutboundChannel.CallOpts) -} - -// Principal is a free data retrieval call binding the contract method 0xba5d3078. -// -// Solidity: function principal() view returns(address) -func (_BasicOutboundChannel *BasicOutboundChannelCaller) Principal(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _BasicOutboundChannel.contract.Call(opts, &out, "principal") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// Principal is a free data retrieval call binding the contract method 0xba5d3078. -// -// Solidity: function principal() view returns(address) -func (_BasicOutboundChannel *BasicOutboundChannelSession) Principal() (common.Address, error) { - return _BasicOutboundChannel.Contract.Principal(&_BasicOutboundChannel.CallOpts) -} - -// Principal is a free data retrieval call binding the contract method 0xba5d3078. -// -// Solidity: function principal() view returns(address) -func (_BasicOutboundChannel *BasicOutboundChannelCallerSession) Principal() (common.Address, error) { - return _BasicOutboundChannel.Contract.Principal(&_BasicOutboundChannel.CallOpts) +// Solidity: function nonce(address ) view returns(uint64) +func (_BasicOutboundChannel *BasicOutboundChannelCallerSession) Nonce(arg0 common.Address) (uint64, error) { + return _BasicOutboundChannel.Contract.Nonce(&_BasicOutboundChannel.CallOpts, arg0) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. @@ -490,25 +459,25 @@ func (_BasicOutboundChannel *BasicOutboundChannelTransactorSession) GrantRole(ro return _BasicOutboundChannel.Contract.GrantRole(&_BasicOutboundChannel.TransactOpts, role, account) } -// Initialize is a paid mutator transaction binding the contract method 0x77a24f36. +// Initialize is a paid mutator transaction binding the contract method 0x946d9204. // -// Solidity: function initialize(address _configUpdater, address _principal, address[] defaultOperators) returns() -func (_BasicOutboundChannel *BasicOutboundChannelTransactor) Initialize(opts *bind.TransactOpts, _configUpdater common.Address, _principal common.Address, defaultOperators []common.Address) (*types.Transaction, error) { - return _BasicOutboundChannel.contract.Transact(opts, "initialize", _configUpdater, _principal, defaultOperators) +// Solidity: function initialize(address _configUpdater, address[] defaultOperators) returns() +func (_BasicOutboundChannel *BasicOutboundChannelTransactor) Initialize(opts *bind.TransactOpts, _configUpdater common.Address, defaultOperators []common.Address) (*types.Transaction, error) { + return _BasicOutboundChannel.contract.Transact(opts, "initialize", _configUpdater, defaultOperators) } -// Initialize is a paid mutator transaction binding the contract method 0x77a24f36. +// Initialize is a paid mutator transaction binding the contract method 0x946d9204. // -// Solidity: function initialize(address _configUpdater, address _principal, address[] defaultOperators) returns() -func (_BasicOutboundChannel *BasicOutboundChannelSession) Initialize(_configUpdater common.Address, _principal common.Address, defaultOperators []common.Address) (*types.Transaction, error) { - return _BasicOutboundChannel.Contract.Initialize(&_BasicOutboundChannel.TransactOpts, _configUpdater, _principal, defaultOperators) +// Solidity: function initialize(address _configUpdater, address[] defaultOperators) returns() +func (_BasicOutboundChannel *BasicOutboundChannelSession) Initialize(_configUpdater common.Address, defaultOperators []common.Address) (*types.Transaction, error) { + return _BasicOutboundChannel.Contract.Initialize(&_BasicOutboundChannel.TransactOpts, _configUpdater, defaultOperators) } -// Initialize is a paid mutator transaction binding the contract method 0x77a24f36. +// Initialize is a paid mutator transaction binding the contract method 0x946d9204. // -// Solidity: function initialize(address _configUpdater, address _principal, address[] defaultOperators) returns() -func (_BasicOutboundChannel *BasicOutboundChannelTransactorSession) Initialize(_configUpdater common.Address, _principal common.Address, defaultOperators []common.Address) (*types.Transaction, error) { - return _BasicOutboundChannel.Contract.Initialize(&_BasicOutboundChannel.TransactOpts, _configUpdater, _principal, defaultOperators) +// Solidity: function initialize(address _configUpdater, address[] defaultOperators) returns() +func (_BasicOutboundChannel *BasicOutboundChannelTransactorSession) Initialize(_configUpdater common.Address, defaultOperators []common.Address) (*types.Transaction, error) { + return _BasicOutboundChannel.Contract.Initialize(&_BasicOutboundChannel.TransactOpts, _configUpdater, defaultOperators) } // RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. @@ -595,46 +564,25 @@ func (_BasicOutboundChannel *BasicOutboundChannelTransactorSession) RevokeRole(r return _BasicOutboundChannel.Contract.RevokeRole(&_BasicOutboundChannel.TransactOpts, role, account) } -// SetPrincipal is a paid mutator transaction binding the contract method 0x847fd5bf. -// -// Solidity: function setPrincipal(address _principal) returns() -func (_BasicOutboundChannel *BasicOutboundChannelTransactor) SetPrincipal(opts *bind.TransactOpts, _principal common.Address) (*types.Transaction, error) { - return _BasicOutboundChannel.contract.Transact(opts, "setPrincipal", _principal) -} - -// SetPrincipal is a paid mutator transaction binding the contract method 0x847fd5bf. -// -// Solidity: function setPrincipal(address _principal) returns() -func (_BasicOutboundChannel *BasicOutboundChannelSession) SetPrincipal(_principal common.Address) (*types.Transaction, error) { - return _BasicOutboundChannel.Contract.SetPrincipal(&_BasicOutboundChannel.TransactOpts, _principal) -} - -// SetPrincipal is a paid mutator transaction binding the contract method 0x847fd5bf. -// -// Solidity: function setPrincipal(address _principal) returns() -func (_BasicOutboundChannel *BasicOutboundChannelTransactorSession) SetPrincipal(_principal common.Address) (*types.Transaction, error) { - return _BasicOutboundChannel.Contract.SetPrincipal(&_BasicOutboundChannel.TransactOpts, _principal) -} - // Submit is a paid mutator transaction binding the contract method 0x76846edd. // -// Solidity: function submit(address _origin, bytes _payload) returns() -func (_BasicOutboundChannel *BasicOutboundChannelTransactor) Submit(opts *bind.TransactOpts, _origin common.Address, _payload []byte) (*types.Transaction, error) { - return _BasicOutboundChannel.contract.Transact(opts, "submit", _origin, _payload) +// Solidity: function submit(address _account, bytes _payload) returns() +func (_BasicOutboundChannel *BasicOutboundChannelTransactor) Submit(opts *bind.TransactOpts, _account common.Address, _payload []byte) (*types.Transaction, error) { + return _BasicOutboundChannel.contract.Transact(opts, "submit", _account, _payload) } // Submit is a paid mutator transaction binding the contract method 0x76846edd. // -// Solidity: function submit(address _origin, bytes _payload) returns() -func (_BasicOutboundChannel *BasicOutboundChannelSession) Submit(_origin common.Address, _payload []byte) (*types.Transaction, error) { - return _BasicOutboundChannel.Contract.Submit(&_BasicOutboundChannel.TransactOpts, _origin, _payload) +// Solidity: function submit(address _account, bytes _payload) returns() +func (_BasicOutboundChannel *BasicOutboundChannelSession) Submit(_account common.Address, _payload []byte) (*types.Transaction, error) { + return _BasicOutboundChannel.Contract.Submit(&_BasicOutboundChannel.TransactOpts, _account, _payload) } // Submit is a paid mutator transaction binding the contract method 0x76846edd. // -// Solidity: function submit(address _origin, bytes _payload) returns() -func (_BasicOutboundChannel *BasicOutboundChannelTransactorSession) Submit(_origin common.Address, _payload []byte) (*types.Transaction, error) { - return _BasicOutboundChannel.Contract.Submit(&_BasicOutboundChannel.TransactOpts, _origin, _payload) +// Solidity: function submit(address _account, bytes _payload) returns() +func (_BasicOutboundChannel *BasicOutboundChannelTransactorSession) Submit(_account common.Address, _payload []byte) (*types.Transaction, error) { + return _BasicOutboundChannel.Contract.Submit(&_BasicOutboundChannel.TransactOpts, _account, _payload) } // BasicOutboundChannelMessageIterator is returned from FilterMessage and is used to iterate over the raw logs and unpacked data for Message events raised by the BasicOutboundChannel contract. @@ -707,14 +655,15 @@ func (it *BasicOutboundChannelMessageIterator) Close() error { // BasicOutboundChannelMessage represents a Message event raised by the BasicOutboundChannel contract. type BasicOutboundChannelMessage struct { Source common.Address + Account common.Address Nonce uint64 Payload []byte Raw types.Log // Blockchain specific contextual infos } -// FilterMessage is a free log retrieval operation binding the contract event 0x779b38144a38cfc4351816442048b17fe24ba2b0e0c63446b576e8281160b15b. +// FilterMessage is a free log retrieval operation binding the contract event 0xdaab80e89869997d1cabbe1122788e90fe72b9234ff97a9217dcbb5126f3562f. // -// Solidity: event Message(address source, uint64 nonce, bytes payload) +// Solidity: event Message(address source, address account, uint64 nonce, bytes payload) func (_BasicOutboundChannel *BasicOutboundChannelFilterer) FilterMessage(opts *bind.FilterOpts) (*BasicOutboundChannelMessageIterator, error) { logs, sub, err := _BasicOutboundChannel.contract.FilterLogs(opts, "Message") @@ -724,9 +673,9 @@ func (_BasicOutboundChannel *BasicOutboundChannelFilterer) FilterMessage(opts *b return &BasicOutboundChannelMessageIterator{contract: _BasicOutboundChannel.contract, event: "Message", logs: logs, sub: sub}, nil } -// WatchMessage is a free log subscription operation binding the contract event 0x779b38144a38cfc4351816442048b17fe24ba2b0e0c63446b576e8281160b15b. +// WatchMessage is a free log subscription operation binding the contract event 0xdaab80e89869997d1cabbe1122788e90fe72b9234ff97a9217dcbb5126f3562f. // -// Solidity: event Message(address source, uint64 nonce, bytes payload) +// Solidity: event Message(address source, address account, uint64 nonce, bytes payload) func (_BasicOutboundChannel *BasicOutboundChannelFilterer) WatchMessage(opts *bind.WatchOpts, sink chan<- *BasicOutboundChannelMessage) (event.Subscription, error) { logs, sub, err := _BasicOutboundChannel.contract.WatchLogs(opts, "Message") @@ -761,9 +710,9 @@ func (_BasicOutboundChannel *BasicOutboundChannelFilterer) WatchMessage(opts *bi }), nil } -// ParseMessage is a log parse operation binding the contract event 0x779b38144a38cfc4351816442048b17fe24ba2b0e0c63446b576e8281160b15b. +// ParseMessage is a log parse operation binding the contract event 0xdaab80e89869997d1cabbe1122788e90fe72b9234ff97a9217dcbb5126f3562f. // -// Solidity: event Message(address source, uint64 nonce, bytes payload) +// Solidity: event Message(address source, address account, uint64 nonce, bytes payload) func (_BasicOutboundChannel *BasicOutboundChannelFilterer) ParseMessage(log types.Log) (*BasicOutboundChannelMessage, error) { event := new(BasicOutboundChannelMessage) if err := _BasicOutboundChannel.contract.UnpackLog(event, "Message", log); err != nil { diff --git a/relayer/relays/beacon/config/config.go b/relayer/relays/beacon/config/config.go index 8b28633064209..98419ad84d141 100644 --- a/relayer/relays/beacon/config/config.go +++ b/relayer/relays/beacon/config/config.go @@ -1,6 +1,11 @@ package config -import "github.com/snowfork/snowbridge/relayer/config" +import ( + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/snowfork/snowbridge/relayer/config" +) type Config struct { Source SourceConfig `mapstructure:"source"` @@ -18,9 +23,22 @@ type Spec struct { } type SourceConfig struct { - Beacon BeaconConfig `mapstructure:"beacon"` - Ethereum config.EthereumConfig `mapstructure:"ethereum"` - Contracts ContractsConfig `mapstructure:"contracts"` + Beacon BeaconConfig `mapstructure:"beacon"` + Ethereum config.EthereumConfig `mapstructure:"ethereum"` + Contracts ContractsConfig `mapstructure:"contracts"` + BasicChannelAddresses []string `mapstructure:"basicChannelAddresses"` +} + +func (c *SourceConfig) GetBasicChannelAddresses() ([]common.Address, error) { + var addresses []common.Address + + for _, address := range c.BasicChannelAddresses { + trimmedAddress := strings.TrimPrefix(address, "0x") + + addresses = append(addresses, common.HexToAddress(trimmedAddress)) + } + + return addresses, nil } type ContractsConfig struct { diff --git a/relayer/relays/beacon/message/ethereum-listener.go b/relayer/relays/beacon/message/ethereum-listener.go index 4b86dbf110265..86b511447cbe2 100644 --- a/relayer/relays/beacon/message/ethereum-listener.go +++ b/relayer/relays/beacon/message/ethereum-listener.go @@ -13,7 +13,6 @@ import ( "github.com/snowfork/snowbridge/relayer/contracts/basic" "github.com/snowfork/snowbridge/relayer/contracts/incentivized" "github.com/snowfork/snowbridge/relayer/relays/beacon/config" - "github.com/snowfork/snowbridge/relayer/relays/ethereum/syncer" "golang.org/x/sync/errgroup" ) @@ -22,8 +21,9 @@ type ParachainPayload struct { } type EventContainer struct { - Event *etypes.Log - Nonce uint64 + Event *etypes.Log + Origin common.Address + Nonce uint64 } type EthereumListener struct { @@ -32,7 +32,6 @@ type EthereumListener struct { basicOutboundChannel *basic.BasicOutboundChannel incentivizedOutboundChannel *incentivized.IncentivizedOutboundChannel mapping map[common.Address]string - headerSyncer *syncer.Syncer headerCache *ethereum.HeaderCache } @@ -46,7 +45,6 @@ func NewEthereumListener( basicOutboundChannel: nil, incentivizedOutboundChannel: nil, mapping: make(map[common.Address]string), - headerSyncer: nil, } } @@ -88,9 +86,10 @@ func (li *EthereumListener) ProcessBasicEvents( ctx context.Context, start uint64, end uint64, + addressNonceMap map[common.Address]uint64, ) (ParachainPayload, error) { filterOptions := bind.FilterOpts{Start: start, End: &end, Context: ctx} - basicEvents, err := li.queryBasicEvents(li.basicOutboundChannel, &filterOptions) + basicEvents, err := li.queryBasicEvents(li.basicOutboundChannel, addressNonceMap, &filterOptions) if err != nil { return ParachainPayload{}, err } @@ -123,7 +122,7 @@ func (li *EthereumListener) ProcessIncentivizedEvents( return ParachainPayload{Messages: messages}, nil } -func (li *EthereumListener) queryBasicEvents(contract *basic.BasicOutboundChannel, options *bind.FilterOpts) ([]EventContainer, error) { +func (li *EthereumListener) queryBasicEvents(contract *basic.BasicOutboundChannel, addressNonceMap map[common.Address]uint64, options *bind.FilterOpts) ([]EventContainer, error) { var events []EventContainer iter, err := contract.FilterMessage(options) @@ -140,10 +139,14 @@ func (li *EthereumListener) queryBasicEvents(contract *basic.BasicOutboundChanne } break } - events = append(events, EventContainer{ - Event: &iter.Event.Raw, - Nonce: iter.Event.Nonce, - }) + + if addressNonceMap[iter.Event.Account] != 0 { + events = append(events, EventContainer{ + Event: &iter.Event.Raw, + Origin: iter.Event.Account, + Nonce: iter.Event.Nonce, + }) + } } return events, nil } @@ -202,6 +205,7 @@ func (li *EthereumListener) makeOutgoingMessages( return nil, err } + msg.Origin = eventContainer.Origin msg.Nonce = eventContainer.Nonce messages[i] = msg diff --git a/relayer/relays/beacon/message/message.go b/relayer/relays/beacon/message/message.go index 0bf3df1c096d4..1093daeb3b7c3 100644 --- a/relayer/relays/beacon/message/message.go +++ b/relayer/relays/beacon/message/message.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/ethereum/go-ethereum/common" log "github.com/sirupsen/logrus" "github.com/snowfork/snowbridge/relayer/chain" "github.com/snowfork/snowbridge/relayer/chain/ethereum" @@ -13,22 +14,28 @@ import ( ) type Message struct { - writer *writer.ParachainWriter - listener *EthereumListener + writer *writer.ParachainWriter + listener *EthereumListener + addresses []common.Address } func New(ctx context.Context, eg *errgroup.Group, writer *writer.ParachainWriter, configSource *config.SourceConfig, ethconn *ethereum.Connection) (*Message, error) { + addresses, err := configSource.GetBasicChannelAddresses() + if err != nil { + return nil, err + } + listener := NewEthereumListener( configSource, ethconn, ) - err := listener.Start(ctx, eg) + err = listener.Start(ctx, eg) if err != nil { return &Message{}, err } - return &Message{writer, listener}, nil + return &Message{writer, listener, addresses}, nil } func (m *Message) SyncBasic(ctx context.Context, eg *errgroup.Group, blockNumber <-chan uint64) error { @@ -37,31 +44,36 @@ func (m *Message) SyncBasic(ctx context.Context, eg *errgroup.Group, blockNumber return fmt.Errorf("fetch last basic channel message block number") } - nonce, err := m.writer.GetLastBasicChannelNonce() + addressNonceMap, err := m.writer.GetLastBasicChannelNoncesByAddresses(m.addresses) if err != nil { return fmt.Errorf("fetch last basic channel message nonce") } - log.WithFields(log.Fields{ - "block_number": lastVerifiedBlockNumber, - "nonce": nonce, - }).Info("last basic channel") + addressNonzeroNonceMap := make(map[common.Address]uint64, len(addressNonceMap)) + for address, nonce := range addressNonceMap { + log.WithFields(log.Fields{ + "block_number": lastVerifiedBlockNumber, + "address": address, + "nonce": nonce, + }).Info("last basic channel") + + if nonce != 0 { + addressNonzeroNonceMap[address] = nonce + } + } // If the last nonce is set, there could be messages that have not been processed in the same block. // Messages that have already been verified will not be reprocessed because they will be filtered out - // in filterMessagesByLastNonce. + // in filterMessagesByLastNonces. // Messages after the lastVerifiedBlockNumber will be processed normally in the go routine below. - if nonce != 0 { + if len(addressNonzeroNonceMap) != 0 { log.Info("processing basic block events for last verified block") - basicPayload, err := m.listener.ProcessBasicEvents(ctx, lastVerifiedBlockNumber, lastVerifiedBlockNumber) + basicPayload, err := m.listener.ProcessBasicEvents(ctx, lastVerifiedBlockNumber, lastVerifiedBlockNumber, addressNonzeroNonceMap) if err != nil { return err } - basicPayload.Messages = filterMessagesByLastNonce(basicPayload.Messages, nonce) - // Reset the nonce so that the next block processing range will exclude the block that was synced, - // and start syncing from the next block instead - nonce = 0 + basicPayload.Messages = filterMessagesByLastNonces(basicPayload.Messages, addressNonzeroNonceMap) err = m.writeMessages(ctx, basicPayload) if err != nil { @@ -69,6 +81,11 @@ func (m *Message) SyncBasic(ctx context.Context, eg *errgroup.Group, blockNumber } } + addressNonceMap = make(map[common.Address]uint64, len(m.addresses)) + for _, address := range m.addresses { + addressNonceMap[address] = 1 + } + eg.Go(func() error { for { select { @@ -91,7 +108,7 @@ func (m *Message) SyncBasic(ctx context.Context, eg *errgroup.Group, blockNumber "start": lastVerifiedBlockNumber, "end": blockNumber, }).Info("fetching basic channel messages") - basicPayload, err := m.listener.ProcessBasicEvents(ctx, lastVerifiedBlockNumber, blockNumber) + basicPayload, err := m.listener.ProcessBasicEvents(ctx, lastVerifiedBlockNumber, blockNumber, addressNonceMap) if err != nil { return err } @@ -213,3 +230,17 @@ func filterMessagesByLastNonce(messages []*chain.EthereumOutboundMessage, nonce return resultMessages } + +func filterMessagesByLastNonces(messages []*chain.EthereumOutboundMessage, addressNonceMap map[common.Address]uint64) []*chain.EthereumOutboundMessage { + resultMessages := []*chain.EthereumOutboundMessage{} + + for _, basicMessage := range messages { + if basicMessage.Nonce <= addressNonceMap[basicMessage.Origin] { + continue + } + + resultMessages = append(resultMessages, basicMessage) + } + + return resultMessages +} diff --git a/relayer/relays/beacon/writer/parachain-writer.go b/relayer/relays/beacon/writer/parachain-writer.go index 1131cea421b2b..76555bf698e98 100644 --- a/relayer/relays/beacon/writer/parachain-writer.go +++ b/relayer/relays/beacon/writer/parachain-writer.go @@ -246,19 +246,24 @@ func (wr *ParachainWriter) GetLastBasicChannelMessage() (uint64, error) { return uint64(blockNumber), nil } -func (wr *ParachainWriter) GetLastBasicChannelNonce() (uint64, error) { - key, err := types.CreateStorageKey(wr.conn.Metadata(), "BasicInboundChannel", "Nonce", nil, nil) - if err != nil { - return 0, fmt.Errorf("create storage key for last sync committee: %w", err) - } +func (wr *ParachainWriter) GetLastBasicChannelNoncesByAddresses(addresses []common.Address) (map[common.Address]uint64, error) { + addressNonceMap := make(map[common.Address]uint64, len(addresses)) + + for _, address := range addresses { + key, err := types.CreateStorageKey(wr.conn.Metadata(), "BasicOutboundChannel", "Nonces", address[:], nil) + if err != nil { + return addressNonceMap, fmt.Errorf("create storage key for basic channel nonces: %w", err) + } + + var nonce types.U64 + _, err = wr.conn.API().RPC.State.GetStorageLatest(key, &nonce) + if err != nil { + return addressNonceMap, fmt.Errorf("get storage for latest basic channel nonces (err): %w", err) + } - var nonce types.U64 - _, err = wr.conn.API().RPC.State.GetStorageLatest(key, &nonce) - if err != nil { - return 0, fmt.Errorf("get storage for latest synced sync committee period (err): %w", err) } - return uint64(nonce), nil + return addressNonceMap, nil } func (wr *ParachainWriter) GetLastIncentivizedChannelMessage() (uint64, error) { diff --git a/relayer/relays/parachain/beefy-listener.go b/relayer/relays/parachain/beefy-listener.go index 990f4f807b79e..4df37816f3b46 100644 --- a/relayer/relays/parachain/beefy-listener.go +++ b/relayer/relays/parachain/beefy-listener.go @@ -2,10 +2,12 @@ package parachain import ( "context" + "encoding/hex" "errors" "fmt" "math/big" "sort" + "strings" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -334,7 +336,7 @@ func (li *BeefyListener) discoverCatchupTasks( Context: ctx, } - basicNoncesForAccounts := make([]AccountNonces, len(li.accounts)) + basicChannelAccountNoncesToFind := make(map[types.AccountID]uint64, len(li.accounts)) for _, account := range li.accounts { ethBasicNonce, err := basicContract.Nonces(&options, account) if err != nil { @@ -363,9 +365,9 @@ func (li *BeefyListener) discoverCatchupTasks( "account": types.HexEncodeToString(account[:]), }).Info("Checked latest nonce generated by parachain basic channel") - basicNoncesForAccounts = append(basicNoncesForAccounts, AccountNonces{ - account, uint64(paraBasicNonce), ethBasicNonce, - }) + if uint64(paraBasicNonce) > ethBasicNonce { + basicChannelAccountNoncesToFind[account] = ethBasicNonce + 1 + } } ethIncentivizedNonce, err := incentivizedContract.Nonce(&options) @@ -397,13 +399,6 @@ func (li *BeefyListener) discoverCatchupTasks( var scanIncentivizedChannel bool var incentivizedNonceToFind uint64 - basicChannelAccountNoncesToFind := make(map[types.AccountID]uint64, len(li.accounts)) - for _, nonceForAccount := range basicNoncesForAccounts { - if nonceForAccount.paraBasicNonce > nonceForAccount.ethBasicNonce { - basicChannelAccountNoncesToFind[nonceForAccount.account] = nonceForAccount.ethBasicNonce + 1 - } - } - if uint64(paraIncentivizedNonce) > ethIncentivizedNonce { scanIncentivizedChannel = true incentivizedNonceToFind = ethIncentivizedNonce + 1 @@ -559,8 +554,15 @@ func (li *BeefyListener) scanForCommitments( scanIncentivizedChannel bool, incentivizedNonceToFind uint64, ) ([]*Task, error) { + basicChannelAccountNonceString := "map[" + for account, nonce := range basicChannelAccountNonces { + basicChannelAccountNonceString += fmt.Sprintf("%v: %v ", hex.EncodeToString(account[:]), nonce) + } + basicChannelAccountNonceString = strings.Trim(basicChannelAccountNonceString, " ") + basicChannelAccountNonceString += "]" + log.WithFields(log.Fields{ - "basicAccountNonces": fmt.Sprintf("%+v", basicChannelAccountNonces), + "basicAccountNonces": basicChannelAccountNonceString, "incentivizedNonce": incentivizedNonceToFind, "latestblockNumber": lastParaBlockNumber, }).Debug("Searching backwards from latest block on parachain to find block with nonces") diff --git a/relayer/relays/parachain/config.go b/relayer/relays/parachain/config.go index 324de1b848ce2..3c0c23323443b 100644 --- a/relayer/relays/parachain/config.go +++ b/relayer/relays/parachain/config.go @@ -20,13 +20,13 @@ type SourceConfig struct { Contracts SourceContractsConfig `mapstructure:"contracts"` // Block number when Beefy was activated BeefyActivationBlock uint64 `mapstructure:"beefy-activation-block"` - Accounts []string `mapstructure:"accounts"` + BasicChannelAccounts []string `mapstructure:"basicChannelAccounts"` } func (c *SourceConfig) getAccounts() ([][32]byte, error) { var accounts [][32]byte - for _, account := range c.Accounts { + for _, account := range c.BasicChannelAccounts { trimmedAccount := strings.TrimPrefix(account, "0x") accountBytes, err := hex.DecodeString(trimmedAccount) diff --git a/test/.envrc-example b/test/.envrc-example index e0e90b6925c3a..215e5342562e5 100644 --- a/test/.envrc-example +++ b/test/.envrc-example @@ -6,7 +6,6 @@ export DIFFICULTY=0x4fff0 ## Config for Ethereum deployment # Basic Channel -export BASIC_CHANNEL_PRINCIPAL=0x0000000000000000000000000000000000000042 export BASIC_CHANNEL_SOURCE_ID=0 # Incentivized Channel diff --git a/test/README.md b/test/README.md index 54ffe9ea34692..b3187d90ad955 100644 --- a/test/README.md +++ b/test/README.md @@ -27,7 +27,7 @@ The E2E tests run against local deployments of the parachain, relayer, the ether * lodestar - https://chainsafe.github.io/lodestar/install/source/ Use `v1.1.0`. ```bash - yarn global add @chainsafe/lodestar@1.0.0 + yarn global add @chainsafe/lodestar@1.1.0 ``` * sponge - Is available in the `moreutils` package. diff --git a/test/config/beacon-relay.json b/test/config/beacon-relay.json index 0c981de209529..4ec5f89ea7050 100644 --- a/test/config/beacon-relay.json +++ b/test/config/beacon-relay.json @@ -20,7 +20,8 @@ "contracts": { "BasicOutboundChannel": null, "IncentivizedOutboundChannel": null - } + }, + "basicChannelAddresses": [] }, "sink": { "parachain": { diff --git a/test/config/parachain-relay.json b/test/config/parachain-relay.json index 90c09020bd0bf..fcf8aac2552a4 100644 --- a/test/config/parachain-relay.json +++ b/test/config/parachain-relay.json @@ -15,7 +15,7 @@ "IncentivizedInboundChannel": null }, "beefy-activation-block": 0, - "accounts": [] + "basicChannelAccounts": [] }, "sink": { "ethereum": { diff --git a/test/package.json b/test/package.json index 1f5307bde9255..4b8722761a23c 100644 --- a/test/package.json +++ b/test/package.json @@ -4,7 +4,7 @@ "main": "index.js", "license": "MIT", "scripts": { - "test": "mocha --timeout 400000 --exit" + "test": "mocha --timeout 1500000 --exit" }, "devDependencies": { "@polkadot/api": "^8.3.1", diff --git a/test/scripts/start-services.sh b/test/scripts/start-services.sh index cad8ce70aab35..5fcf77cff02fa 100755 --- a/test/scripts/start-services.sh +++ b/test/scripts/start-services.sh @@ -13,10 +13,12 @@ infura_endpoint_ws="${ETH_WS_ENDPOINT:-ws://localhost:8546}/${INFURA_PROJECT_ID: parachain_relay_eth_key="${PARACHAIN_RELAY_ETH_KEY:-0x8013383de6e5a891e7754ae1ef5a21e7661f1fe67cd47ca8ebf4acd6de66879a}" beefy_relay_eth_key="${BEEFY_RELAY_ETH_KEY:-0x935b65c833ced92c43ef9de6bff30703d941bd92a2637cb00cfad389f5862109}" -# Accounts for which the relayer will relay messages over the basic channel. -# Currently only works for messages from Polkadot to Ethereum until SNO-305 is complete. +# Parachain accounts for which the relayer will relay messages over the basic channel. # These IDs are for the test accounts Alice, Bob, Charlie, Dave, Eve and Ferdie, in order -account_ids="${ACCOUNT_IDS:-0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d,0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48,0x90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22,0x306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20,0xe659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e,0x1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c}" +basic_parachain_account_ids="${BASIC_PARACHAIN_ACCOUNT_IDS:-0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d,0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48,0x90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22,0x306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20,0xe659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e,0x1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c}" +# Ethereum addresses for which the relayer will relay messages over the basic channel. +# This address is for the default eth account used in the E2E tests, taken from test/src/ethclient/index.js. +basic_eth_addresses="${BASIC_ETH_ADDRESSES:-0x89b4ab1ef20763630df9743acf155865600daff2}" beacon_endpoint_http="${BEACON_HTTP_ENDPOINT:-http://localhost:9596}" @@ -155,13 +157,13 @@ start_polkadot_launch() echo "Found initial finalized block: $initial_beacon_block" bootstrap_header="" while [ -z "$bootstrap_header" ] || [ "$bootstrap_header" == "" ] || [ "$bootstrap_header" == "null" ] - do + do echo "Waiting for beacon to get initial bootstrap..." bootstrap_header=$(curl -s "$beacon_endpoint_http/eth/v1/beacon/light_client/bootstrap/$initial_beacon_block" \ | jq -r '.data.header') sleep 3 - done - + done + curl -s "$beacon_endpoint_http/eth/v1/beacon/light_client/bootstrap/$initial_beacon_block" \ | node scripts/helpers/transformInitialBeaconSync.js > "$output_dir/initialBeaconSync_tmp.json" @@ -248,7 +250,7 @@ start_relayer() --arg k2 "$(address_for IncentivizedInboundChannel)" \ --arg k3 "$(address_for BeefyClient)" \ --arg infura_endpoint_ws $infura_endpoint_ws \ - --arg account_ids $account_ids \ + --arg basic_parachain_account_ids $basic_parachain_account_ids \ ' .source.contracts.BasicInboundChannel = $k1 | .source.contracts.IncentivizedInboundChannel = $k2 @@ -257,7 +259,7 @@ start_relayer() | .sink.contracts.IncentivizedInboundChannel = $k2 | .source.ethereum.endpoint = $infura_endpoint_ws | .sink.ethereum.endpoint = $infura_endpoint_ws - | .source.accounts = ($account_ids | split(",")) + | .source.basicChannelAccounts = ($basic_parachain_account_ids | split(",")) ' \ config/parachain-relay.json > $output_dir/parachain-relay.json @@ -285,12 +287,14 @@ start_relayer() --arg infura_endpoint_ws $infura_endpoint_ws \ --arg beacon_endpoint_http $beacon_endpoint_http \ --arg active_spec $active_spec \ + --arg basic_eth_addresses $basic_eth_addresses \ ' .source.contracts.BasicOutboundChannel = $k1 | .source.contracts.IncentivizedOutboundChannel = $k2 | .source.ethereum.endpoint = $infura_endpoint_ws | .source.beacon.endpoint = $beacon_endpoint_http | .source.beacon.activeSpec = $active_spec + | .source.basicChannelAddresses = ($basic_eth_addresses | split(",")) ' \ config/beacon-relay.json > $output_dir/beacon-relay.json