From 967b2f040943f97e70c1015b0c5aee758f360656 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Tue, 7 Nov 2023 16:09:14 +0200 Subject: [PATCH 01/14] Add support for message ids --- contracts/src/Assets.sol | 3 +- contracts/src/DeployScript.sol | 15 +- contracts/src/Gateway.sol | 13 +- contracts/src/Types.sol | 2 + contracts/src/interfaces/IGateway.sol | 20 +- contracts/test/Gateway.t.sol | 38 +-- parachain/Cargo.lock | 1 + parachain/pallets/control/src/lib.rs | 15 +- parachain/pallets/control/src/tests.rs | 8 +- .../pallets/ethereum-beacon-client/Cargo.toml | 2 +- parachain/pallets/inbound-queue/Cargo.toml | 6 +- .../pallets/inbound-queue/src/envelope.rs | 34 ++- parachain/pallets/inbound-queue/src/lib.rs | 60 ++--- parachain/pallets/inbound-queue/src/test.rs | 83 +------ .../outbound-queue/src/benchmarking.rs | 2 +- parachain/pallets/outbound-queue/src/lib.rs | 25 +- parachain/pallets/outbound-queue/src/mock.rs | 3 + .../outbound-queue/src/send_message_impl.rs | 38 +-- parachain/pallets/outbound-queue/src/types.rs | 4 + parachain/primitives/core/src/outbound.rs | 11 +- parachain/primitives/ethereum/Cargo.toml | 3 +- .../primitives/router/src/inbound/mod.rs | 1 + .../primitives/router/src/outbound/mod.rs | 46 ++-- polkadot-sdk | 2 +- relayer/contracts/gateway.go | 219 +++++++++++++++--- relayer/relays/execution/main.go | 2 +- relayer/relays/parachain/types.go | 2 + web/packages/test/scripts/set-env.sh | 2 + 28 files changed, 434 insertions(+), 226 deletions(-) diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index ed489fddca..3f04a3ba6e 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -9,7 +9,7 @@ import {SafeTokenTransferFrom} from "./utils/SafeTransfer.sol"; import {AssetsStorage} from "./storage/AssetsStorage.sol"; import {SubstrateTypes} from "./SubstrateTypes.sol"; -import {ParaID, Config} from "./Types.sol"; +import {ParaID, Config, Channel} from "./Types.sol"; import {Address} from "./utils/Address.sol"; /// @title Library for implementing Ethereum->Polkadot ERC20 transfers. @@ -71,6 +71,7 @@ library Assets { payload = SubstrateTypes.SendToken(address(this), token, destinationChain, destinationAddress, amount); extraFee = $.sendTokenFee; + emit IGateway.TokenSent(sender, token, destinationChain, abi.encodePacked(destinationAddress), amount); } diff --git a/contracts/src/DeployScript.sol b/contracts/src/DeployScript.sol index 2efddbe9f9..813a5c3388 100644 --- a/contracts/src/DeployScript.sol +++ b/contracts/src/DeployScript.sol @@ -12,7 +12,7 @@ import {Gateway} from "./Gateway.sol"; import {GatewayUpgradeMock} from "../test/mocks/GatewayUpgradeMock.sol"; import {Agent} from "./Agent.sol"; import {AgentExecutor} from "./AgentExecutor.sol"; -import {ParaID, Config} from "./Types.sol"; +import {ParaID, Config, OperatingMode} from "./Types.sol"; import {SafeNativeTransfer} from "./utils/SafeTransfer.sol"; import {stdJson} from "forge-std/StdJson.sol"; @@ -66,8 +66,19 @@ contract DeployScript is Script { assetHubAgentID ); + bool rejectOutboundMessages = vm.envBool("REJECT_OUTBOUND_MESSAGES"); + OperatingMode defaultOperatingMode; + if (rejectOutboundMessages) { + defaultOperatingMode = OperatingMode.RejectingOutboundMessages; + } else { + defaultOperatingMode = OperatingMode.Normal; + } + bytes memory initParams = abi.encode( - vm.envUint("DEFAULT_FEE"), vm.envUint("REGISTER_NATIVE_TOKEN_FEE"), vm.envUint("SEND_NATIVE_TOKEN_FEE") + defaultOperatingMode, + vm.envUint("DEFAULT_FEE"), + vm.envUint("REGISTER_NATIVE_TOKEN_FEE"), + vm.envUint("SEND_NATIVE_TOKEN_FEE") ); GatewayProxy gateway = new GatewayProxy(address(gatewayLogic), initParams); diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 6609f4d8cc..6ac486fdfe 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -195,7 +195,7 @@ contract Gateway is IGateway, IInitializable { _transferNativeFromAgent(channel.agent, payable(msg.sender), amount); } - emit IGateway.InboundMessageDispatched(message.origin, message.nonce, success); + emit IGateway.InboundMessageDispatched(message.origin, message.nonce, message.id, success); } /** @@ -486,7 +486,10 @@ contract Gateway is IGateway, IInitializable { payable(msg.sender).safeNativeTransfer(msg.value - channel.fee - extraFee); } - emit IGateway.OutboundMessageAccepted(dest, channel.outboundNonce, payload); + // Generate a unique ID for this message + bytes32 messageID = keccak256(abi.encodePacked(dest, channel.outboundNonce)); + + emit IGateway.OutboundMessageAccepted(dest, channel.outboundNonce, messageID, payload); } /// @dev Outbound message can be disabled globally or on a per-channel basis. @@ -543,12 +546,12 @@ contract Gateway is IGateway, IInitializable { revert Unauthorized(); } - (uint256 defaultFee, uint256 registerTokenFee, uint256 sendTokenFee) = - abi.decode(data, (uint256, uint256, uint256)); + (OperatingMode defaultMode, uint256 defaultFee, uint256 registerTokenFee, uint256 sendTokenFee) = + abi.decode(data, (OperatingMode, uint256, uint256, uint256)); CoreStorage.Layout storage $ = CoreStorage.layout(); - $.mode = OperatingMode.RejectingOutboundMessages; + $.mode = defaultMode; $.defaultFee = defaultFee; // Initialize an agent & channel for BridgeHub diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index cb0fae8266..18c5f72ef7 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -45,6 +45,8 @@ struct InboundMessage { uint256 maxRefund; /// @dev The reward for message submission uint256 reward; + /// @dev ID for this message + bytes32 id; } enum OperatingMode { diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index c94b5fc261..aaf8e8ee1e 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -11,10 +11,13 @@ interface IGateway { */ // Emitted when inbound message has been dispatched - event InboundMessageDispatched(ParaID indexed origin, uint64 nonce, bool success); + event InboundMessageDispatched(ParaID indexed origin, uint64 nonce, bytes32 indexed messageID, bool success); // Emitted when an outbound message has been accepted for delivery to a Polkadot parachain - event OutboundMessageAccepted(ParaID indexed destination, uint64 nonce, bytes payload); + event OutboundMessageAccepted(ParaID indexed destination, uint64 nonce, bytes32 indexed messageID, bytes payload); + + // Emitted when an dispatched inbound message or an accepted outbound message are associated with one or more topic IDs + event Topic(bytes32 topicID); // Emitted when an agent has been created for a consensus system on Polkadot event AgentCreated(bytes32 agentID, address agent); @@ -34,12 +37,6 @@ interface IGateway { // Emitted when funds are withdrawn from an agent event AgentFundsWithdrawn(bytes32 indexed agentID, address indexed recipient, uint256 amount); - /// @dev Emitted once the funds are locked and a message is successfully queued. - event TokenSent( - address indexed token, address indexed sender, ParaID destinationChain, bytes destinationAddress, uint128 amount - ); - event TokenRegistrationSent(address token); - /** * Getters */ @@ -66,6 +63,13 @@ interface IGateway { * Token Transfers */ + /// @dev Emitted once the funds are locked and a message is successfully queued. + event TokenSent( + address indexed token, address indexed sender, ParaID destinationChain, bytes destinationAddress, uint128 amount + ); + + event TokenRegistrationSent(address token); + /// @dev Send a message to the AssetHub parachain to register a new fungible asset /// in the `ForeignAssets` pallet. function registerToken(address token) external payable; diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index ba49b37244..c7c622a43f 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -66,6 +66,7 @@ contract GatewayTest is Test { uint256 public maxDispatchGas = 500_000; uint256 public maxRefund = 1 ether; uint256 public reward = 1 ether; + bytes32 public messageID = keccak256("cabbage"); uint256 public baseFee = 1 ether; uint256 public registerNativeTokenFee = 1 ether; @@ -84,6 +85,7 @@ contract GatewayTest is Test { gateway = new GatewayProxy( address(gatewayLogic), abi.encode( + OperatingMode.Normal, baseFee, registerNativeTokenFee, sendNativeTokenFee @@ -156,11 +158,11 @@ contract GatewayTest is Test { // Expect the gateway to emit `InboundMessageDispatched` vm.expectEmit(true, false, false, false); - emit IGateway.InboundMessageDispatched(bridgeHubParaID, 1, true); + emit IGateway.InboundMessageDispatched(bridgeHubParaID, 1, messageID, true); hoax(relayer, 1 ether); IGateway(address(gateway)).submitInbound( - InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward), + InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward, messageID), proof, makeMockProof() ); @@ -173,7 +175,7 @@ contract GatewayTest is Test { hoax(relayer, 1 ether); IGateway(address(gateway)).submitInbound( - InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward), + InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward, messageID), proof, makeMockProof() ); @@ -182,7 +184,7 @@ contract GatewayTest is Test { vm.expectRevert(Gateway.InvalidNonce.selector); hoax(relayer, 1 ether); IGateway(address(gateway)).submitInbound( - InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward), + InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward, messageID), proof, makeMockProof() ); @@ -194,7 +196,9 @@ contract GatewayTest is Test { vm.expectRevert(Gateway.ChannelDoesNotExist.selector); hoax(relayer); IGateway(address(gateway)).submitInbound( - InboundMessage(ParaID.wrap(42), 1, command, "", maxDispatchGas, maxRefund, reward), proof, makeMockProof() + InboundMessage(ParaID.wrap(42), 1, command, "", maxDispatchGas, maxRefund, reward, messageID), + proof, + makeMockProof() ); } @@ -208,7 +212,7 @@ contract GatewayTest is Test { hoax(relayer, 1 ether); IGateway(address(gateway)).submitInbound( - InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward), + InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward, messageID), proof, makeMockProof() ); @@ -231,7 +235,7 @@ contract GatewayTest is Test { uint256 startGas = gasleft(); IGateway(address(gateway)).submitInbound( - InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward), + InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward, messageID), proof, makeMockProof() ); @@ -257,7 +261,7 @@ contract GatewayTest is Test { hoax(relayer, 1 ether); IGateway(address(gateway)).submitInbound( - InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward), + InboundMessage(bridgeHubParaID, 1, command, params, maxDispatchGas, maxRefund, reward, messageID), proof, makeMockProof() ); @@ -535,7 +539,7 @@ contract GatewayTest is Test { emit TokenRegistrationSent(address(token)); vm.expectEmit(true, false, false, false); - emit IGateway.OutboundMessageAccepted(assetHubParaID, 1, SubstrateTypes.RegisterToken(address(token))); + emit IGateway.OutboundMessageAccepted(assetHubParaID, 1, messageID, bytes("")); IGateway(address(gateway)).registerToken{value: 2 ether}(address(token)); } @@ -545,7 +549,7 @@ contract GatewayTest is Test { emit IGateway.TokenRegistrationSent(address(token)); vm.expectEmit(true, false, false, false); - emit IGateway.OutboundMessageAccepted(assetHubParaID, 1, SubstrateTypes.RegisterToken(address(token))); + emit IGateway.OutboundMessageAccepted(assetHubParaID, 1, messageID, bytes("")); uint256 totalFee = baseFee + registerNativeTokenFee; uint256 balanceBefore = address(this).balance; @@ -571,9 +575,7 @@ contract GatewayTest is Test { // Expect the gateway to emit `OutboundMessageAccepted` vm.expectEmit(true, false, false, false); - emit IGateway.OutboundMessageAccepted( - assetHubParaID, 1, SubstrateTypes.SendToken(address(token), destPara, destAddress, 1) - ); + emit IGateway.OutboundMessageAccepted(assetHubParaID, 1, messageID, bytes("")); IGateway(address(gateway)).sendToken{value: 2 ether}(address(token), destPara, destAddress, 1); } @@ -591,9 +593,7 @@ contract GatewayTest is Test { // Expect the gateway to emit `OutboundMessageAccepted` vm.expectEmit(true, false, false, false); - emit IGateway.OutboundMessageAccepted( - assetHubParaID, 1, SubstrateTypes.SendToken(address(token), destAddress, 1) - ); + emit IGateway.OutboundMessageAccepted(assetHubParaID, 1, messageID, bytes("")); IGateway(address(gateway)).sendToken{value: 2 ether}(address(token), destPara, destAddress, 1); } @@ -611,7 +611,7 @@ contract GatewayTest is Test { // Expect the gateway to emit `OutboundMessageAccepted` vm.expectEmit(true, false, false, false); - emit IGateway.OutboundMessageAccepted(assetHubParaID, 1, hex""); + emit IGateway.OutboundMessageAccepted(assetHubParaID, 1, messageID, bytes("")); IGateway(address(gateway)).sendToken{value: 2 ether}(address(token), destPara, destAddress, 1); } @@ -743,10 +743,10 @@ contract GatewayTest is Test { vm.expectEmit(true, false, false, true); // Expect dispatch result as false for `OutOfGas` - emit IGateway.InboundMessageDispatched(bridgeHubParaID, 1, false); + emit IGateway.InboundMessageDispatched(bridgeHubParaID, 1, messageID, false); // maxDispatchGas as 1 for `create_agent` is definitely not enough IGateway(address(gateway)).submitInbound( - InboundMessage(bridgeHubParaID, 1, command, params, 1, maxRefund, reward), proof, makeMockProof() + InboundMessage(bridgeHubParaID, 1, command, params, 1, maxRefund, reward, messageID), proof, makeMockProof() ); } } diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 8732841b3f..c26c95b7e2 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -3241,6 +3241,7 @@ dependencies = [ "frame-support", "frame-system", "hex-literal", + "log", "pallet-balances", "parity-scale-codec", "rlp", diff --git a/parachain/pallets/control/src/lib.rs b/parachain/pallets/control/src/lib.rs index c1946d8cc8..627ec9ac23 100644 --- a/parachain/pallets/control/src/lib.rs +++ b/parachain/pallets/control/src/lib.rs @@ -200,6 +200,10 @@ pub mod pallet { #[pallet::getter(fn channels)] pub type Channels = StorageMap<_, Twox64Concat, ParaId, (), OptionQuery>; + /// Generator for a unique message ID + #[pallet::storage] + pub type NextMessageId = StorageValue<_, u64, ValueQuery>; + #[pallet::call] impl Pallet { /// Sends command to the Gateway contract to upgrade itself with a new implementation @@ -429,7 +433,7 @@ pub mod pallet { impl Pallet { /// Send `command` to the Gateway on the channel identified by `origin`. fn send(origin: ParaId, command: Command, pays_fee: PaysFee) -> DispatchResult { - let message = Message { origin, command }; + let message = Message { id: Self::alloc_message_id(), origin, command }; let (ticket, fee) = T::OutboundQueue::validate(&message).map_err(|err| Error::::Send(err))?; @@ -473,5 +477,14 @@ pub mod pallet { }); Ok(()) } + + // Allocate a unique id for a message. Used in the implementation of SendMessage,. + pub(crate) fn alloc_message_id() -> H256 { + NextMessageId::::mutate(|next_message_id| { + *next_message_id = next_message_id.saturating_add(1) + }); + let next_message_id = NextMessageId::::get(); + sp_io::hashing::blake2_256(&(next_message_id.encode())).into() + } } } diff --git a/parachain/pallets/control/src/tests.rs b/parachain/pallets/control/src/tests.rs index 92548f9ee9..ba8b77f995 100644 --- a/parachain/pallets/control/src/tests.rs +++ b/parachain/pallets/control/src/tests.rs @@ -520,8 +520,11 @@ fn charge_fee_for_create_agent() { assert_ok!(EthereumControl::create_agent(origin.clone())); // assert sovereign_balance decreased by (fee.base_fee + fee.delivery_fee) - let message = - Message { origin: para_id.into(), command: Command::CreateAgent { agent_id } }; + let message = Message { + id: H256::zero(), + origin: para_id.into(), + command: Command::CreateAgent { agent_id }, + }; let (_, fee) = OutboundQueue::validate(&message).unwrap(); let sovereign_balance = Balances::balance(&sovereign_account); assert_eq!(sovereign_balance + fee.local + fee.remote, InitialFunding::get()); @@ -555,6 +558,7 @@ fn charge_fee_for_transfer_native_from_agent() { let sovereign_balance_before = Balances::balance(&sovereign_account); assert_ok!(EthereumControl::transfer_native_from_agent(origin.clone(), recipient, amount)); let message = Message { + id: H256::zero(), origin: para_id.into(), command: Command::TransferNativeFromAgent { agent_id, recipient, amount }, }; diff --git a/parachain/pallets/ethereum-beacon-client/Cargo.toml b/parachain/pallets/ethereum-beacon-client/Cargo.toml index e3a20829cb..f4318a293c 100644 --- a/parachain/pallets/ethereum-beacon-client/Cargo.toml +++ b/parachain/pallets/ethereum-beacon-client/Cargo.toml @@ -18,7 +18,7 @@ scale-info = { version = "2.9.0", default-features = false, features = [ "derive ssz_rs = { version="0.9.0", default-features = false } ssz_rs_derive = { version="0.9.0", default-features = false } byte-slice-cast = { version = "1.2.1", default-features = false } -rlp = { version = "0.5", default-features = false } +rlp = { version = "0.5.2", default-features = false } hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.20", default-features = false } diff --git a/parachain/pallets/inbound-queue/Cargo.toml b/parachain/pallets/inbound-queue/Cargo.toml index 0f3da50660..226b127e42 100644 --- a/parachain/pallets/inbound-queue/Cargo.toml +++ b/parachain/pallets/inbound-queue/Cargo.toml @@ -14,7 +14,8 @@ serde = { version = "1.0.188", optional = true } codec = { version = "3.6.1", package = "parity-scale-codec", default-features = false, features = [ "derive" ] } scale-info = { version = "2.9.0", default-features = false, features = [ "derive" ] } hex-literal = { version = "0.4.1", optional = true } -rlp = { version = "0.5", default-features = false, optional = true } +rlp = { version = "0.5.2", default-features = false, optional = true } +log = { version = "0.4.20", default-features = false } frame-benchmarking = { path = "../../../polkadot-sdk/substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../polkadot-sdk/substrate/frame/support", default-features = false } @@ -41,12 +42,13 @@ snowbridge-beacon-primitives = { path = "../../primitives/beacon" } snowbridge-ethereum-beacon-client = { path = "../../pallets/ethereum-beacon-client" } hex-literal = { version = "0.4.1" } -rlp = { version = "0.5" } +rlp = { version = "0.5.2" } [features] default = ["std"] std = [ "serde", + "log/std", "codec/std", "scale-info/std", "frame-support/std", diff --git a/parachain/pallets/inbound-queue/src/envelope.rs b/parachain/pallets/inbound-queue/src/envelope.rs index 3ce9dfd71d..0462faa2f0 100644 --- a/parachain/pallets/inbound-queue/src/envelope.rs +++ b/parachain/pallets/inbound-queue/src/envelope.rs @@ -4,15 +4,16 @@ use ethabi::{Event, Param, ParamKind, Token}; use snowbridge_core::ParaId; use snowbridge_ethereum::{log::Log, H160}; -use sp_core::RuntimeDebug; +use sp_core::{RuntimeDebug, H256}; use sp_std::{convert::TryFrom, prelude::*}; // Used to decode an OutboundMessageAccepted log into an [`Envelope`]. static EVENT_ABI: &Event = &Event { - signature: "OutboundMessageAccepted(uint256,uint64,bytes)", + signature: "OutboundMessageAccepted(uint256,uint64,bytes32,bytes)", inputs: &[ Param { kind: ParamKind::Uint(256), indexed: true }, Param { kind: ParamKind::Uint(64), indexed: false }, + Param { kind: ParamKind::FixedBytes(32), indexed: true }, Param { kind: ParamKind::Bytes, indexed: false }, ], anonymous: false, @@ -27,10 +28,14 @@ pub struct Envelope { pub dest: ParaId, /// A nonce for enforcing replay protection and ordering. pub nonce: u64, + /// An id for tracing the message on its route (has no role in bridge consensus) + pub message_id: H256, /// The inner payload generated from the source application. pub payload: Vec, } +use log; + #[derive(Copy, Clone, PartialEq, Eq, RuntimeDebug)] pub struct EnvelopeDecodeError; @@ -38,8 +43,12 @@ impl TryFrom for Envelope { type Error = EnvelopeDecodeError; fn try_from(log: Log) -> Result { + log::info!(target: "snowbridge-inbound-queue", "FOO -2"); + let tokens = EVENT_ABI.decode(log.topics, log.data).map_err(|_| EnvelopeDecodeError)?; + log::info!(target: "snowbridge-inbound-queue", "FOO -1"); + let mut iter = tokens.into_iter(); let dest = match iter.next().ok_or(EnvelopeDecodeError)? { @@ -47,16 +56,35 @@ impl TryFrom for Envelope { _ => return Err(EnvelopeDecodeError), }; + log::info!(target: "snowbridge-inbound-queue", "FOO 0"); + let nonce = match iter.next().ok_or(EnvelopeDecodeError)? { Token::Uint(nonce) => nonce.low_u64(), _ => return Err(EnvelopeDecodeError), }; + log::info!(target: "snowbridge-inbound-queue", "FOO 1"); + + let message_id = match iter.next().ok_or(EnvelopeDecodeError)? { + Token::FixedBytes(message_id) => { + log::info!(target: "snowbridge-inbound-queue", "FOO 2"); + let message_id: [u8; 32] = + message_id.try_into().map_err(|_| EnvelopeDecodeError)?; + log::info!(target: "snowbridge-inbound-queue", "FOO 3"); + H256::from(&message_id) + }, + _ => return Err(EnvelopeDecodeError), + }; + + log::info!(target: "snowbridge-inbound-queue", "FOO 4"); + let payload = match iter.next().ok_or(EnvelopeDecodeError)? { Token::Bytes(payload) => payload, _ => return Err(EnvelopeDecodeError), }; - Ok(Self { gateway: log.address, dest, nonce, payload }) + log::info!(target: "snowbridge-inbound-queue", "FOO 5"); + + Ok(Self { gateway: log.address, dest, nonce, message_id, payload }) } } diff --git a/parachain/pallets/inbound-queue/src/lib.rs b/parachain/pallets/inbound-queue/src/lib.rs index a48b8ff4ce..a2d47f9c1e 100644 --- a/parachain/pallets/inbound-queue/src/lib.rs +++ b/parachain/pallets/inbound-queue/src/lib.rs @@ -29,9 +29,7 @@ mod envelope; mod benchmarking; #[cfg(feature = "runtime-benchmarks")] -use snowbridge_beacon_primitives::CompactExecutionHeader; -#[cfg(feature = "runtime-benchmarks")] -use snowbridge_ethereum::H256; +use {snowbridge_beacon_primitives::CompactExecutionHeader, sp_core::H256}; pub mod weights; @@ -39,20 +37,17 @@ pub mod weights; mod test; use codec::{Decode, DecodeAll, Encode}; +use envelope::Envelope; use frame_support::{ - traits::fungible::{Inspect, Mutate}, + traits::{ + fungible::{Inspect, Mutate}, + tokens::Preservation, + }, + weights::WeightToFee, PalletError, }; use frame_system::ensure_signed; use scale_info::TypeInfo; -use sp_core::H160; -use sp_std::convert::TryFrom; -use xcm::v3::{ - send_xcm, Junction::*, Junctions::*, MultiLocation, SendError as XcmpSendError, SendXcm, - XcmHash, -}; - -use envelope::Envelope; use snowbridge_core::{ inbound::{Message, Verifier}, sibling_sovereign_account, BasicOperatingMode, ParaId, @@ -61,12 +56,14 @@ use snowbridge_router_primitives::{ inbound, inbound::{ConvertMessage, ConvertMessageError}, }; - +use sp_core::H160; use sp_runtime::traits::Saturating; - -use frame_support::{traits::tokens::Preservation, weights::WeightToFee}; - +use sp_std::convert::TryFrom; pub use weights::WeightInfo; +use xcm::v3::{ + send_xcm, Instruction::SetTopic, Junction::*, Junctions::*, MultiLocation, + SendError as XcmpSendError, SendXcm, +}; type BalanceOf = <::Token as Inspect<::AccountId>>::Balance; @@ -136,8 +133,8 @@ pub mod pallet { dest: ParaId, /// The message nonce nonce: u64, - /// XCM hash - xcm_hash: XcmHash, + /// ID of the XCM message which was forwarded to the final destination parachain + message_id: [u8; 32], }, /// Set OperatingMode OperatingModeChanged { mode: BasicOperatingMode }, @@ -210,11 +207,16 @@ pub mod pallet { let who = ensure_signed(origin)?; ensure!(!Self::operating_mode().is_halted(), Error::::Halted); + log::info!(target: "snowbridge-inbound-queue", "WOOP"); + // submit message to verifier for verification - let log = T::Verifier::verify(&message)?; + let logf = T::Verifier::verify(&message)?; + + log::info!(target: "snowbridge-inbound-queue", "BAR: {:?} {:?}", logf.data.len(), logf.topics.len()); + log::info!(target: "snowbridge-inbound-queue", "BOOZ: {:?}", logf.topics.get(0).unwrap()); // Decode log into an Envelope - let envelope = Envelope::try_from(log).map_err(|_| Error::::InvalidEnvelope)?; + let envelope = Envelope::try_from(logf).map_err(|_| Error::::InvalidEnvelope)?; // Verify that the message was submitted from the known Gateway contract ensure!(T::GatewayAddress::get() == envelope.gateway, Error::::InvalidGateway,); @@ -244,20 +246,24 @@ pub mod pallet { )?; // Decode message into XCM - let xcm = match inbound::VersionedMessage::decode_all(&mut envelope.payload.as_ref()) { - Ok(message) => T::MessageConverter::convert(message) - .map_err(|e| Error::::ConvertMessage(e))?, - Err(_) => return Err(Error::::InvalidPayload.into()), - }; + let mut xcm = + match inbound::VersionedMessage::decode_all(&mut envelope.payload.as_ref()) { + Ok(message) => T::MessageConverter::convert(message) + .map_err(|e| Error::::ConvertMessage(e))?, + Err(_) => return Err(Error::::InvalidPayload.into()), + }; + + // Append the message id as an XCM topic + xcm.inner_mut().extend(vec![SetTopic(envelope.message_id.into())]); // Attempt to send XCM to a dest parachain let dest = MultiLocation { parents: 1, interior: X1(Parachain(envelope.dest.into())) }; - let (xcm_hash, _) = send_xcm::(dest, xcm).map_err(Error::::from)?; + let (message_id, _) = send_xcm::(dest, xcm).map_err(Error::::from)?; Self::deposit_event(Event::MessageReceived { dest: envelope.dest, nonce: envelope.nonce, - xcm_hash, + message_id, }); Ok(()) diff --git a/parachain/pallets/inbound-queue/src/test.rs b/parachain/pallets/inbound-queue/src/test.rs index 59db735ffa..c34c1c8fe3 100644 --- a/parachain/pallets/inbound-queue/src/test.rs +++ b/parachain/pallets/inbound-queue/src/test.rs @@ -238,36 +238,29 @@ fn parse_dest(message: Message) -> ParaId { } // dest para is 1000 -const OUTBOUND_QUEUE_EVENT_LOG: [u8; 221] = hex!( +const OUTBOUND_QUEUE_EVENT_LOG: [u8; 254] = hex!( " - f8db94eda338e4dc46038493b885327842fd3e301cab39f842a0d56f1b8dfd3ba41f19c499ceec5f9546f61befa5f10398a75d7dba53a219fecea000000000000000000000000000000000000000000000000000000000000003e8b88000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000 + f8fc94eda338e4dc46038493b885327842fd3e301cab39f863a05066fbba677e15936860e04088ca4cad3acd4c19706962196a5346f1457f7169a000000000000000000000000000000000000000000000000000000000000003e8a0afad3c9777134532ae230b4fad334eef2e0dacbb965920412a7eaa59b07d640fb88000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000 " ); // dest para is 1001 -const OUTBOUND_QUEUE_EVENT_LOG_INVALID_DEST: [u8; 221] = hex!( +const OUTBOUND_QUEUE_EVENT_LOG_INVALID_DEST: [u8; 254] = hex!( " - f8db94eda338e4dc46038493b885327842fd3e301cab39f842a0d56f1b8dfd3ba41f19c499ceec5f9546f61befa5f10398a75d7dba53a219fecea000000000000000000000000000000000000000000000000000000000000003e9b88000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000 + f8fc94eda338e4dc46038493b885327842fd3e301cab39f863a05066fbba677e15936860e04088ca4cad3acd4c19706962196a5346f1457f7169a000000000000000000000000000000000000000000000000000000000000003e9a0afad3c9777134532ae230b4fad334eef2e0dacbb965920412a7eaa59b07d640fb88000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000 " ); -// gateway in message does not match configured gateway in runtime -const BAD_OUTBOUND_QUEUE_EVENT_LOG: [u8; 221] = hex!( +// gateway in message does not match configured gateway in runtimeå +const BAD_OUTBOUND_QUEUE_EVENT_LOG: [u8; 254] = hex!( " - f8db940000000000000000000000000000000000000000f842a0d56f1b8dfd3ba41f19c499ceec5f9546f61befa5f10398a75d7dba53a219fecea000000000000000000000000000000000000000000000000000000000000003e8b88000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000 - " -); - -// invalid payload with unsupported version -const BAD_OUTBOUND_QUEUE_LOG_UNSUPPORTED_VERSION: [u8; 221] = hex!( - " - f8db94eda338e4dc46038493b885327842fd3e301cab39f842a0d56f1b8dfd3ba41f19c499ceec5f9546f61befa5f10398a75d7dba53a219fecea000000000000000000000000000000000000000000000000000000000000003e8b88000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e010f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000 + f8fc940000000000000000000000000000000000000000f863a05066fbba677e15936860e04088ca4cad3acd4c19706962196a5346f1457f7169a000000000000000000000000000000000000000000000000000000000000003e8a0afad3c9777134532ae230b4fad334eef2e0dacbb965920412a7eaa59b07d640fb88000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000 " ); const XCM_HASH: [u8; 32] = [ - 186, 27, 67, 39, 117, 164, 224, 191, 202, 232, 218, 108, 34, 65, 36, 199, 247, 19, 150, 198, - 182, 180, 39, 112, 150, 64, 84, 15, 174, 213, 183, 207, + 201, 101, 244, 67, 153, 61, 253, 203, 92, 23, 197, 172, 112, 209, 53, 248, 118, 25, 253, 110, + 168, 201, 60, 156, 227, 26, 55, 145, 5, 177, 78, 189, ]; const ASSET_HUB_PARAID: u32 = 1000u32; const TEMPLATE_PARAID: u32 = 1001u32; @@ -296,7 +289,7 @@ fn test_submit_happy_path() { expect_events(vec![InboundQueueEvent::MessageReceived { dest: ASSET_HUB_PARAID.into(), nonce: 1, - xcm_hash: XCM_HASH, + message_id: XCM_HASH, } .into()]); }); @@ -414,62 +407,6 @@ fn test_submit_no_funds_to_reward_relayers() { }); } -#[test] -fn test_convert_xcm_message() { - new_tester().execute_with(|| { - // Submit message - let message = Message { - data: OUTBOUND_QUEUE_EVENT_LOG.into(), - proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), - }, - }; - let log = ::Verifier::verify(&message).unwrap(); - - // Decode log into an Envelope - let envelope = Envelope::try_from(log).map_err(|_| Error::::InvalidEnvelope).unwrap(); - - let message = - inbound::VersionedMessage::decode_all(&mut envelope.payload.as_ref()).unwrap(); - - let xcm = ::MessageConverter::convert(message).unwrap(); - - println!("xcm: {:?}", xcm); - - let hash = xcm.using_encoded(sp_io::hashing::blake2_256); - - assert_eq!(hash, XCM_HASH); - }) -} - -#[test] -fn test_submit_with_invalid_payload_unsupported_version() { - new_tester().execute_with(|| { - let relayer: AccountId = Keyring::Bob.into(); - let origin = RuntimeOrigin::signed(relayer); - - // Deposit funds into sovereign account of Asset Hub (Statemint) - let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); - let _ = Balances::mint_into(&sovereign_account, 10000); - - // Submit message - let message = Message { - data: BAD_OUTBOUND_QUEUE_LOG_UNSUPPORTED_VERSION.into(), - proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), - }, - }; - assert_noop!( - InboundQueue::submit(origin.clone(), message.clone()), - Error::::InvalidPayload - ); - }); -} - #[test] fn test_set_operating_mode() { new_tester().execute_with(|| { diff --git a/parachain/pallets/outbound-queue/src/benchmarking.rs b/parachain/pallets/outbound-queue/src/benchmarking.rs index 9fead12bfc..921507425f 100644 --- a/parachain/pallets/outbound-queue/src/benchmarking.rs +++ b/parachain/pallets/outbound-queue/src/benchmarking.rs @@ -21,7 +21,7 @@ mod benchmarks { #[benchmark] fn do_process_message() -> Result<(), BenchmarkError> { let enqueued_message = QueuedMessage { - id: H256::zero().into(), + id: H256::zero(), origin: 1000.into(), command: Command::Upgrade { impl_address: H160::zero(), diff --git a/parachain/pallets/outbound-queue/src/lib.rs b/parachain/pallets/outbound-queue/src/lib.rs index 283e13d9c6..2b9fb6b8ff 100644 --- a/parachain/pallets/outbound-queue/src/lib.rs +++ b/parachain/pallets/outbound-queue/src/lib.rs @@ -173,7 +173,7 @@ pub mod pallet { pub enum Event { /// Message has been queued and will be processed in the future MessageQueued { - /// ID of the message. Usually the XCM message hash. + /// ID of the message. Usually the XCM message hash or a SetTopic. id: H256, }, /// Message will be committed at the end of current block. From now on, to track the @@ -352,30 +352,31 @@ pub mod pallet { } // Decode bytes into versioned message - let versioned_enqueued_message: VersionedQueuedMessage = + let versioned_queued_message: VersionedQueuedMessage = VersionedQueuedMessage::decode(&mut message).map_err(|_| Corrupt)?; // Convert versioned message into latest supported message version - let enqueued_message: QueuedMessage = - versioned_enqueued_message.try_into().map_err(|_| Unsupported)?; + let queued_message: QueuedMessage = + versioned_queued_message.try_into().map_err(|_| Unsupported)?; - let next_nonce = Nonce::::get(enqueued_message.origin).saturating_add(1); + let next_nonce = Nonce::::get(queued_message.origin).saturating_add(1); - let command = enqueued_message.command.index(); - let params = enqueued_message.command.abi_encode(); - let max_dispatch_gas = T::GasMeter::maximum_required(&enqueued_message.command) as u128; - let max_refund = Self::calculate_maximum_gas_refund(&enqueued_message.command); + let command = queued_message.command.index(); + let params = queued_message.command.abi_encode(); + let max_dispatch_gas = T::GasMeter::maximum_required(&queued_message.command) as u128; + let max_refund = Self::calculate_maximum_gas_refund(&queued_message.command); let reward = Self::fee_config().reward; // Construct the final committed message let message = CommittedMessage { - origin: enqueued_message.origin, + origin: queued_message.origin, nonce: next_nonce, command, params, max_dispatch_gas, max_refund, reward, + id: queued_message.id, }; // ABI-encode and hash the prepared message @@ -384,10 +385,10 @@ pub mod pallet { Messages::::append(Box::new(message)); MessageLeaves::::append(message_abi_encoded_hash); - Nonce::::set(enqueued_message.origin, next_nonce); + Nonce::::set(queued_message.origin, next_nonce); Self::deposit_event(Event::MessageAccepted { - id: enqueued_message.id, + id: queued_message.id, nonce: next_nonce, }); diff --git a/parachain/pallets/outbound-queue/src/mock.rs b/parachain/pallets/outbound-queue/src/mock.rs index ed10932c9e..794c953faa 100644 --- a/parachain/pallets/outbound-queue/src/mock.rs +++ b/parachain/pallets/outbound-queue/src/mock.rs @@ -127,6 +127,7 @@ where T: Config, { Message { + id: H256::zero(), origin: OwnParaIdOf::::get(), command: Command::Upgrade { impl_address: H160::zero(), @@ -142,6 +143,7 @@ where T: Config, { Message { + id: H256::zero(), origin: OwnParaIdOf::::get(), command: Command::Upgrade { impl_address: H160::zero(), @@ -156,6 +158,7 @@ where pub fn mock_message(sibling_para_id: u32) -> Message { Message { + id: H256::zero(), origin: sibling_para_id.into(), command: Command::AgentExecute { agent_id: Default::default(), diff --git a/parachain/pallets/outbound-queue/src/send_message_impl.rs b/parachain/pallets/outbound-queue/src/send_message_impl.rs index 4912b9100e..080bde21be 100644 --- a/parachain/pallets/outbound-queue/src/send_message_impl.rs +++ b/parachain/pallets/outbound-queue/src/send_message_impl.rs @@ -8,7 +8,7 @@ use frame_support::{ }; use snowbridge_core::outbound::{ AggregateMessageOrigin, ExportOrigin, Fee, Message, QueuedMessage, SendError, SendMessage, - VersionedQueuedMessage, + Ticket as TicketTrait, VersionedQueuedMessage, }; use sp_core::H256; use sp_runtime::BoundedVec; @@ -18,23 +18,35 @@ pub type MaxEnqueuedMessageSizeOf = <::MessageQueue as EnqueueMessage>::MaxMessageLen; #[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound)] -pub struct Ticket> { - pub id: H256, +pub struct Ticket +where + T: Config, +{ + pub message_id: H256, pub origin: ParaId, - pub message: BoundedVec, + pub message: BoundedVec>, } -impl SendMessage for Pallet { - type Ticket = Ticket>; +impl TicketTrait for Ticket +where + T: Config, +{ + fn message_id(&self) -> H256 { + self.message_id + } +} + +impl SendMessage for Pallet +where + T: Config, +{ + type Ticket = Ticket; type Balance = T::Balance; fn validate(message: &Message) -> Result<(Self::Ticket, Fee), SendError> { // The inner payload should not be too large let payload = message.command.abi_encode(); - // Create a message id for tracking progress in submission pipeline - let message_id: H256 = sp_io::hashing::blake2_256(&(message.encode())).into(); - ensure!( payload.len() < T::MaxMessagePayloadSize::get() as usize, SendError::MessageTooLarge @@ -43,7 +55,7 @@ impl SendMessage for Pallet { let fee = Self::calculate_fee(&message.command); let queued_message: VersionedQueuedMessage = QueuedMessage { - id: message_id, + id: message.id, origin: message.origin, command: message.command.clone(), } @@ -51,7 +63,7 @@ impl SendMessage for Pallet { // The whole message should not be too large let encoded = queued_message.encode().try_into().map_err(|_| SendError::MessageTooLarge)?; - let ticket = Ticket { id: message_id, origin: message.origin, message: encoded }; + let ticket = Ticket { message_id: message.id, origin: message.origin, message: encoded }; Ok((ticket, fee)) } @@ -79,7 +91,7 @@ impl SendMessage for Pallet { let message = ticket.message.as_bounded_slice(); T::MessageQueue::enqueue_message(message, origin); - Self::deposit_event(Event::MessageQueued { id: ticket.id }); - Ok(ticket.id) + Self::deposit_event(Event::MessageQueued { id: ticket.message_id }); + Ok(ticket.message_id) } } diff --git a/parachain/pallets/outbound-queue/src/types.rs b/parachain/pallets/outbound-queue/src/types.rs index bdfd51e942..db75a2c6b5 100644 --- a/parachain/pallets/outbound-queue/src/types.rs +++ b/parachain/pallets/outbound-queue/src/types.rs @@ -4,6 +4,7 @@ use frame_support::traits::ProcessMessage; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use sp_arithmetic::FixedU128; +use sp_core::H256; use sp_runtime::{traits::Zero, RuntimeDebug}; use sp_std::prelude::*; @@ -33,6 +34,8 @@ pub struct CommittedMessage { pub max_refund: u128, /// Reward in ether for delivering this message, in addition to the gas refund pub reward: u128, + /// Message ID (Used for tracing messages across route, has no role in consensus) + pub id: H256, } /// Convert message into an ABI-encoded form for delivery to the InboundQueue contract on Ethereum @@ -46,6 +49,7 @@ impl From for Token { Token::Uint(x.max_dispatch_gas.into()), Token::Uint(x.max_refund.into()), Token::Uint(x.reward.into()), + Token::FixedBytes(Vec::from(x.id.as_ref())), ]) } } diff --git a/parachain/primitives/core/src/outbound.rs b/parachain/primitives/core/src/outbound.rs index cd15d33963..57723a17f2 100644 --- a/parachain/primitives/core/src/outbound.rs +++ b/parachain/primitives/core/src/outbound.rs @@ -4,7 +4,6 @@ pub use polkadot_parachain_primitives::primitives::Id as ParaId; use scale_info::TypeInfo; use sp_arithmetic::traits::{BaseArithmetic, Unsigned}; use sp_core::{RuntimeDebug, H256}; - pub use v1::{AgentExecuteCommand, Command, Initializer, Message, OperatingMode, QueuedMessage}; /// Enqueued outbound messages need to be versioned to prevent data corruption @@ -43,6 +42,8 @@ mod v1 { #[derive(Encode, Decode, TypeInfo, Clone, RuntimeDebug)] #[cfg_attr(feature = "std", derive(PartialEq))] pub struct Message { + /// ID for this message. One will be automatically generated if not provided + pub id: H256, /// The parachain from which the message originated pub origin: ParaId, /// The stable ID for a receiving gateway contract @@ -225,7 +226,7 @@ mod v1 { #[derive(Encode, Decode, Clone, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(PartialEq))] pub struct QueuedMessage { - /// Message ID (usually hash of message) + /// Message ID pub id: H256, /// ID of source parachain pub origin: ParaId, @@ -266,7 +267,7 @@ where /// A trait for sending messages to Ethereum pub trait SendMessage { - type Ticket: Clone + Encode + Decode; + type Ticket: Ticket; type Balance: BaseArithmetic + Unsigned + Copy; /// Validate an outbound message and return a tuple: @@ -278,6 +279,10 @@ pub trait SendMessage { fn deliver(ticket: Self::Ticket) -> Result; } +pub trait Ticket: Encode + Decode + Clone { + fn message_id(&self) -> H256; +} + /// Reasons why sending to Ethereum could not be initiated #[derive(Copy, Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, PalletError, TypeInfo)] pub enum SendError { diff --git a/parachain/primitives/ethereum/Cargo.toml b/parachain/primitives/ethereum/Cargo.toml index 7ff906b19a..832a7bffe0 100644 --- a/parachain/primitives/ethereum/Cargo.toml +++ b/parachain/primitives/ethereum/Cargo.toml @@ -14,8 +14,7 @@ ethereum-types = { version = "0.14.1", default-features = false, features = [ "c hex = { package = "rustc-hex", version = "2.1.0", default-features = false } hex-literal = { version = "0.4.1", default-features = false } parity-bytes = { version = "0.1.2", default-features = false } -rlp = { version = "0.5", default-features = false } -#getrandom = { version = "0.2.1", features = [ "js" ] } +rlp = { version = "0.5.2", default-features = false } sp-io = { path = "../../../polkadot-sdk/substrate/primitives/io", default-features = false } sp-std = { path = "../../../polkadot-sdk/substrate/primitives/std", default-features = false } diff --git a/parachain/primitives/router/src/inbound/mod.rs b/parachain/primitives/router/src/inbound/mod.rs index 54447cb01f..235ea98c71 100644 --- a/parachain/primitives/router/src/inbound/mod.rs +++ b/parachain/primitives/router/src/inbound/mod.rs @@ -83,6 +83,7 @@ pub enum ConvertMessageError { /// convert the inbound message to xcm which will be forwarded to the destination chain pub trait ConvertMessage { + /// Converts a versioned message into an XCM message and an optional topicID fn convert(message: VersionedMessage) -> Result, ConvertMessageError>; } diff --git a/parachain/primitives/router/src/outbound/mod.rs b/parachain/primitives/router/src/outbound/mod.rs index a2b8620fde..1123d29231 100644 --- a/parachain/primitives/router/src/outbound/mod.rs +++ b/parachain/primitives/router/src/outbound/mod.rs @@ -25,7 +25,6 @@ where UniversalLocation: Get, GatewayLocation: Get, OutboundQueue: SendMessage, - OutboundQueue::Ticket: Encode + Decode, AgentHashedDescription: ConvertLocation, { type Ticket = (Vec, XcmHash); @@ -98,7 +97,7 @@ where })?; let mut converter = XcmConverter::new(&message, &gateway_network, &gateway_address); - let (agent_execute_command, max_target_fee) = converter.convert().map_err(|err|{ + let (agent_execute_command, max_target_fee, topic_id) = converter.convert().map_err(|err|{ log::error!(target: "xcm::ethereum_blob_exporter", "unroutable due to pattern matching error '{err:?}'."); SendError::Unroutable })?; @@ -119,6 +118,7 @@ where }; let outbound_message = Message { + id: topic_id.into(), origin: para_id.into(), command: Command::AgentExecute { agent_id, command: agent_execute_command }, }; @@ -132,7 +132,7 @@ where // convert fee to MultiAsset let fee = MultiAsset::from((MultiLocation::parent(), fee.total())).into(); - Ok(((ticket.encode(), XcmHash::default()), fee)) + Ok(((ticket.encode(), topic_id.into()), fee)) } fn deliver(blob: (Vec, XcmHash)) -> Result { @@ -142,13 +142,13 @@ where SendError::NotApplicable })?; - let message_hash = OutboundQueue::deliver(ticket).map_err(|_| { + let message_id = OutboundQueue::deliver(ticket).map_err(|_| { log::error!(target: "xcm::ethereum_blob_exporter", "OutboundQueue submit of message failed"); SendError::Transport("other transport error") })?; - log::info!(target: "xcm::ethereum_blob_exporter", "message delivered {message_hash:#?}."); - Ok(message_hash.into()) + log::info!(target: "xcm::ethereum_blob_exporter", "message delivered {message_id:#?}."); + Ok(message_id.into()) } } @@ -187,7 +187,7 @@ impl<'a, Call> XcmConverter<'a, Call> { fn convert( &mut self, - ) -> Result<(AgentExecuteCommand, Option<&'a MultiAsset>), XcmConverterError> { + ) -> Result<(AgentExecuteCommand, Option<&'a MultiAsset>, [u8; 32]), XcmConverterError> { // Get target fees if specified. let max_target_fee = self.fee_info()?; @@ -195,7 +195,7 @@ impl<'a, Call> XcmConverter<'a, Call> { let result = self.native_tokens_unlock_message()?; // Match last set topic. Later could use message id for replies - let _ = match self.next()? { + let topic_id = match self.next()? { SetTopic(id) => id, _ => return Err(XcmConverterError::SetTopicExpected), }; @@ -205,7 +205,7 @@ impl<'a, Call> XcmConverter<'a, Call> { return Err(XcmConverterError::EndOfXcmMessageExpected) } - Ok((result, max_target_fee)) + Ok((result, max_target_fee, *topic_id)) } fn fee_info(&mut self) -> Result, XcmConverterError> { @@ -307,7 +307,7 @@ impl<'a, Call> XcmConverter<'a, Call> { mod tests { use frame_support::parameter_types; use hex_literal::hex; - use snowbridge_core::outbound::{Fee, SendError}; + use snowbridge_core::outbound::{Fee, SendError, Ticket as TicketTrait}; use xcm::v3::prelude::SendError as XcmSendError; use xcm_builder::{DescribeAllTerminal, DescribeFamily, HashedDescription}; @@ -316,6 +316,7 @@ mod tests { use super::*; parameter_types! { + const MaxMessageSize: u32 = u32::MAX; const RelayNetwork: NetworkId = Polkadot; const UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get()), Parachain(1013)); const BridgedNetwork: NetworkId = Ethereum{ chain_id: 1 }; @@ -326,13 +327,22 @@ mod tests { const GATEWAY: [u8; 20] = hex!("D184c103F7acc340847eEE82a0B909E3358bc28d"); + #[derive(Encode, Decode, Clone)] + struct MockTicket(); + + impl TicketTrait for MockTicket { + fn message_id(&self) -> H256 { + H256::zero() + } + } + struct MockOkOutboundQueue; impl SendMessage for MockOkOutboundQueue { - type Ticket = (); + type Ticket = MockTicket; type Balance = u128; - fn validate(_: &Message) -> Result<((), Fee), SendError> { - Ok(((), Fee { local: 1, remote: 1 })) + fn validate(_: &Message) -> Result<(Self::Ticket, Fee), SendError> { + Ok((MockTicket(), Fee { local: 1, remote: 1 })) } fn deliver(_: Self::Ticket) -> Result { @@ -341,10 +351,10 @@ mod tests { } struct MockErrOutboundQueue; impl SendMessage for MockErrOutboundQueue { - type Ticket = (); + type Ticket = MockTicket; type Balance = u128; - fn validate(_: &Message) -> Result<((), Fee), SendError> { + fn validate(_: &Message) -> Result<(Self::Ticket, Fee), SendError> { Err(SendError::MessageTooLarge) } @@ -745,7 +755,7 @@ mod tests { amount: 1000, }; let result = converter.convert(); - assert_eq!(result, Ok((expected_payload, Some(&fee)))); + assert_eq!(result, Ok((expected_payload, Some(&fee), [0; 32]))); } #[test] @@ -785,7 +795,7 @@ mod tests { amount: 1000, }; let result = converter.convert(); - assert_eq!(result, Ok((expected_payload, None))); + assert_eq!(result, Ok((expected_payload, None, [0; 32]))); } #[test] @@ -825,7 +835,7 @@ mod tests { amount: 1000, }; let result = converter.convert(); - assert_eq!(result, Ok((expected_payload, None))); + assert_eq!(result, Ok((expected_payload, None, [0; 32]))); } #[test] diff --git a/polkadot-sdk b/polkadot-sdk index dab8646cfd..ce31f30276 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit dab8646cfdd5fe8ffe82335feda064cd4b8a5f2c +Subproject commit ce31f302769f26f61a95efda3c50508cfb0bca46 diff --git a/relayer/contracts/gateway.go b/relayer/contracts/gateway.go index 75c8d29c0f..3a1979a228 100644 --- a/relayer/contracts/gateway.go +++ b/relayer/contracts/gateway.go @@ -38,6 +38,7 @@ type InboundMessage struct { MaxDispatchGas *big.Int MaxRefund *big.Int Reward *big.Int + Id [32]byte } // VerificationDigestItem is an auto generated low-level Go binding around an user-defined struct. @@ -84,7 +85,7 @@ type VerificationProof struct { // GatewayMetaData contains all meta data concerning the Gateway contract. var GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"agent\",\"type\":\"address\"}],\"name\":\"AgentCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AgentFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"paraID\",\"type\":\"uint256\"}],\"name\":\"ChannelCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"paraID\",\"type\":\"uint256\"}],\"name\":\"ChannelUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"origin\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"InboundMessageDispatched\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"enumOperatingMode\",\"name\":\"mode\",\"type\":\"uint8\"}],\"name\":\"OperatingModeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"destination\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"OutboundMessageAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenRegistrationSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"destinationAddress\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"TokenSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"}],\"name\":\"agentOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ParaID\",\"name\":\"paraID\",\"type\":\"uint256\"}],\"name\":\"channelFeeOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ParaID\",\"name\":\"paraID\",\"type\":\"uint256\"}],\"name\":\"channelNoncesOf\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ParaID\",\"name\":\"paraID\",\"type\":\"uint256\"}],\"name\":\"channelOperatingModeOf\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatingMode\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"registerToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"destinationAddress\",\"type\":\"bytes32\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"sendToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"sendToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"ParaID\",\"name\":\"origin\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"enumCommand\",\"name\":\"command\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxDispatchGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxRefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"}],\"internalType\":\"structInboundMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"kind\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"consensusEngineID\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structVerification.DigestItem[]\",\"name\":\"digestItems\",\"type\":\"tuple[]\"}],\"internalType\":\"structVerification.ParachainHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"pos\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"width\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structVerification.HeadProof\",\"name\":\"headProof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structVerification.MMRLeafPartial\",\"name\":\"leafPartial\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"leafProofOrder\",\"type\":\"uint256\"}],\"internalType\":\"structVerification.Proof\",\"name\":\"headerProof\",\"type\":\"tuple\"}],\"name\":\"submitInbound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"agent\",\"type\":\"address\"}],\"name\":\"AgentCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"AgentFundsWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"paraID\",\"type\":\"uint256\"}],\"name\":\"ChannelCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"paraID\",\"type\":\"uint256\"}],\"name\":\"ChannelUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"origin\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"InboundMessageDispatched\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"enumOperatingMode\",\"name\":\"mode\",\"type\":\"uint8\"}],\"name\":\"OperatingModeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"ParaID\",\"name\":\"destination\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"OutboundMessageAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenRegistrationSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"destinationAddress\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"TokenSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"topicID\",\"type\":\"bytes32\"}],\"name\":\"Topic\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"agentID\",\"type\":\"bytes32\"}],\"name\":\"agentOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ParaID\",\"name\":\"paraID\",\"type\":\"uint256\"}],\"name\":\"channelFeeOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ParaID\",\"name\":\"paraID\",\"type\":\"uint256\"}],\"name\":\"channelNoncesOf\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"ParaID\",\"name\":\"paraID\",\"type\":\"uint256\"}],\"name\":\"channelOperatingModeOf\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatingMode\",\"outputs\":[{\"internalType\":\"enumOperatingMode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"registerToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"destinationAddress\",\"type\":\"bytes32\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"sendToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"ParaID\",\"name\":\"destinationChain\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"destinationAddress\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"sendToken\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"ParaID\",\"name\":\"origin\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"enumCommand\",\"name\":\"command\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxDispatchGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxRefund\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reward\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"internalType\":\"structInboundMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"extrinsicsRoot\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"kind\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"consensusEngineID\",\"type\":\"bytes4\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structVerification.DigestItem[]\",\"name\":\"digestItems\",\"type\":\"tuple[]\"}],\"internalType\":\"structVerification.ParachainHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"pos\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"width\",\"type\":\"uint256\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structVerification.HeadProof\",\"name\":\"headProof\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structVerification.MMRLeafPartial\",\"name\":\"leafPartial\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"leafProofOrder\",\"type\":\"uint256\"}],\"internalType\":\"structVerification.Proof\",\"name\":\"headerProof\",\"type\":\"tuple\"}],\"name\":\"submitInbound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // GatewayABI is the input ABI used to generate the binding from. @@ -483,23 +484,23 @@ func (_Gateway *GatewayTransactorSession) SendToken0(token common.Address, desti return _Gateway.Contract.SendToken0(&_Gateway.TransactOpts, token, destinationChain, destinationAddress, amount) } -// SubmitInbound is a paid mutator transaction binding the contract method 0xa7397d76. +// SubmitInbound is a paid mutator transaction binding the contract method 0x5a058f67. // -// Solidity: function submitInbound((uint256,uint64,uint8,bytes,uint256,uint256,uint256) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() +// Solidity: function submitInbound((uint256,uint64,uint8,bytes,uint256,uint256,uint256,bytes32) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() func (_Gateway *GatewayTransactor) SubmitInbound(opts *bind.TransactOpts, message InboundMessage, leafProof [][32]byte, headerProof VerificationProof) (*types.Transaction, error) { return _Gateway.contract.Transact(opts, "submitInbound", message, leafProof, headerProof) } -// SubmitInbound is a paid mutator transaction binding the contract method 0xa7397d76. +// SubmitInbound is a paid mutator transaction binding the contract method 0x5a058f67. // -// Solidity: function submitInbound((uint256,uint64,uint8,bytes,uint256,uint256,uint256) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() +// Solidity: function submitInbound((uint256,uint64,uint8,bytes,uint256,uint256,uint256,bytes32) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() func (_Gateway *GatewaySession) SubmitInbound(message InboundMessage, leafProof [][32]byte, headerProof VerificationProof) (*types.Transaction, error) { return _Gateway.Contract.SubmitInbound(&_Gateway.TransactOpts, message, leafProof, headerProof) } -// SubmitInbound is a paid mutator transaction binding the contract method 0xa7397d76. +// SubmitInbound is a paid mutator transaction binding the contract method 0x5a058f67. // -// Solidity: function submitInbound((uint256,uint64,uint8,bytes,uint256,uint256,uint256) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() +// Solidity: function submitInbound((uint256,uint64,uint8,bytes,uint256,uint256,uint256,bytes32) message, bytes32[] leafProof, ((bytes32,uint256,bytes32,bytes32,(uint256,bytes4,bytes)[]),(uint256,uint256,bytes32[]),(uint8,uint32,bytes32,uint64,uint32,bytes32),bytes32[],uint256) headerProof) returns() func (_Gateway *GatewayTransactorSession) SubmitInbound(message InboundMessage, leafProof [][32]byte, headerProof VerificationProof) (*types.Transaction, error) { return _Gateway.Contract.SubmitInbound(&_Gateway.TransactOpts, message, leafProof, headerProof) } @@ -1150,40 +1151,51 @@ func (it *GatewayInboundMessageDispatchedIterator) Close() error { // GatewayInboundMessageDispatched represents a InboundMessageDispatched event raised by the Gateway contract. type GatewayInboundMessageDispatched struct { - Origin *big.Int - Nonce uint64 - Success bool - Raw types.Log // Blockchain specific contextual infos + Origin *big.Int + Nonce uint64 + MessageID [32]byte + Success bool + Raw types.Log // Blockchain specific contextual infos } -// FilterInboundMessageDispatched is a free log retrieval operation binding the contract event 0xc413674585e5f4244fd69ce2c9587aac57f3fdaf6b337a1f39317d2ffa1279f1. +// FilterInboundMessageDispatched is a free log retrieval operation binding the contract event 0xe88d4734b8bcb71455d9b1ece51ef7aae126a1b670e20b299eb98d606ff7a5dc. // -// Solidity: event InboundMessageDispatched(uint256 indexed origin, uint64 nonce, bool success) -func (_Gateway *GatewayFilterer) FilterInboundMessageDispatched(opts *bind.FilterOpts, origin []*big.Int) (*GatewayInboundMessageDispatchedIterator, error) { +// Solidity: event InboundMessageDispatched(uint256 indexed origin, uint64 nonce, bytes32 indexed messageID, bool success) +func (_Gateway *GatewayFilterer) FilterInboundMessageDispatched(opts *bind.FilterOpts, origin []*big.Int, messageID [][32]byte) (*GatewayInboundMessageDispatchedIterator, error) { var originRule []interface{} for _, originItem := range origin { originRule = append(originRule, originItem) } - logs, sub, err := _Gateway.contract.FilterLogs(opts, "InboundMessageDispatched", originRule) + var messageIDRule []interface{} + for _, messageIDItem := range messageID { + messageIDRule = append(messageIDRule, messageIDItem) + } + + logs, sub, err := _Gateway.contract.FilterLogs(opts, "InboundMessageDispatched", originRule, messageIDRule) if err != nil { return nil, err } return &GatewayInboundMessageDispatchedIterator{contract: _Gateway.contract, event: "InboundMessageDispatched", logs: logs, sub: sub}, nil } -// WatchInboundMessageDispatched is a free log subscription operation binding the contract event 0xc413674585e5f4244fd69ce2c9587aac57f3fdaf6b337a1f39317d2ffa1279f1. +// WatchInboundMessageDispatched is a free log subscription operation binding the contract event 0xe88d4734b8bcb71455d9b1ece51ef7aae126a1b670e20b299eb98d606ff7a5dc. // -// Solidity: event InboundMessageDispatched(uint256 indexed origin, uint64 nonce, bool success) -func (_Gateway *GatewayFilterer) WatchInboundMessageDispatched(opts *bind.WatchOpts, sink chan<- *GatewayInboundMessageDispatched, origin []*big.Int) (event.Subscription, error) { +// Solidity: event InboundMessageDispatched(uint256 indexed origin, uint64 nonce, bytes32 indexed messageID, bool success) +func (_Gateway *GatewayFilterer) WatchInboundMessageDispatched(opts *bind.WatchOpts, sink chan<- *GatewayInboundMessageDispatched, origin []*big.Int, messageID [][32]byte) (event.Subscription, error) { var originRule []interface{} for _, originItem := range origin { originRule = append(originRule, originItem) } - logs, sub, err := _Gateway.contract.WatchLogs(opts, "InboundMessageDispatched", originRule) + var messageIDRule []interface{} + for _, messageIDItem := range messageID { + messageIDRule = append(messageIDRule, messageIDItem) + } + + logs, sub, err := _Gateway.contract.WatchLogs(opts, "InboundMessageDispatched", originRule, messageIDRule) if err != nil { return nil, err } @@ -1215,9 +1227,9 @@ func (_Gateway *GatewayFilterer) WatchInboundMessageDispatched(opts *bind.WatchO }), nil } -// ParseInboundMessageDispatched is a log parse operation binding the contract event 0xc413674585e5f4244fd69ce2c9587aac57f3fdaf6b337a1f39317d2ffa1279f1. +// ParseInboundMessageDispatched is a log parse operation binding the contract event 0xe88d4734b8bcb71455d9b1ece51ef7aae126a1b670e20b299eb98d606ff7a5dc. // -// Solidity: event InboundMessageDispatched(uint256 indexed origin, uint64 nonce, bool success) +// Solidity: event InboundMessageDispatched(uint256 indexed origin, uint64 nonce, bytes32 indexed messageID, bool success) func (_Gateway *GatewayFilterer) ParseInboundMessageDispatched(log types.Log) (*GatewayInboundMessageDispatched, error) { event := new(GatewayInboundMessageDispatched) if err := _Gateway.contract.UnpackLog(event, "InboundMessageDispatched", log); err != nil { @@ -1432,38 +1444,49 @@ func (it *GatewayOutboundMessageAcceptedIterator) Close() error { type GatewayOutboundMessageAccepted struct { Destination *big.Int Nonce uint64 + MessageID [32]byte Payload []byte Raw types.Log // Blockchain specific contextual infos } -// FilterOutboundMessageAccepted is a free log retrieval operation binding the contract event 0xd56f1b8dfd3ba41f19c499ceec5f9546f61befa5f10398a75d7dba53a219fece. +// FilterOutboundMessageAccepted is a free log retrieval operation binding the contract event 0x5066fbba677e15936860e04088ca4cad3acd4c19706962196a5346f1457f7169. // -// Solidity: event OutboundMessageAccepted(uint256 indexed destination, uint64 nonce, bytes payload) -func (_Gateway *GatewayFilterer) FilterOutboundMessageAccepted(opts *bind.FilterOpts, destination []*big.Int) (*GatewayOutboundMessageAcceptedIterator, error) { +// Solidity: event OutboundMessageAccepted(uint256 indexed destination, uint64 nonce, bytes32 indexed messageID, bytes payload) +func (_Gateway *GatewayFilterer) FilterOutboundMessageAccepted(opts *bind.FilterOpts, destination []*big.Int, messageID [][32]byte) (*GatewayOutboundMessageAcceptedIterator, error) { var destinationRule []interface{} for _, destinationItem := range destination { destinationRule = append(destinationRule, destinationItem) } - logs, sub, err := _Gateway.contract.FilterLogs(opts, "OutboundMessageAccepted", destinationRule) + var messageIDRule []interface{} + for _, messageIDItem := range messageID { + messageIDRule = append(messageIDRule, messageIDItem) + } + + logs, sub, err := _Gateway.contract.FilterLogs(opts, "OutboundMessageAccepted", destinationRule, messageIDRule) if err != nil { return nil, err } return &GatewayOutboundMessageAcceptedIterator{contract: _Gateway.contract, event: "OutboundMessageAccepted", logs: logs, sub: sub}, nil } -// WatchOutboundMessageAccepted is a free log subscription operation binding the contract event 0xd56f1b8dfd3ba41f19c499ceec5f9546f61befa5f10398a75d7dba53a219fece. +// WatchOutboundMessageAccepted is a free log subscription operation binding the contract event 0x5066fbba677e15936860e04088ca4cad3acd4c19706962196a5346f1457f7169. // -// Solidity: event OutboundMessageAccepted(uint256 indexed destination, uint64 nonce, bytes payload) -func (_Gateway *GatewayFilterer) WatchOutboundMessageAccepted(opts *bind.WatchOpts, sink chan<- *GatewayOutboundMessageAccepted, destination []*big.Int) (event.Subscription, error) { +// Solidity: event OutboundMessageAccepted(uint256 indexed destination, uint64 nonce, bytes32 indexed messageID, bytes payload) +func (_Gateway *GatewayFilterer) WatchOutboundMessageAccepted(opts *bind.WatchOpts, sink chan<- *GatewayOutboundMessageAccepted, destination []*big.Int, messageID [][32]byte) (event.Subscription, error) { var destinationRule []interface{} for _, destinationItem := range destination { destinationRule = append(destinationRule, destinationItem) } - logs, sub, err := _Gateway.contract.WatchLogs(opts, "OutboundMessageAccepted", destinationRule) + var messageIDRule []interface{} + for _, messageIDItem := range messageID { + messageIDRule = append(messageIDRule, messageIDItem) + } + + logs, sub, err := _Gateway.contract.WatchLogs(opts, "OutboundMessageAccepted", destinationRule, messageIDRule) if err != nil { return nil, err } @@ -1495,9 +1518,9 @@ func (_Gateway *GatewayFilterer) WatchOutboundMessageAccepted(opts *bind.WatchOp }), nil } -// ParseOutboundMessageAccepted is a log parse operation binding the contract event 0xd56f1b8dfd3ba41f19c499ceec5f9546f61befa5f10398a75d7dba53a219fece. +// ParseOutboundMessageAccepted is a log parse operation binding the contract event 0x5066fbba677e15936860e04088ca4cad3acd4c19706962196a5346f1457f7169. // -// Solidity: event OutboundMessageAccepted(uint256 indexed destination, uint64 nonce, bytes payload) +// Solidity: event OutboundMessageAccepted(uint256 indexed destination, uint64 nonce, bytes32 indexed messageID, bytes payload) func (_Gateway *GatewayFilterer) ParseOutboundMessageAccepted(log types.Log) (*GatewayOutboundMessageAccepted, error) { event := new(GatewayOutboundMessageAccepted) if err := _Gateway.contract.UnpackLog(event, "OutboundMessageAccepted", log); err != nil { @@ -1797,6 +1820,140 @@ func (_Gateway *GatewayFilterer) ParseTokenSent(log types.Log) (*GatewayTokenSen return event, nil } +// GatewayTopicIterator is returned from FilterTopic and is used to iterate over the raw logs and unpacked data for Topic events raised by the Gateway contract. +type GatewayTopicIterator struct { + Event *GatewayTopic // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *GatewayTopicIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(GatewayTopic) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(GatewayTopic) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *GatewayTopicIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *GatewayTopicIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// GatewayTopic represents a Topic event raised by the Gateway contract. +type GatewayTopic struct { + TopicID [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTopic is a free log retrieval operation binding the contract event 0xff076dd0e7b4feaccc2daf62ded04e4a813b1cd467b86b1a03eb8b0e5cb8763a. +// +// Solidity: event Topic(bytes32 topicID) +func (_Gateway *GatewayFilterer) FilterTopic(opts *bind.FilterOpts) (*GatewayTopicIterator, error) { + + logs, sub, err := _Gateway.contract.FilterLogs(opts, "Topic") + if err != nil { + return nil, err + } + return &GatewayTopicIterator{contract: _Gateway.contract, event: "Topic", logs: logs, sub: sub}, nil +} + +// WatchTopic is a free log subscription operation binding the contract event 0xff076dd0e7b4feaccc2daf62ded04e4a813b1cd467b86b1a03eb8b0e5cb8763a. +// +// Solidity: event Topic(bytes32 topicID) +func (_Gateway *GatewayFilterer) WatchTopic(opts *bind.WatchOpts, sink chan<- *GatewayTopic) (event.Subscription, error) { + + logs, sub, err := _Gateway.contract.WatchLogs(opts, "Topic") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(GatewayTopic) + if err := _Gateway.contract.UnpackLog(event, "Topic", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTopic is a log parse operation binding the contract event 0xff076dd0e7b4feaccc2daf62ded04e4a813b1cd467b86b1a03eb8b0e5cb8763a. +// +// Solidity: event Topic(bytes32 topicID) +func (_Gateway *GatewayFilterer) ParseTopic(log types.Log) (*GatewayTopic, error) { + event := new(GatewayTopic) + if err := _Gateway.contract.UnpackLog(event, "Topic", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + // GatewayUpgradedIterator is returned from FilterUpgraded and is used to iterate over the raw logs and unpacked data for Upgraded events raised by the Gateway contract. type GatewayUpgradedIterator struct { Event *GatewayUpgraded // Event containing the contract specifics and raw log diff --git a/relayer/relays/execution/main.go b/relayer/relays/execution/main.go index 2519b88837..c39a7fa18e 100644 --- a/relayer/relays/execution/main.go +++ b/relayer/relays/execution/main.go @@ -255,7 +255,7 @@ func (r *Relay) findEvents( } func (r *Relay) findEventsWithFilter(opts *bind.FilterOpts, paraID uint32, start uint64) (bool, []*contracts.GatewayOutboundMessageAccepted, error) { - iter, err := r.gatewayContract.FilterOutboundMessageAccepted(opts, []*big.Int{big.NewInt(int64(paraID))}) + iter, err := r.gatewayContract.FilterOutboundMessageAccepted(opts, []*big.Int{big.NewInt(int64(paraID))}, [][32]byte{}) if err != nil { return false, nil, err } diff --git a/relayer/relays/parachain/types.go b/relayer/relays/parachain/types.go index 9bdff130e8..f002002236 100644 --- a/relayer/relays/parachain/types.go +++ b/relayer/relays/parachain/types.go @@ -90,6 +90,7 @@ type OutboundQueueMessage struct { MaxDispatchGas types.U128 MaxRefund types.U128 Reward types.U128 + ID types.Bytes32 } func (m OutboundQueueMessage) IntoInboundMessage() contracts.InboundMessage { @@ -101,6 +102,7 @@ func (m OutboundQueueMessage) IntoInboundMessage() contracts.InboundMessage { MaxDispatchGas: m.MaxDispatchGas.Int, MaxRefund: m.MaxRefund.Int, Reward: m.Reward.Int, + Id: m.ID, } } diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index 74a703ced2..00d1e23fc5 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -77,10 +77,12 @@ export RANDAO_COMMIT_DELAY="${ETH_RANDAO_DELAY:-3}" export RANDAO_COMMIT_EXP="${ETH_RANDAO_EXP:-3}" export MINIMUM_REQUIRED_SIGNATURES="${MINIMUM_REQUIRED_SIGNATURES:-16}" +export REJECT_OUTBOUND_MESSAGES=false export DEFAULT_FEE="${ETH_DEFAULT_FEE:-1}" export CREATE_CALL_INDEX="${ETH_CREATE_CALL_INDEX:-0x3500}" + export REGISTER_NATIVE_TOKEN_FEE="${ETH_REGISTER_NATIVE_TOKEN_FEE:-0}" export SEND_NATIVE_TOKEN_FEE="${ETH_SEND_NATIVE_TOKEN_FEE:-0}" From 273542b9cd4e41d22a3083f538dae97d8da7385b Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Tue, 7 Nov 2023 20:56:59 +0200 Subject: [PATCH 02/14] Add support for message IDs --- contracts/test/Gateway.t.sol | 16 +- parachain/Cargo.lock | 641 +++++++++++++++--- parachain/pallets/inbound-queue/Cargo.toml | 6 +- .../src/benchmarking/fixtures.rs | 2 +- .../pallets/inbound-queue/src/envelope.rs | 76 +-- parachain/pallets/inbound-queue/src/lib.rs | 8 +- parachain/primitives/router/Cargo.toml | 1 + polkadot-sdk | 2 +- .../test/scripts/configure-bridgehub.sh | 1 - 9 files changed, 595 insertions(+), 158 deletions(-) diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index c7c622a43f..af5ae9b140 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -28,20 +28,6 @@ import {WETH9} from "canonical-weth/WETH9.sol"; import "./mocks/GatewayUpgradeMock.sol"; contract GatewayTest is Test { - event InboundMessageDispatched(ParaID indexed origin, uint64 nonce, bool result); - event OutboundMessageAccepted(ParaID indexed dest, uint64 nonce, bytes payload); - event NativeTokensUnlocked(address token, address recipient, uint256 amount); - event TokenRegistrationSent(address token); - event TokenSent( - address indexed sender, address indexed token, ParaID destinationChain, bytes destinationAddress, uint128 amount - ); - event AgentCreated(bytes32 agentID, address agent); - event ChannelCreated(ParaID indexed paraID); - event ChannelUpdated(ParaID indexed paraID); - - event Upgraded(address indexed implementation); - event Initialized(uint256 d0, uint256 d1); - ParaID public bridgeHubParaID = ParaID.wrap(1001); bytes32 public bridgeHubAgentID = keccak256("1001"); address public bridgeHubAgent; @@ -536,7 +522,7 @@ contract GatewayTest is Test { function testRegisterToken() public { vm.expectEmit(false, false, false, true); - emit TokenRegistrationSent(address(token)); + emit IGateway.TokenRegistrationSent(address(token)); vm.expectEmit(true, false, false, false); emit IGateway.OutboundMessageAccepted(assetHubParaID, 1, messageID, bytes("")); diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index c26c95b7e2..7da754e114 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -59,6 +59,66 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloy-primitives" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0628ec0ba5b98b3370bb6be17b12f23bfce8ee4ad83823325a20546d9b03b78" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "proptest", + "rand 0.8.5", + "ruint", + "serde", + "tiny-keccak 2.0.2", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" +dependencies = [ + "arrayvec 0.7.2", + "bytes", + "smol_str", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a98ad1696a2e17f010ae8e43e9f2a1e930ed176a8e3ff77acfeff6dfb07b42c" +dependencies = [ + "const-hex", + "dunce", + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.38", + "syn-solidity", + "tiny-keccak 2.0.2", +] + +[[package]] +name = "alloy-sol-types" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98d7107bed88e8f09f0ddcc3335622d87bfb6821f3e0c7473329fb1cfad5e015" +dependencies = [ + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + [[package]] name = "amcl" version = "0.3.0" @@ -122,8 +182,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f" dependencies = [ "ark-ec", - "ark-ff", - "ark-std", + "ark-ff 0.4.2", + "ark-std 0.4.0", ] [[package]] @@ -133,9 +193,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" dependencies = [ "ark-ec", - "ark-ff", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", ] [[package]] @@ -144,10 +204,10 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ - "ark-ff", + "ark-ff 0.4.2", "ark-poly", - "ark-serialize", - "ark-std", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "derivative", "hashbrown 0.13.2", "itertools", @@ -163,8 +223,26 @@ checksum = "f9cde0f2aa063a2a5c28d39b47761aa102bda7c13c84fc118a61b87c7b2f785c" dependencies = [ "ark-bls12-381", "ark-ec", - "ark-ff", - "ark-std", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", ] [[package]] @@ -173,20 +251,30 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "derivative", "digest 0.10.7", "itertools", "num-bigint", "num-traits", "paste", - "rustc_version", + "rustc_version 0.4.0", "zeroize", ] +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "ark-ff-asm" version = "0.4.2" @@ -197,6 +285,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + [[package]] name = "ark-ff-macros" version = "0.4.2" @@ -216,9 +316,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "derivative", "hashbrown 0.13.2", ] @@ -230,9 +330,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51bd73bb6ddb72630987d37fa963e99196896c0d0ea81b7c894567e74a2f83af" dependencies = [ "ark-ec", - "ark-ff", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "parity-scale-codec", "scale-info", ] @@ -243,15 +343,25 @@ version = "0.0.2" source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" dependencies = [ "ark-ec", - "ark-ff", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "ark-transcript", "digest 0.10.7", "rand_core 0.6.4", "zeroize", ] +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + [[package]] name = "ark-serialize" version = "0.4.2" @@ -259,7 +369,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ "ark-serialize-derive", - "ark-std", + "ark-std 0.4.0", "digest 0.10.7", "num-bigint", ] @@ -275,6 +385,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "ark-std" version = "0.4.0" @@ -290,9 +410,9 @@ name = "ark-transcript" version = "0.0.2" source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "digest 0.10.7", "rand_core 0.6.4", "sha3", @@ -350,6 +470,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -379,9 +511,9 @@ dependencies = [ "ark-bls12-381", "ark-ec", "ark-ed-on-bls12-381-bandersnatch", - "ark-ff", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "dleq_vrf", "fflonk", "merlin 3.0.0", @@ -432,6 +564,21 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitcoin_hashes" version = "0.11.0" @@ -444,6 +591,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "bitvec" version = "1.0.1" @@ -643,10 +796,10 @@ version = "0.1.0" source = "git+https://github.com/w3f/ring-proof#edd1e90b847e560bf60fc2e8712235ccfa11a9a9" dependencies = [ "ark-ec", - "ark-ff", + "ark-ff 0.4.2", "ark-poly", - "ark-serialize", - "ark-std", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "fflonk", "merlin 3.0.0", "rand_chacha 0.3.1", @@ -668,6 +821,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "const-hex" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + [[package]] name = "const-oid" version = "0.9.2" @@ -840,7 +1006,7 @@ dependencies = [ "digest 0.10.7", "fiat-crypto", "platforms", - "rustc_version", + "rustc_version 0.4.0", "subtle", "zeroize", ] @@ -941,7 +1107,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version", + "rustc_version 0.4.0", "syn 1.0.109", ] @@ -980,11 +1146,11 @@ version = "0.0.2" source = "git+https://github.com/w3f/ring-vrf?rev=4b09416#4b09416fd23383ec436ddac127d58c7b7cd392c6" dependencies = [ "ark-ec", - "ark-ff", + "ark-ff 0.4.2", "ark-scale", "ark-secret-scalar", - "ark-serialize", - "ark-std", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "ark-transcript", "arrayvec 0.7.2", "rand_core 0.6.4", @@ -1018,6 +1184,12 @@ dependencies = [ "walkdir", ] +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + [[package]] name = "dyn-clonable" version = "0.9.0" @@ -1155,6 +1327,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "errno" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -1230,6 +1412,23 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec 0.7.2", + "auto_impl", + "bytes", +] + [[package]] name = "ff" version = "0.13.0" @@ -1246,10 +1445,10 @@ version = "0.1.0" source = "git+https://github.com/w3f/fflonk#e141d4b6f42fb481aefe1b479788694945b6940d" dependencies = [ "ark-ec", - "ark-ff", + "ark-ff 0.4.2", "ark-poly", - "ark-serialize", - "ark-std", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "merlin 3.0.0", ] @@ -1271,6 +1470,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" version = "1.1.0" @@ -1321,7 +1526,7 @@ name = "frame-support" version = "4.0.0-dev" dependencies = [ "aquamarine", - "bitflags", + "bitflags 1.3.2", "docify", "environmental", "frame-metadata", @@ -1833,7 +2038,7 @@ checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1894,6 +2099,12 @@ version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libsecp256k1" version = "0.7.1" @@ -1966,6 +2177,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + [[package]] name = "lock_api" version = "0.4.9" @@ -2069,7 +2286,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" dependencies = [ - "rustix", + "rustix 0.36.11", ] [[package]] @@ -2223,11 +2440,12 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2393,9 +2611,9 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2419,6 +2637,17 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +[[package]] +name = "pest" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -2573,6 +2802,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.4.1", + "lazy_static", + "num-traits", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax 0.7.5", + "rusty-fork", + "tempfile", + "unarray", +] + [[package]] name = "psm" version = "0.1.21" @@ -2582,6 +2831,12 @@ dependencies = [ "cc", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.33" @@ -2668,6 +2923,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "rawpointer" version = "0.2.1" @@ -2680,7 +2944,16 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", ] [[package]] @@ -2711,7 +2984,7 @@ checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.6.28", ] [[package]] @@ -2720,7 +2993,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.28", ] [[package]] @@ -2729,6 +3002,12 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + [[package]] name = "rfc6979" version = "0.4.0" @@ -2745,10 +3024,10 @@ version = "0.1.0" source = "git+https://github.com/w3f/ring-proof#edd1e90b847e560bf60fc2e8712235ccfa11a9a9" dependencies = [ "ark-ec", - "ark-ff", + "ark-ff 0.4.2", "ark-poly", - "ark-serialize", - "ark-std", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "blake2", "common", "fflonk", @@ -2765,6 +3044,36 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "ruint" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "724fd11728a3804e9944b14cab63825024c40bf42f8af87c8b5d97c4bbacf426" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.5", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -2777,13 +3086,22 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.17", ] [[package]] @@ -2792,12 +3110,25 @@ version = "0.36.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" dependencies = [ - "bitflags", - "errno", + "bitflags 1.3.2", + "errno 0.2.8", "io-lifetimes", "libc", - "linux-raw-sys", - "windows-sys", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.38.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +dependencies = [ + "bitflags 2.4.1", + "errno 0.3.5", + "libc", + "linux-raw-sys 0.4.10", + "windows-sys 0.48.0", ] [[package]] @@ -2806,6 +3137,18 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.12" @@ -2944,12 +3287,30 @@ dependencies = [ "zeroize", ] +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.190" @@ -3092,6 +3453,15 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +[[package]] +name = "smol_str" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +dependencies = [ + "serde", +] + [[package]] name = "snowbridge-beacon-primitives" version = "0.0.1" @@ -3236,12 +3606,13 @@ dependencies = [ name = "snowbridge-inbound-queue" version = "0.1.1" dependencies = [ - "ethabi-decode", + "alloy-sol-types", "frame-benchmarking", "frame-support", "frame-system", "hex-literal", "log", + "num-traits", "pallet-balances", "parity-scale-codec", "rlp", @@ -3424,7 +3795,7 @@ dependencies = [ "array-bytes 6.1.0", "bandersnatch_vrfs", "bip39", - "bitflags", + "bitflags 1.3.2", "blake2", "bounded-collections", "bs58", @@ -3974,6 +4345,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn-solidity" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -3998,6 +4381,19 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.4.1", + "rustix 0.38.21", + "windows-sys 0.48.0", +] + [[package]] name = "termcolor" version = "1.2.0" @@ -4226,6 +4622,12 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "uint" version = "0.9.5" @@ -4238,6 +4640,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -4303,8 +4711,8 @@ dependencies = [ "ark-bls12-377", "ark-bls12-381", "ark-ec", - "ark-ff", - "ark-serialize", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", "ark-serialize-derive", "arrayref", "constcat", @@ -4318,6 +4726,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "walkdir" version = "2.3.2" @@ -4463,7 +4880,7 @@ dependencies = [ "wasmtime-environ", "wasmtime-jit", "wasmtime-runtime", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -4514,7 +4931,7 @@ dependencies = [ "wasmtime-environ", "wasmtime-jit-icache-coherence", "wasmtime-runtime", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -4534,7 +4951,7 @@ checksum = "aecae978b13f7f67efb23bd827373ace4578f2137ec110bbf6a4a7cde4121bbd" dependencies = [ "cfg-if", "libc", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -4554,11 +4971,11 @@ dependencies = [ "memoffset", "paste", "rand 0.8.5", - "rustix", + "rustix 0.36.11", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -4630,7 +5047,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.1", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -4639,13 +5065,28 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_msvc 0.42.1", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -4654,42 +5095,84 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_i686_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_x86_64_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "winnow" version = "0.5.17" @@ -4720,9 +5203,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] diff --git a/parachain/pallets/inbound-queue/Cargo.toml b/parachain/pallets/inbound-queue/Cargo.toml index 226b127e42..71d0c20730 100644 --- a/parachain/pallets/inbound-queue/Cargo.toml +++ b/parachain/pallets/inbound-queue/Cargo.toml @@ -16,6 +16,8 @@ scale-info = { version = "2.9.0", default-features = false, features = [ "derive hex-literal = { version = "0.4.1", optional = true } rlp = { version = "0.5.2", default-features = false, optional = true } log = { version = "0.4.20", default-features = false } +alloy-sol-types = { version = "0.4.2", default-features = false } +num-traits = { version = "0.2.16", default-features = false } frame-benchmarking = { path = "../../../polkadot-sdk/substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../polkadot-sdk/substrate/frame/support", default-features = false } @@ -32,7 +34,6 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot-sdk/p snowbridge-core = { path = "../../primitives/core", default-features = false } snowbridge-ethereum = { path = "../../primitives/ethereum", default-features = false } snowbridge-router-primitives = { path = "../../primitives/router", default-features = false } -ethabi = { git = "https://github.com/Snowfork/ethabi-decode.git", package = "ethabi-decode", branch = "master", default-features = false } snowbridge-beacon-primitives = { path = "../../primitives/beacon", default-features = false, optional = true } [dev-dependencies] @@ -51,6 +52,7 @@ std = [ "log/std", "codec/std", "scale-info/std", + "alloy-sol-types/std", "frame-support/std", "frame-system/std", "pallet-balances/std", @@ -59,10 +61,10 @@ std = [ "sp-runtime/std", "sp-std/std", "sp-io/std", + "num-traits/std", "snowbridge-core/std", "snowbridge-ethereum/std", "snowbridge-router-primitives/std", - "ethabi/std", "xcm/std", "xcm-builder/std", ] diff --git a/parachain/pallets/inbound-queue/src/benchmarking/fixtures.rs b/parachain/pallets/inbound-queue/src/benchmarking/fixtures.rs index ae1e00fb2a..11da799df8 100644 --- a/parachain/pallets/inbound-queue/src/benchmarking/fixtures.rs +++ b/parachain/pallets/inbound-queue/src/benchmarking/fixtures.rs @@ -17,7 +17,7 @@ pub fn make_create_message() -> InboundQueueTest { receipts_root: hex!("0115ab735d37c5e4cdb0374d8bb547c6dd6ccaa996d996d1eabc5399a719219e").into(), }, message: Message { - data: hex!("f8db94eda338e4dc46038493b885327842fd3e301cab39f842a0d56f1b8dfd3ba41f19c499ceec5f9546f61befa5f10398a75d7dba53a219fecea000000000000000000000000000000000000000000000000000000000000003e8b88000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").to_vec(), + data: hex!("f8fc94eda338e4dc46038493b885327842fd3e301cab39f863a05066fbba677e15936860e04088ca4cad3acd4c19706962196a5346f1457f7169a000000000000000000000000000000000000000000000000000000000000003e8a0afad3c9777134532ae230b4fad334eef2e0dacbb965920412a7eaa59b07d640fb88000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").to_vec(), proof: Proof { block_hash: hex!("5f465744c166e9d10dc0031942a59ff82b640053253da517a1b576afdadb0363").into(), tx_index: 0, diff --git a/parachain/pallets/inbound-queue/src/envelope.rs b/parachain/pallets/inbound-queue/src/envelope.rs index 0462faa2f0..225d90216d 100644 --- a/parachain/pallets/inbound-queue/src/envelope.rs +++ b/parachain/pallets/inbound-queue/src/envelope.rs @@ -1,23 +1,16 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork -use ethabi::{Event, Param, ParamKind, Token}; use snowbridge_core::ParaId; use snowbridge_ethereum::{log::Log, H160}; use sp_core::{RuntimeDebug, H256}; use sp_std::{convert::TryFrom, prelude::*}; -// Used to decode an OutboundMessageAccepted log into an [`Envelope`]. -static EVENT_ABI: &Event = &Event { - signature: "OutboundMessageAccepted(uint256,uint64,bytes32,bytes)", - inputs: &[ - Param { kind: ParamKind::Uint(256), indexed: true }, - Param { kind: ParamKind::Uint(64), indexed: false }, - Param { kind: ParamKind::FixedBytes(32), indexed: true }, - Param { kind: ParamKind::Bytes, indexed: false }, - ], - anonymous: false, -}; +use alloy_sol_types::{abi::token::WordToken, sol, SolEvent}; + +sol! { + event OutboundMessageAccepted(uint256 indexed destination, uint64 nonce, bytes32 indexed messageID, bytes payload); +} /// An inbound message that has had its outer envelope decoded. #[derive(Clone, RuntimeDebug)] @@ -34,8 +27,6 @@ pub struct Envelope { pub payload: Vec, } -use log; - #[derive(Copy, Clone, PartialEq, Eq, RuntimeDebug)] pub struct EnvelopeDecodeError; @@ -43,47 +34,22 @@ impl TryFrom for Envelope { type Error = EnvelopeDecodeError; fn try_from(log: Log) -> Result { - log::info!(target: "snowbridge-inbound-queue", "FOO -2"); - - let tokens = EVENT_ABI.decode(log.topics, log.data).map_err(|_| EnvelopeDecodeError)?; - - log::info!(target: "snowbridge-inbound-queue", "FOO -1"); - - let mut iter = tokens.into_iter(); - - let dest = match iter.next().ok_or(EnvelopeDecodeError)? { - Token::Uint(dest) => dest.low_u32().into(), - _ => return Err(EnvelopeDecodeError), - }; - - log::info!(target: "snowbridge-inbound-queue", "FOO 0"); - - let nonce = match iter.next().ok_or(EnvelopeDecodeError)? { - Token::Uint(nonce) => nonce.low_u64(), - _ => return Err(EnvelopeDecodeError), - }; - - log::info!(target: "snowbridge-inbound-queue", "FOO 1"); - - let message_id = match iter.next().ok_or(EnvelopeDecodeError)? { - Token::FixedBytes(message_id) => { - log::info!(target: "snowbridge-inbound-queue", "FOO 2"); - let message_id: [u8; 32] = - message_id.try_into().map_err(|_| EnvelopeDecodeError)?; - log::info!(target: "snowbridge-inbound-queue", "FOO 3"); - H256::from(&message_id) - }, - _ => return Err(EnvelopeDecodeError), - }; - - log::info!(target: "snowbridge-inbound-queue", "FOO 4"); - - let payload = match iter.next().ok_or(EnvelopeDecodeError)? { - Token::Bytes(payload) => payload, - _ => return Err(EnvelopeDecodeError), - }; - - log::info!(target: "snowbridge-inbound-queue", "FOO 5"); + let topics: Vec = log + .clone() + .topics + .iter() + .map(|t| WordToken::from(*t.as_fixed_bytes())) + .collect(); + + let event = OutboundMessageAccepted::decode_log(topics, &log.data, true).map_err(|e| { + log::error!(target: "ethereum-beacon-client","FOO {:?}", e); + EnvelopeDecodeError + })?; + + let dest: ParaId = event.destination.saturating_to::().into(); + let nonce = event.nonce; + let message_id = H256::from(event.messageID.as_ref()); + let payload = event.payload; Ok(Self { gateway: log.address, dest, nonce, message_id, payload }) } diff --git a/parachain/pallets/inbound-queue/src/lib.rs b/parachain/pallets/inbound-queue/src/lib.rs index a2d47f9c1e..a6d17d11f2 100644 --- a/parachain/pallets/inbound-queue/src/lib.rs +++ b/parachain/pallets/inbound-queue/src/lib.rs @@ -58,7 +58,7 @@ use snowbridge_router_primitives::{ }; use sp_core::H160; use sp_runtime::traits::Saturating; -use sp_std::convert::TryFrom; +use sp_std::{convert::TryFrom, vec}; pub use weights::WeightInfo; use xcm::v3::{ send_xcm, Instruction::SetTopic, Junction::*, Junctions::*, MultiLocation, @@ -207,13 +207,13 @@ pub mod pallet { let who = ensure_signed(origin)?; ensure!(!Self::operating_mode().is_halted(), Error::::Halted); - log::info!(target: "snowbridge-inbound-queue", "WOOP"); + log::info!(target: "ethereum-beacon-client", "WOOP"); // submit message to verifier for verification let logf = T::Verifier::verify(&message)?; - log::info!(target: "snowbridge-inbound-queue", "BAR: {:?} {:?}", logf.data.len(), logf.topics.len()); - log::info!(target: "snowbridge-inbound-queue", "BOOZ: {:?}", logf.topics.get(0).unwrap()); + log::info!(target: "ethereum-beacon-client", "BAR: {:?} {:?}", logf.data.len(), logf.topics.len()); + log::info!(target: "ethereum-beacon-client", "BOOZ: {:?}", logf.topics.get(0).unwrap()); // Decode log into an Envelope let envelope = Envelope::try_from(logf).map_err(|_| Error::::InvalidEnvelope)?; diff --git a/parachain/primitives/router/Cargo.toml b/parachain/primitives/router/Cargo.toml index 3a93e709bf..056a33d2ca 100644 --- a/parachain/primitives/router/Cargo.toml +++ b/parachain/primitives/router/Cargo.toml @@ -47,6 +47,7 @@ std = [ "xcm-executor/std", "snowbridge-core/std", "ethabi/std", + "log/std", ] runtime-benchmarks = [ "snowbridge-core/runtime-benchmarks", diff --git a/polkadot-sdk b/polkadot-sdk index ce31f30276..ed481c9c7e 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit ce31f302769f26f61a95efda3c50508cfb0bca46 +Subproject commit ed481c9c7e94b810311cf2bd597b5e5c46724904 diff --git a/web/packages/test/scripts/configure-bridgehub.sh b/web/packages/test/scripts/configure-bridgehub.sh index 83fb369362..c43625d42c 100755 --- a/web/packages/test/scripts/configure-bridgehub.sh +++ b/web/packages/test/scripts/configure-bridgehub.sh @@ -74,7 +74,6 @@ configure_bridgehub() { wait_beacon_chain_ready config_beacon_checkpoint open_hrmp_channels - enable_gateway } if [ -z "${from_start_services:-}" ]; then From 84d2a292fe113f119623feac7ea0037ccfa460bc Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 8 Nov 2023 09:33:42 +0200 Subject: [PATCH 03/14] inbound-queue no longer depends on older legacy ethereum-related crates --- parachain/Cargo.lock | 15 ++++++- .../ethereum-beacon-client/src/impls.rs | 23 +++++----- .../ethereum-beacon-client/src/tests.rs | 15 ++++--- parachain/pallets/inbound-queue/Cargo.toml | 8 ++-- .../pallets/inbound-queue/src/envelope.rs | 44 +++++++++---------- parachain/pallets/inbound-queue/src/lib.rs | 17 +++---- parachain/pallets/inbound-queue/src/test.rs | 29 +++--------- parachain/primitives/core/src/inbound.rs | 39 +++++++++------- 8 files changed, 98 insertions(+), 92 deletions(-) diff --git a/parachain/Cargo.lock b/parachain/Cargo.lock index 7da754e114..6593791e25 100644 --- a/parachain/Cargo.lock +++ b/parachain/Cargo.lock @@ -85,11 +85,23 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" dependencies = [ + "alloy-rlp-derive", "arrayvec 0.7.2", "bytes", "smol_str", ] +[[package]] +name = "alloy-rlp-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0391754c09fab4eae3404d19d0d297aa1c670c1775ab51d8a5312afeca23157" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "alloy-sol-macro" version = "0.4.2" @@ -3606,6 +3618,8 @@ dependencies = [ name = "snowbridge-inbound-queue" version = "0.1.1" dependencies = [ + "alloy-primitives", + "alloy-rlp", "alloy-sol-types", "frame-benchmarking", "frame-support", @@ -3615,7 +3629,6 @@ dependencies = [ "num-traits", "pallet-balances", "parity-scale-codec", - "rlp", "scale-info", "serde", "snowbridge-beacon-primitives", diff --git a/parachain/pallets/ethereum-beacon-client/src/impls.rs b/parachain/pallets/ethereum-beacon-client/src/impls.rs index 571c0f9f7c..189dc6e93c 100644 --- a/parachain/pallets/ethereum-beacon-client/src/impls.rs +++ b/parachain/pallets/ethereum-beacon-client/src/impls.rs @@ -2,23 +2,23 @@ // SPDX-FileCopyrightText: 2023 Snowfork use super::*; -use snowbridge_ethereum::{Log, Receipt}; -use sp_runtime::DispatchError; +use snowbridge_core::inbound::VerificationError::{self, *}; +use snowbridge_ethereum::Receipt; impl Verifier for Pallet { /// Verify a message by verifying the existence of the corresponding /// Ethereum log in a block. Returns the log if successful. The execution header containing /// the log should be in the beacon client storage, meaning it has been verified and is an /// ancestor of a finalized beacon block. - fn verify(message: &Message) -> Result { + fn verify(message: &Message) -> Result<(), VerificationError> { log::info!( target: "ethereum-beacon-client", "💫 Verifying message with block hash {}", message.proof.block_hash, ); - let header = >::get(message.proof.block_hash) - .ok_or(Error::::MissingHeader)?; + let header = + >::get(message.proof.block_hash).ok_or(HeaderNotFound)?; let receipt = match Self::verify_receipt_inclusion(header.receipts_root, &message.proof) { Ok(receipt) => receipt, @@ -48,7 +48,7 @@ impl Verifier for Pallet { message.proof.block_hash, err ); - return Err(Error::::DecodeFailed.into()) + return Err(InvalidLog) }, }; @@ -58,7 +58,7 @@ impl Verifier for Pallet { "💫 Event log not found in receipt for transaction at index {} in block {}", message.proof.tx_index, message.proof.block_hash, ); - return Err(Error::::InvalidProof.into()) + return Err(NotFound) } log::info!( @@ -67,7 +67,7 @@ impl Verifier for Pallet { message.proof.block_hash, ); - Ok(log) + Ok(()) } } @@ -77,9 +77,8 @@ impl Pallet { pub fn verify_receipt_inclusion( receipts_root: H256, proof: &Proof, - ) -> Result { - let result = - verify_receipt_proof(receipts_root, &proof.data.1).ok_or(Error::::InvalidProof)?; + ) -> Result { + let result = verify_receipt_proof(receipts_root, &proof.data.1).ok_or(InvalidProof)?; match result { Ok(receipt) => Ok(receipt), @@ -89,7 +88,7 @@ impl Pallet { "💫 Failed to decode transaction receipt: {}", err ); - Err(Error::::InvalidProof.into()) + Err(InvalidProof) }, } } diff --git a/parachain/pallets/ethereum-beacon-client/src/tests.rs b/parachain/pallets/ethereum-beacon-client/src/tests.rs index 32cf0d485d..e4cc7a5435 100644 --- a/parachain/pallets/ethereum-beacon-client/src/tests.rs +++ b/parachain/pallets/ethereum-beacon-client/src/tests.rs @@ -16,7 +16,10 @@ use primitives::{ CompactExecutionHeader, ExecutionHeaderState, Fork, ForkVersions, NextSyncCommitteeUpdate, }; use rand::{thread_rng, Rng}; -use snowbridge_core::{inbound::Verifier, RingBufferMap}; +use snowbridge_core::{ + inbound::{VerificationError, Verifier}, + RingBufferMap, +}; use sp_core::H256; use sp_runtime::DispatchError; @@ -922,7 +925,7 @@ fn verify_message_missing_header() { let message = get_message_verification_payload(); new_tester().execute_with(|| { - assert_err!(EthereumBeaconClient::verify(&message), Error::::MissingHeader); + assert_err!(EthereumBeaconClient::verify(&message), VerificationError::HeaderNotFound); }); } @@ -935,7 +938,7 @@ fn verify_message_invalid_proof() { new_tester().execute_with(|| { >::insert(block_hash, header); - assert_err!(EthereumBeaconClient::verify(&message), Error::::InvalidProof); + assert_err!(EthereumBeaconClient::verify(&message), VerificationError::InvalidProof); }); } @@ -948,7 +951,7 @@ fn verify_message_invalid_receipts_root() { new_tester().execute_with(|| { >::insert(block_hash, header); - assert_err!(EthereumBeaconClient::verify(&message), Error::::InvalidProof); + assert_err!(EthereumBeaconClient::verify(&message), VerificationError::InvalidProof); }); } @@ -961,7 +964,7 @@ fn verify_message_invalid_message_data() { new_tester().execute_with(|| { >::insert(block_hash, header); - assert_err!(EthereumBeaconClient::verify(&message), Error::::DecodeFailed); + assert_err!(EthereumBeaconClient::verify(&message), VerificationError::InvalidLog); }); } @@ -974,7 +977,7 @@ fn verify_message_receipt_does_not_contain_log() { new_tester().execute_with(|| { >::insert(block_hash, header); - assert_err!(EthereumBeaconClient::verify(&message), Error::::InvalidProof); + assert_err!(EthereumBeaconClient::verify(&message), VerificationError::NotFound); }); } diff --git a/parachain/pallets/inbound-queue/Cargo.toml b/parachain/pallets/inbound-queue/Cargo.toml index 71d0c20730..688d392499 100644 --- a/parachain/pallets/inbound-queue/Cargo.toml +++ b/parachain/pallets/inbound-queue/Cargo.toml @@ -14,9 +14,10 @@ serde = { version = "1.0.188", optional = true } codec = { version = "3.6.1", package = "parity-scale-codec", default-features = false, features = [ "derive" ] } scale-info = { version = "2.9.0", default-features = false, features = [ "derive" ] } hex-literal = { version = "0.4.1", optional = true } -rlp = { version = "0.5.2", default-features = false, optional = true } log = { version = "0.4.20", default-features = false } +alloy-primitives = { version = "0.4.2", default-features = false, features = ["rlp"] } alloy-sol-types = { version = "0.4.2", default-features = false } +alloy-rlp = { version = "0.3.3", default-features = false, features = ["derive"] } num-traits = { version = "0.2.16", default-features = false } frame-benchmarking = { path = "../../../polkadot-sdk/substrate/frame/benchmarking", default-features = false, optional = true } @@ -41,9 +42,7 @@ frame-benchmarking = { path = "../../../polkadot-sdk/substrate/frame/benchmarkin sp-keyring = { path = "../../../polkadot-sdk/substrate/primitives/keyring" } snowbridge-beacon-primitives = { path = "../../primitives/beacon" } snowbridge-ethereum-beacon-client = { path = "../../pallets/ethereum-beacon-client" } - hex-literal = { version = "0.4.1" } -rlp = { version = "0.5.2" } [features] default = ["std"] @@ -52,7 +51,9 @@ std = [ "log/std", "codec/std", "scale-info/std", + "alloy-primitives/std", "alloy-sol-types/std", + "alloy-rlp/std", "frame-support/std", "frame-system/std", "pallet-balances/std", @@ -74,7 +75,6 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "hex-literal", - "rlp", "snowbridge-beacon-primitives", "xcm-builder/runtime-benchmarks", ] diff --git a/parachain/pallets/inbound-queue/src/envelope.rs b/parachain/pallets/inbound-queue/src/envelope.rs index 225d90216d..e12ecf6c0f 100644 --- a/parachain/pallets/inbound-queue/src/envelope.rs +++ b/parachain/pallets/inbound-queue/src/envelope.rs @@ -1,12 +1,20 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use snowbridge_core::ParaId; -use snowbridge_ethereum::{log::Log, H160}; -use sp_core::{RuntimeDebug, H256}; +use sp_core::{RuntimeDebug, H160, H256}; use sp_std::{convert::TryFrom, prelude::*}; -use alloy_sol_types::{abi::token::WordToken, sol, SolEvent}; +use alloy_primitives::{Address, Bytes, B256}; +use alloy_rlp::RlpDecodable; +use alloy_sol_types::{sol, SolEvent}; + +#[derive(RlpDecodable, RuntimeDebug)] +pub struct Log { + pub address: Address, + pub topics: Vec, + pub data: Bytes, +} sol! { event OutboundMessageAccepted(uint256 indexed destination, uint64 nonce, bytes32 indexed messageID, bytes payload); @@ -27,30 +35,22 @@ pub struct Envelope { pub payload: Vec, } -#[derive(Copy, Clone, PartialEq, Eq, RuntimeDebug)] +#[derive(Copy, Clone, RuntimeDebug)] pub struct EnvelopeDecodeError; impl TryFrom for Envelope { type Error = EnvelopeDecodeError; fn try_from(log: Log) -> Result { - let topics: Vec = log - .clone() - .topics - .iter() - .map(|t| WordToken::from(*t.as_fixed_bytes())) - .collect(); - - let event = OutboundMessageAccepted::decode_log(topics, &log.data, true).map_err(|e| { - log::error!(target: "ethereum-beacon-client","FOO {:?}", e); - EnvelopeDecodeError - })?; - - let dest: ParaId = event.destination.saturating_to::().into(); - let nonce = event.nonce; - let message_id = H256::from(event.messageID.as_ref()); - let payload = event.payload; - - Ok(Self { gateway: log.address, dest, nonce, message_id, payload }) + let event = OutboundMessageAccepted::decode_log(log.topics, &log.data, true) + .map_err(|_| EnvelopeDecodeError)?; + + Ok(Self { + gateway: H160::from(log.address.as_ref()), + dest: event.destination.saturating_to::().into(), + nonce: event.nonce, + message_id: H256::from(event.messageID.as_ref()), + payload: event.payload, + }) } } diff --git a/parachain/pallets/inbound-queue/src/lib.rs b/parachain/pallets/inbound-queue/src/lib.rs index a6d17d11f2..124184c44b 100644 --- a/parachain/pallets/inbound-queue/src/lib.rs +++ b/parachain/pallets/inbound-queue/src/lib.rs @@ -36,8 +36,9 @@ pub mod weights; #[cfg(test)] mod test; +use alloy_rlp::Decodable as RlpDecodable; use codec::{Decode, DecodeAll, Encode}; -use envelope::Envelope; +use envelope::{Envelope, Log}; use frame_support::{ traits::{ fungible::{Inspect, Mutate}, @@ -49,7 +50,7 @@ use frame_support::{ use frame_system::ensure_signed; use scale_info::TypeInfo; use snowbridge_core::{ - inbound::{Message, Verifier}, + inbound::{Message, VerificationError, Verifier}, sibling_sovereign_account, BasicOperatingMode, ParaId, }; use snowbridge_router_primitives::{ @@ -156,6 +157,8 @@ pub mod pallet { InvalidAccountConversion, /// Pallet is halted Halted, + /// Message verification error, + Verification(VerificationError), /// XCMP send failure Send(SendError), /// Message conversion error @@ -207,16 +210,14 @@ pub mod pallet { let who = ensure_signed(origin)?; ensure!(!Self::operating_mode().is_halted(), Error::::Halted); - log::info!(target: "ethereum-beacon-client", "WOOP"); - // submit message to verifier for verification - let logf = T::Verifier::verify(&message)?; + T::Verifier::verify(&message).map_err(|e| Error::::Verification(e))?; - log::info!(target: "ethereum-beacon-client", "BAR: {:?} {:?}", logf.data.len(), logf.topics.len()); - log::info!(target: "ethereum-beacon-client", "BOOZ: {:?}", logf.topics.get(0).unwrap()); + let log = Log::decode(&mut message.data.as_slice()) + .map_err(|_| Error::::InvalidEnvelope)?; // Decode log into an Envelope - let envelope = Envelope::try_from(logf).map_err(|_| Error::::InvalidEnvelope)?; + let envelope = Envelope::try_from(log).map_err(|_| Error::::InvalidEnvelope)?; // Verify that the message was submitted from the known Gateway contract ensure!(T::GatewayAddress::get() == envelope.gateway, Error::::InvalidGateway,); diff --git a/parachain/pallets/inbound-queue/src/test.rs b/parachain/pallets/inbound-queue/src/test.rs index c34c1c8fe3..e7b3224b65 100644 --- a/parachain/pallets/inbound-queue/src/test.rs +++ b/parachain/pallets/inbound-queue/src/test.rs @@ -10,10 +10,9 @@ use frame_support::{ use hex_literal::hex; use snowbridge_beacon_primitives::{Fork, ForkVersions}; use snowbridge_core::{ - inbound::{Message, Proof}, + inbound::{Message, Proof, VerificationError}, ParaId, }; -use snowbridge_ethereum::Log; use snowbridge_router_primitives::inbound::MessageToXcm; use sp_core::{H160, H256}; use sp_keyring::AccountKeyring as Keyring; @@ -24,7 +23,7 @@ use sp_runtime::{ use sp_std::convert::From; use xcm::v3::{prelude::*, MultiAssets, SendXcm}; -use crate::{self as inbound_queue, envelope::Envelope, Error, Event as InboundQueueEvent}; +use crate::{self as inbound_queue, Error, Event as InboundQueueEvent}; type Block = frame_system::mocking::MockBlock; @@ -121,9 +120,8 @@ impl snowbridge_ethereum_beacon_client::Config for Test { pub struct MockVerifier; impl Verifier for MockVerifier { - fn verify(message: &Message) -> Result { - let log: Log = rlp::decode(&message.data).unwrap(); - Ok(log) + fn verify(_: &Message) -> Result<(), VerificationError> { + Ok(()) } } @@ -221,22 +219,6 @@ pub fn new_tester() -> sp_io::TestExternalities { ext } -fn parse_dest(message: Message) -> ParaId { - 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.dest -} - // dest para is 1000 const OUTBOUND_QUEUE_EVENT_LOG: [u8; 254] = hex!( " @@ -369,8 +351,7 @@ fn test_submit_with_invalid_nonce() { }; assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); - let event_dest = parse_dest(message.clone()); - let nonce: u64 = >::get(event_dest); + let nonce: u64 = >::get(ParaId::from(1000)); assert_eq!(nonce, 1); // Submit the same again diff --git a/parachain/primitives/core/src/inbound.rs b/parachain/primitives/core/src/inbound.rs index 5e7b10c25b..be179de7fe 100644 --- a/parachain/primitives/core/src/inbound.rs +++ b/parachain/primitives/core/src/inbound.rs @@ -3,36 +3,45 @@ //! Types for representing inbound messages use codec::{Decode, Encode}; +use frame_support::PalletError; use scale_info::TypeInfo; -use snowbridge_ethereum::Log; use sp_core::H256; -use sp_runtime::{DispatchError, RuntimeDebug}; +use sp_runtime::RuntimeDebug; use sp_std::vec::Vec; /// A trait for verifying inbound messages from Ethereum. -/// -/// This trait should be implemented by runtime modules that wish to provide message verification -/// functionality. pub trait Verifier { - fn verify(message: &Message) -> Result; + fn verify(message: &Message) -> Result<(), VerificationError>; +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, PalletError, TypeInfo)] +#[cfg_attr(feature = "std", derive(PartialEq))] +pub enum VerificationError { + /// Execution header is missing + HeaderNotFound, + /// Log was not found in the verified transaction receipt + NotFound, + /// Data payload does not decode into a valid Log + InvalidLog, + /// Unable to verify the transaction receipt with the provided proof + InvalidProof, } pub type MessageNonce = u64; -/// A message relayed from Ethereum. -#[derive(PartialEq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +/// A bridge message from the Gateway contract on Ethereum +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(PartialEq))] pub struct Message { - /// The raw RLP-encoded message data. + /// RLP-encoded event log pub data: Vec, - /// Input to the message verifier + /// Inclusion proof for a transaction receipt containing the event log pub proof: Proof, } -/// Verification input for the message verifier. -/// -/// This data type allows us to support multiple verification schemes. In the near future, -/// A light-client scheme will be added too. -#[derive(PartialEq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +/// Inclusion proof for a transaction receipt +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(PartialEq))] pub struct Proof { // The block hash of the block in which the receipt was included. pub block_hash: H256, From b0e408e27129dff6fcd049dcfb3e7aa836141b46 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 8 Nov 2023 10:00:41 +0200 Subject: [PATCH 04/14] Use for generating unique message ids --- parachain/pallets/control/src/lib.rs | 15 +-------------- parachain/pallets/control/src/tests.rs | 4 ++-- .../outbound-queue/src/benchmarking.rs | 2 +- parachain/pallets/outbound-queue/src/mock.rs | 6 +++--- .../outbound-queue/src/send_message_impl.rs | 9 +++++++-- parachain/primitives/core/src/outbound.rs | 19 +++++++++++++------ .../primitives/router/src/outbound/mod.rs | 2 +- 7 files changed, 28 insertions(+), 29 deletions(-) diff --git a/parachain/pallets/control/src/lib.rs b/parachain/pallets/control/src/lib.rs index 627ec9ac23..c0417fa400 100644 --- a/parachain/pallets/control/src/lib.rs +++ b/parachain/pallets/control/src/lib.rs @@ -200,10 +200,6 @@ pub mod pallet { #[pallet::getter(fn channels)] pub type Channels = StorageMap<_, Twox64Concat, ParaId, (), OptionQuery>; - /// Generator for a unique message ID - #[pallet::storage] - pub type NextMessageId = StorageValue<_, u64, ValueQuery>; - #[pallet::call] impl Pallet { /// Sends command to the Gateway contract to upgrade itself with a new implementation @@ -433,7 +429,7 @@ pub mod pallet { impl Pallet { /// Send `command` to the Gateway on the channel identified by `origin`. fn send(origin: ParaId, command: Command, pays_fee: PaysFee) -> DispatchResult { - let message = Message { id: Self::alloc_message_id(), origin, command }; + let message = Message { id: None, origin, command }; let (ticket, fee) = T::OutboundQueue::validate(&message).map_err(|err| Error::::Send(err))?; @@ -477,14 +473,5 @@ pub mod pallet { }); Ok(()) } - - // Allocate a unique id for a message. Used in the implementation of SendMessage,. - pub(crate) fn alloc_message_id() -> H256 { - NextMessageId::::mutate(|next_message_id| { - *next_message_id = next_message_id.saturating_add(1) - }); - let next_message_id = NextMessageId::::get(); - sp_io::hashing::blake2_256(&(next_message_id.encode())).into() - } } } diff --git a/parachain/pallets/control/src/tests.rs b/parachain/pallets/control/src/tests.rs index ba8b77f995..10be9b3a65 100644 --- a/parachain/pallets/control/src/tests.rs +++ b/parachain/pallets/control/src/tests.rs @@ -521,7 +521,7 @@ fn charge_fee_for_create_agent() { assert_ok!(EthereumControl::create_agent(origin.clone())); // assert sovereign_balance decreased by (fee.base_fee + fee.delivery_fee) let message = Message { - id: H256::zero(), + id: None, origin: para_id.into(), command: Command::CreateAgent { agent_id }, }; @@ -558,7 +558,7 @@ fn charge_fee_for_transfer_native_from_agent() { let sovereign_balance_before = Balances::balance(&sovereign_account); assert_ok!(EthereumControl::transfer_native_from_agent(origin.clone(), recipient, amount)); let message = Message { - id: H256::zero(), + id: None, origin: para_id.into(), command: Command::TransferNativeFromAgent { agent_id, recipient, amount }, }; diff --git a/parachain/pallets/outbound-queue/src/benchmarking.rs b/parachain/pallets/outbound-queue/src/benchmarking.rs index 921507425f..4ec2910ece 100644 --- a/parachain/pallets/outbound-queue/src/benchmarking.rs +++ b/parachain/pallets/outbound-queue/src/benchmarking.rs @@ -21,7 +21,7 @@ mod benchmarks { #[benchmark] fn do_process_message() -> Result<(), BenchmarkError> { let enqueued_message = QueuedMessage { - id: H256::zero(), + id: None, origin: 1000.into(), command: Command::Upgrade { impl_address: H160::zero(), diff --git a/parachain/pallets/outbound-queue/src/mock.rs b/parachain/pallets/outbound-queue/src/mock.rs index 794c953faa..d817261068 100644 --- a/parachain/pallets/outbound-queue/src/mock.rs +++ b/parachain/pallets/outbound-queue/src/mock.rs @@ -127,7 +127,7 @@ where T: Config, { Message { - id: H256::zero(), + id: None, origin: OwnParaIdOf::::get(), command: Command::Upgrade { impl_address: H160::zero(), @@ -143,7 +143,7 @@ where T: Config, { Message { - id: H256::zero(), + id: None, origin: OwnParaIdOf::::get(), command: Command::Upgrade { impl_address: H160::zero(), @@ -158,7 +158,7 @@ where pub fn mock_message(sibling_para_id: u32) -> Message { Message { - id: H256::zero(), + id: None, origin: sibling_para_id.into(), command: Command::AgentExecute { agent_id: Default::default(), diff --git a/parachain/pallets/outbound-queue/src/send_message_impl.rs b/parachain/pallets/outbound-queue/src/send_message_impl.rs index 080bde21be..9dacf2c17f 100644 --- a/parachain/pallets/outbound-queue/src/send_message_impl.rs +++ b/parachain/pallets/outbound-queue/src/send_message_impl.rs @@ -6,6 +6,7 @@ use frame_support::{ traits::{EnqueueMessage, Get}, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; +use frame_system::unique; use snowbridge_core::outbound::{ AggregateMessageOrigin, ExportOrigin, Fee, Message, QueuedMessage, SendError, SendMessage, Ticket as TicketTrait, VersionedQueuedMessage, @@ -52,10 +53,14 @@ where SendError::MessageTooLarge ); + // Generate a unique message id unless one is provided + let message_id: H256 = + message.id.unwrap_or_else(|| unique((message.origin, &message.command)).into()); + let fee = Self::calculate_fee(&message.command); let queued_message: VersionedQueuedMessage = QueuedMessage { - id: message.id, + id: message_id, origin: message.origin, command: message.command.clone(), } @@ -63,7 +68,7 @@ where // The whole message should not be too large let encoded = queued_message.encode().try_into().map_err(|_| SendError::MessageTooLarge)?; - let ticket = Ticket { message_id: message.id, origin: message.origin, message: encoded }; + let ticket = Ticket { message_id, origin: message.origin, message: encoded }; Ok((ticket, fee)) } diff --git a/parachain/primitives/core/src/outbound.rs b/parachain/primitives/core/src/outbound.rs index 57723a17f2..1afafec13f 100644 --- a/parachain/primitives/core/src/outbound.rs +++ b/parachain/primitives/core/src/outbound.rs @@ -38,12 +38,17 @@ mod v1 { use sp_core::{RuntimeDebug, H160, H256, U256}; use sp_std::{borrow::ToOwned, vec, vec::Vec}; - /// A message which can be accepted by the [`OutboundQueue`] + /// A message which can be accepted by implementations of [`SendMessage`] #[derive(Encode, Decode, TypeInfo, Clone, RuntimeDebug)] #[cfg_attr(feature = "std", derive(PartialEq))] pub struct Message { - /// ID for this message. One will be automatically generated if not provided - pub id: H256, + /// ID for this message. One will be automatically generated if not provided. + /// + /// When this message is created from an XCM message, the ID should be extracted + /// from the `SetTopic` instruction. + /// + /// The ID plays no role in bridge consensus, and is purely meant for message tracing. + pub id: Option, /// The parachain from which the message originated pub origin: ParaId, /// The stable ID for a receiving gateway contract @@ -57,7 +62,7 @@ mod v1 { } /// A command which is executable by the Gateway contract on Ethereum - #[derive(Encode, Decode, TypeInfo, Clone, RuntimeDebug)] + #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(PartialEq))] pub enum Command { /// Execute a sub-command within an agent for a consensus system in Polkadot @@ -177,7 +182,8 @@ mod v1 { /// Representation of a call to the initializer of an implementation contract. /// The initializer has the following ABI signature: `initialize(bytes)`. - #[derive(Encode, Decode, TypeInfo, PartialEq, Clone, RuntimeDebug)] + #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] + #[cfg_attr(feature = "std", derive(PartialEq))] pub struct Initializer { /// ABI-encoded params of type `bytes` to pass to the initializer pub params: Vec, @@ -186,7 +192,8 @@ mod v1 { } /// A Sub-command executable within an agent - #[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)] + #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] + #[cfg_attr(feature = "std", derive(PartialEq))] pub enum AgentExecuteCommand { /// Transfer ERC20 tokens TransferToken { diff --git a/parachain/primitives/router/src/outbound/mod.rs b/parachain/primitives/router/src/outbound/mod.rs index 1123d29231..7c2024649a 100644 --- a/parachain/primitives/router/src/outbound/mod.rs +++ b/parachain/primitives/router/src/outbound/mod.rs @@ -118,7 +118,7 @@ where }; let outbound_message = Message { - id: topic_id.into(), + id: Some(topic_id.into()), origin: para_id.into(), command: Command::AgentExecute { agent_id, command: agent_execute_command }, }; From 6f0eecb9d5383dd54c7a3e200704d94b20e59467 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 8 Nov 2023 12:29:26 +0200 Subject: [PATCH 05/14] Bump polkadot-sdk --- polkadot-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot-sdk b/polkadot-sdk index f4e542d9b6..1adaaee513 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit f4e542d9b663aa6c5cc1b67bf59f8373d64db844 +Subproject commit 1adaaee51314dc7747442b1179a781ffb648d1d0 From 211895023a143174dd2fa1b385d304681e96d4e4 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 8 Nov 2023 15:36:23 +0200 Subject: [PATCH 06/14] revert some changes that caused tests to fail --- parachain/primitives/core/src/inbound.rs | 6 ++---- parachain/primitives/core/src/outbound.rs | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/parachain/primitives/core/src/inbound.rs b/parachain/primitives/core/src/inbound.rs index be179de7fe..8f3d6d6332 100644 --- a/parachain/primitives/core/src/inbound.rs +++ b/parachain/primitives/core/src/inbound.rs @@ -30,8 +30,7 @@ pub enum VerificationError { pub type MessageNonce = u64; /// A bridge message from the Gateway contract on Ethereum -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -#[cfg_attr(feature = "std", derive(PartialEq))] +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] pub struct Message { /// RLP-encoded event log pub data: Vec, @@ -40,8 +39,7 @@ pub struct Message { } /// Inclusion proof for a transaction receipt -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -#[cfg_attr(feature = "std", derive(PartialEq))] +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] pub struct Proof { // The block hash of the block in which the receipt was included. pub block_hash: H256, diff --git a/parachain/primitives/core/src/outbound.rs b/parachain/primitives/core/src/outbound.rs index 9b1c741906..4d3f78ca31 100644 --- a/parachain/primitives/core/src/outbound.rs +++ b/parachain/primitives/core/src/outbound.rs @@ -182,8 +182,7 @@ mod v1 { /// Representation of a call to the initializer of an implementation contract. /// The initializer has the following ABI signature: `initialize(bytes)`. - #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] - #[cfg_attr(feature = "std", derive(PartialEq))] + #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] pub struct Initializer { /// ABI-encoded params of type `bytes` to pass to the initializer pub params: Vec, @@ -230,7 +229,7 @@ mod v1 { } /// Message which is awaiting processing in the MessageQueue pallet - #[derive(Encode, Decode, Clone, RuntimeDebug, TypeInfo)] + #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] #[cfg_attr(feature = "std", derive(PartialEq))] pub struct QueuedMessage { /// Message ID From 75ccfa7bedefa81d2565526ca2a528e11c5ecddb Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 8 Nov 2023 20:15:50 +0200 Subject: [PATCH 07/14] review feedback --- parachain/pallets/ethereum-beacon-client/src/impls.rs | 2 +- parachain/pallets/ethereum-beacon-client/src/tests.rs | 2 +- parachain/primitives/core/src/inbound.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parachain/pallets/ethereum-beacon-client/src/impls.rs b/parachain/pallets/ethereum-beacon-client/src/impls.rs index 189dc6e93c..35b2e287de 100644 --- a/parachain/pallets/ethereum-beacon-client/src/impls.rs +++ b/parachain/pallets/ethereum-beacon-client/src/impls.rs @@ -58,7 +58,7 @@ impl Verifier for Pallet { "💫 Event log not found in receipt for transaction at index {} in block {}", message.proof.tx_index, message.proof.block_hash, ); - return Err(NotFound) + return Err(LogNotFound) } log::info!( diff --git a/parachain/pallets/ethereum-beacon-client/src/tests.rs b/parachain/pallets/ethereum-beacon-client/src/tests.rs index e4cc7a5435..95a7c38229 100644 --- a/parachain/pallets/ethereum-beacon-client/src/tests.rs +++ b/parachain/pallets/ethereum-beacon-client/src/tests.rs @@ -977,7 +977,7 @@ fn verify_message_receipt_does_not_contain_log() { new_tester().execute_with(|| { >::insert(block_hash, header); - assert_err!(EthereumBeaconClient::verify(&message), VerificationError::NotFound); + assert_err!(EthereumBeaconClient::verify(&message), VerificationError::LogNotFound); }); } diff --git a/parachain/primitives/core/src/inbound.rs b/parachain/primitives/core/src/inbound.rs index 8f3d6d6332..bc28c7e3bb 100644 --- a/parachain/primitives/core/src/inbound.rs +++ b/parachain/primitives/core/src/inbound.rs @@ -20,7 +20,7 @@ pub enum VerificationError { /// Execution header is missing HeaderNotFound, /// Log was not found in the verified transaction receipt - NotFound, + LogNotFound, /// Data payload does not decode into a valid Log InvalidLog, /// Unable to verify the transaction receipt with the provided proof From 1186e92b12b0ab8c34a3e16370d36a3fe81c3f55 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 8 Nov 2023 20:25:28 +0200 Subject: [PATCH 08/14] more review feedback --- contracts/src/Assets.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index 3f04a3ba6e..b53a6f6ff5 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -9,7 +9,7 @@ import {SafeTokenTransferFrom} from "./utils/SafeTransfer.sol"; import {AssetsStorage} from "./storage/AssetsStorage.sol"; import {SubstrateTypes} from "./SubstrateTypes.sol"; -import {ParaID, Config, Channel} from "./Types.sol"; +import {ParaID, Config} from "./Types.sol"; import {Address} from "./utils/Address.sol"; /// @title Library for implementing Ethereum->Polkadot ERC20 transfers. From 67a66b1a0f75f9e84f4fa01481c674f818d3dc9f Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 8 Nov 2023 21:20:57 +0200 Subject: [PATCH 09/14] Update polkadot-sdk --- polkadot-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot-sdk b/polkadot-sdk index 1adaaee513..f7fbba7532 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit 1adaaee51314dc7747442b1179a781ffb648d1d0 +Subproject commit f7fbba753247de67d36af870b2c69b8f2efc629a From 884355dad1a9e9d864805290159522f9d6b61809 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Wed, 8 Nov 2023 21:22:34 +0200 Subject: [PATCH 10/14] remove obsolete code --- contracts/src/interfaces/IGateway.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/contracts/src/interfaces/IGateway.sol b/contracts/src/interfaces/IGateway.sol index aaf8e8ee1e..26f565983b 100644 --- a/contracts/src/interfaces/IGateway.sol +++ b/contracts/src/interfaces/IGateway.sol @@ -16,9 +16,6 @@ interface IGateway { // Emitted when an outbound message has been accepted for delivery to a Polkadot parachain event OutboundMessageAccepted(ParaID indexed destination, uint64 nonce, bytes32 indexed messageID, bytes payload); - // Emitted when an dispatched inbound message or an accepted outbound message are associated with one or more topic IDs - event Topic(bytes32 topicID); - // Emitted when an agent has been created for a consensus system on Polkadot event AgentCreated(bytes32 agentID, address agent); From 2c303b221fbb063b50d8a44f37af310409814e31 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Thu, 9 Nov 2023 10:32:13 +0200 Subject: [PATCH 11/14] Remove misc whitespace --- web/packages/test/scripts/set-env.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index 00d1e23fc5..21585af512 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -82,7 +82,6 @@ export DEFAULT_FEE="${ETH_DEFAULT_FEE:-1}" export CREATE_CALL_INDEX="${ETH_CREATE_CALL_INDEX:-0x3500}" - export REGISTER_NATIVE_TOKEN_FEE="${ETH_REGISTER_NATIVE_TOKEN_FEE:-0}" export SEND_NATIVE_TOKEN_FEE="${ETH_SEND_NATIVE_TOKEN_FEE:-0}" From 2fd977717957b20660c9261083a5f3cca76c0595 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Thu, 9 Nov 2023 10:44:47 +0200 Subject: [PATCH 12/14] Add back tests I hastily removed --- .../primitives/router/src/outbound/mod.rs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/parachain/primitives/router/src/outbound/mod.rs b/parachain/primitives/router/src/outbound/mod.rs index 1e91ae1fc3..80e61dae5c 100644 --- a/parachain/primitives/router/src/outbound/mod.rs +++ b/parachain/primitives/router/src/outbound/mod.rs @@ -756,6 +756,71 @@ mod tests { assert_eq!(result, Ok((expected_payload, [0; 32]))); } + #[test] + fn xcm_converter_convert_with_fees_less_than_reserve_yields_success() { + let network = BridgedNetwork::get(); + + let token_address: [u8; 20] = hex!("1000000000000000000000000000000000000000"); + let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000"); + + let asset_location = X1(AccountKey20 { network: None, key: token_address }).into(); + let fee_asset = MultiAsset { id: Concrete(asset_location), fun: Fungible(500) }; + + let assets: MultiAssets = + vec![MultiAsset { id: Concrete(asset_location), fun: Fungible(1000) }].into(); + + let filter: MultiAssetFilter = assets.clone().into(); + + let message: Xcm<()> = vec![ + WithdrawAsset(assets.clone()), + ClearOrigin, + BuyExecution { fees: fee_asset, weight_limit: Unlimited }, + DepositAsset { + assets: filter, + beneficiary: X1(AccountKey20 { network: None, key: beneficiary_address }).into(), + }, + SetTopic([0; 32]), + ] + .into(); + let mut converter = XcmConverter::new(&message, &network); + let expected_payload = AgentExecuteCommand::TransferToken { + token: token_address.into(), + recipient: beneficiary_address.into(), + amount: 1000, + }; + let result = converter.convert(); + assert_eq!(result, Ok((expected_payload, [0; 32]))); + } + + #[test] + fn xcm_converter_convert_without_set_topic_yields_set_topic_expected() { + let network = BridgedNetwork::get(); + + let token_address: [u8; 20] = hex!("1000000000000000000000000000000000000000"); + let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000"); + + let assets: MultiAssets = vec![MultiAsset { + id: Concrete(X1(AccountKey20 { network: None, key: token_address }).into()), + fun: Fungible(1000), + }] + .into(); + let filter: MultiAssetFilter = assets.clone().into(); + + let message: Xcm<()> = vec![ + WithdrawAsset(assets.clone()), + BuyExecution { fees: assets.get(0).unwrap().clone(), weight_limit: Unlimited }, + DepositAsset { + assets: filter, + beneficiary: X1(AccountKey20 { network: None, key: beneficiary_address }).into(), + }, + ClearTopic, + ] + .into(); + let mut converter = XcmConverter::new(&message, &network); + let result = converter.convert(); + assert_eq!(result.err(), Some(XcmConverterError::SetTopicExpected)); + } + #[test] fn xcm_converter_convert_with_partial_message_yields_unexpected_end_of_xcm() { let network = BridgedNetwork::get(); From cf4a83fa3d5319d67a131c0878e1b81b5412b6d9 Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Thu, 9 Nov 2023 16:34:09 +0200 Subject: [PATCH 13/14] Remove obsolete errors from ethereum-beacon-client --- parachain/pallets/ethereum-beacon-client/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/parachain/pallets/ethereum-beacon-client/src/lib.rs b/parachain/pallets/ethereum-beacon-client/src/lib.rs index 9c0d435624..0f3cf025b5 100644 --- a/parachain/pallets/ethereum-beacon-client/src/lib.rs +++ b/parachain/pallets/ethereum-beacon-client/src/lib.rs @@ -134,9 +134,6 @@ pub mod pallet { InvalidAncestryMerkleProof, InvalidBlockRootsRootMerkleProof, HeaderNotFinalized, - MissingHeader, - InvalidProof, - DecodeFailed, BlockBodyHashTreeRootFailed, HeaderHashTreeRootFailed, SyncCommitteeHashTreeRootFailed, From b8a52432fbdc5018901f7664f922e0d43e5251dc Mon Sep 17 00:00:00 2001 From: Vincent Geddes Date: Thu, 9 Nov 2023 17:17:31 +0200 Subject: [PATCH 14/14] Update polkadot-sdk --- polkadot-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot-sdk b/polkadot-sdk index 38754ed566..464bf57bfb 160000 --- a/polkadot-sdk +++ b/polkadot-sdk @@ -1 +1 @@ -Subproject commit 38754ed56624b3e78e9c4c153762b8f74181208b +Subproject commit 464bf57bfb368e3089248d0bec3db75d5f8de613