diff --git a/Cargo.lock b/Cargo.lock index 96041faaf..e3b45b8a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8921,6 +8921,7 @@ dependencies = [ "futures", "native-tls", "sled", + "sp-core", "tokio 1.27.0", "tracing", "tracing-test", diff --git a/crates/event-watcher-traits/Cargo.toml b/crates/event-watcher-traits/Cargo.toml index d1a5270aa..cdcd06cab 100644 --- a/crates/event-watcher-traits/Cargo.toml +++ b/crates/event-watcher-traits/Cargo.toml @@ -27,6 +27,7 @@ native-tls = { workspace = true } webb-proposals = { workspace = true } tracing-test = "0.2" sled = { version = "^0.34" } +sp-core = { workspace = true } [features] default = ["std", "evm", "substrate"] diff --git a/crates/event-watcher-traits/src/substrate/bridge_watcher.rs b/crates/event-watcher-traits/src/substrate/bridge_watcher.rs index 794c66d07..c095d2b20 100644 --- a/crates/event-watcher-traits/src/substrate/bridge_watcher.rs +++ b/crates/event-watcher-traits/src/substrate/bridge_watcher.rs @@ -13,7 +13,7 @@ // limitations under the License. use super::{event_watcher::SubstrateEventWatcher, *}; - +use sp_core::sr25519::Pair as Sr25519Pair; // A Substrate Bridge Watcher is a trait for Signature Bridge Pallet that is not specific for watching events from that pallet, /// instead it watches for commands sent from other event watchers or services, it helps decouple the event watchers /// from the actual action that should be taken depending on the event. @@ -32,6 +32,7 @@ where chain_id: u32, store: Arc, client: Arc, + pair: Sr25519Pair, cmd: BridgeCommand, ) -> webb_relayer_utils::Result<()>; @@ -48,6 +49,7 @@ where &self, chain_id: u32, client: Arc, + pair: Sr25519Pair, store: Arc, ) -> webb_relayer_utils::Result<()> { let backoff = backoff::backoff::Constant::new(Duration::from_secs(1)); @@ -64,6 +66,7 @@ where chain_id, store.clone(), client.clone(), + pair.clone(), cmd, ) .await diff --git a/crates/proposal-signing-backends/src/dkg.rs b/crates/proposal-signing-backends/src/dkg.rs index f1639f07d..7401a8b64 100644 --- a/crates/proposal-signing-backends/src/dkg.rs +++ b/crates/proposal-signing-backends/src/dkg.rs @@ -1,4 +1,3 @@ -use std::borrow::Cow; use std::sync::Arc; use tokio::sync::Mutex; use webb::substrate::dkg_runtime::api::runtime_types::webb_proposals::header::{TypedChainId, ResourceId}; @@ -10,38 +9,27 @@ use webb_proposals::ProposalTrait; use webb::substrate::scale::{Encode, Decode}; use webb_relayer_utils::metric; use webb::substrate::dkg_runtime::api as RuntimeApi; -use webb::substrate::subxt::dynamic::Value; use webb_relayer_store::{QueueStore, SledStore}; use webb_relayer_store::sled::SledQueueKey; -use webb_relayer_types::dynamic_payload::WebbDynamicTxPayload; -use webb::substrate::subxt::tx::{PairSigner}; +use webb::substrate::subxt::tx::PairSigner; use webb::substrate::dkg_runtime::api::runtime_types::sp_core::bounded::bounded_vec::BoundedVec; type DkgConfig = PolkadotConfig; type DkgClient = OnlineClient; /// A ProposalSigningBackend that uses the DKG System for Signing Proposals. +#[derive(typed_builder::TypedBuilder)] pub struct DkgProposalSigningBackend { + #[builder(setter(into))] pub client: DkgClient, pub pair: PairSigner, - pub typed_chain_id: webb_proposals::TypedChainId, /// Something that implements the QueueStore trait. + #[builder(setter(into))] store: Arc, -} - -impl DkgProposalSigningBackend { - pub fn new( - client: OnlineClient, - pair: PairSigner, - typed_chain_id: webb_proposals::TypedChainId, - store: Arc, - ) -> Self { - Self { - client, - pair, - typed_chain_id, - store, - } - } + /// The chain id of the chain that this backend is running on. + /// + /// This used as the source chain id for the proposals. + #[builder(setter(into))] + src_chain_id: webb_proposals::TypedChainId, } //AnchorUpdateProposal for evm @@ -53,9 +41,8 @@ impl super::ProposalSigningBackend for DkgProposalSigningBackend { ) -> webb_relayer_utils::Result { let header = proposal.header(); let resource_id = header.resource_id(); - let src_chain_id = - webb_proposals_typed_chain_converter(self.typed_chain_id); + webb_proposals_typed_chain_converter(self.src_chain_id); let chain_nonce_addrs = RuntimeApi::storage() .dkg_proposals() .chain_nonces(&src_chain_id); @@ -97,49 +84,57 @@ impl super::ProposalSigningBackend for DkgProposalSigningBackend { proposal: &(impl ProposalTrait + Sync + Send + 'static), _metrics: Arc>, ) -> webb_relayer_utils::Result<()> { + let my_chain_id_addr = + RuntimeApi::constants().dkg_proposals().chain_identifier(); + let my_chain_id = self.client.constants().at(&my_chain_id_addr)?; + let my_chain_id = match my_chain_id { + TypedChainId::Substrate(chain_id) => chain_id, + TypedChainId::PolkadotParachain(chain_id) => chain_id, + TypedChainId::KusamaParachain(chain_id) => chain_id, + _ => return Err(webb_relayer_utils::Error::Generic( + "dkg proposal signing backend only supports substrate chains", + )), + }; let tx_api = RuntimeApi::tx().dkg_proposals(); let resource_id = proposal.header().resource_id(); let nonce = proposal.header().nonce(); let src_chain_id = - webb_proposals_typed_chain_converter(self.typed_chain_id); - let nonce = Nonce::decode(&mut nonce.encode().as_slice())?; + webb_proposals_typed_chain_converter(self.src_chain_id); tracing::debug!( - nonce = %hex::encode(nonce.encode()), + ?nonce, resource_id = %hex::encode(resource_id.into_bytes()), - src_chain_id = ?self.typed_chain_id, + src_chain_id = ?self.src_chain_id, proposal = %hex::encode(proposal.to_vec()), "sending proposal to DKG runtime" ); - let xt = tx_api.acknowledge_proposal( + let nonce = Nonce::decode(&mut nonce.encode().as_slice())?; + + let acknowledge_proposal_tx = tx_api.acknowledge_proposal( nonce.clone(), src_chain_id, ResourceId(resource_id.into_bytes()), BoundedVec(proposal.to_vec()), ); - // webb dynamic payload - let execute_proposal_tx = WebbDynamicTxPayload { - pallet_name: Cow::Borrowed("DKGProposals"), - call_name: Cow::Borrowed("acknowledge_proposal"), - fields: vec![ - Value::u128(u128::from(nonce.0)), - Value::u128(u128::from(self.typed_chain_id.chain_id())), - Value::from_bytes( - ResourceId(resource_id.into_bytes()).encode(), - ), - Value::from_bytes(BoundedVec(proposal.to_vec()).encode()), - ], - }; - let data_hash = utils::keccak256(xt.call_data().encode()); + + let signer = &self.pair; + let signed_acknowledge_proposal_tx = self + .client + .tx() + .create_signed(&acknowledge_proposal_tx, signer, Default::default()) + .await?; + + let data_hash = + utils::keccak256(acknowledge_proposal_tx.call_data().encode()); let tx_key = SledQueueKey::from_substrate_with_custom_key( - self.typed_chain_id.underlying_chain_id(), + my_chain_id, make_acknowledge_proposal_key(data_hash), ); - // Enqueue WebbDynamicTxPayload in protocol-substrate transaction queue - QueueStore::::enqueue_item( + // Enqueue transaction in protocol-substrate transaction queue + QueueStore::>::enqueue_item( &self.store, tx_key, - execute_proposal_tx, + signed_acknowledge_proposal_tx.into_encoded(), )?; Ok(()) diff --git a/crates/relayer-types/src/dynamic_payload.rs b/crates/relayer-types/src/dynamic_payload.rs deleted file mode 100644 index f7b0f65a5..000000000 --- a/crates/relayer-types/src/dynamic_payload.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 Webb Technologies Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use serde::{Deserialize, Serialize}; -use std::borrow::Cow; -use webb::substrate::subxt::dynamic::Value; - -/// This represents a intermediary type to store `DynamicTxPayload`. -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct WebbDynamicTxPayload<'a> { - /// Pallet name - pub pallet_name: Cow<'a, str>, - /// Extrinsic name - pub call_name: Cow<'a, str>, - /// Extrinsic params - pub fields: Vec>, -} diff --git a/crates/relayer-types/src/lib.rs b/crates/relayer-types/src/lib.rs index cd07a09c8..d91751840 100644 --- a/crates/relayer-types/src/lib.rs +++ b/crates/relayer-types/src/lib.rs @@ -1,4 +1,3 @@ -pub mod dynamic_payload; pub mod etherscan_api; pub mod mnemonic; pub mod private_key; diff --git a/crates/tx-queue/src/substrate/substrate_tx_queue.rs b/crates/tx-queue/src/substrate/substrate_tx_queue.rs index d25b72155..80ba2b4bf 100644 --- a/crates/tx-queue/src/substrate/substrate_tx_queue.rs +++ b/crates/tx-queue/src/substrate/substrate_tx_queue.rs @@ -15,7 +15,9 @@ use futures::StreamExt; use futures::TryFutureExt; use rand::Rng; +use webb::substrate::subxt; use webb::substrate::subxt::config::ExtrinsicParams; +use webb::substrate::subxt::tx::SubmittableExtrinsic; use webb_relayer_context::RelayerContext; use webb_relayer_store::sled::SledQueueKey; use webb_relayer_store::QueueStore; @@ -24,28 +26,24 @@ use std::sync::Arc; use std::time::Duration; use sp_core::sr25519; -use std::marker::PhantomData; -use webb::substrate::subxt; -use webb::substrate::subxt::tx::{PairSigner, TxStatus as TransactionStatus}; -use webb_relayer_types::dynamic_payload::WebbDynamicTxPayload; +use webb::substrate::subxt::tx::TxStatus as TransactionStatus; /// The SubstrateTxQueue stores transaction call params in bytes so the relayer can process them later. /// This prevents issues such as creating transactions with the same nonce. /// Randomized sleep intervals are used to prevent relayers from submitting /// the same transaction. #[derive(Clone)] -pub struct SubstrateTxQueue<'a, S> +pub struct SubstrateTxQueue where - S: QueueStore, Key = SledQueueKey>, + S: QueueStore, Key = SledQueueKey>, { ctx: RelayerContext, chain_id: u32, store: Arc, - _marker: PhantomData<&'a ()>, } -impl<'a, S> SubstrateTxQueue<'a, S> +impl SubstrateTxQueue where - S: QueueStore, Key = SledQueueKey>, + S: QueueStore, Key = SledQueueKey>, { /// Creates a new SubstrateTxQueue instance. /// @@ -61,7 +59,6 @@ where ctx, chain_id, store, - _marker: PhantomData {}, } } /// Starts the SubstrateTxQueue service. @@ -96,10 +93,6 @@ where .substrate_provider::(&chain_id.to_string()) .await?; - // get pair - let pair = self.ctx.substrate_wallet(&chain_id.to_string()).await?; - let signer = PairSigner::new(pair); - tracing::event!( target: webb_relayer_utils::probe::TARGET, tracing::Level::DEBUG, @@ -113,26 +106,16 @@ where let task = || async { loop { tracing::trace!("Checking for any txs in the queue ..."); - // dequeue transaction call data. This are call params stored as bytes + // dequeue signed transaction let maybe_call_data = store.dequeue_item( SledQueueKey::from_substrate_chain_id(chain_id), )?; if let Some(payload) = maybe_call_data { - let dynamic_tx_payload = subxt::dynamic::tx( - payload.pallet_name, - payload.call_name, - payload.fields, + let signed_extrinsic = SubmittableExtrinsic::from_bytes( + client.clone(), + payload, ); - let signed_extrinsic = client - .tx() - .create_signed( - &dynamic_tx_payload, - &signer, - Default::default(), - ) - .map_err(Into::into) - .map_err(backoff::Error::transient) - .await?; + // dry run test let dry_run_outcome = signed_extrinsic.dry_run(None).await; match dry_run_outcome { @@ -161,12 +144,8 @@ where } } // watch_extrinsic submits and returns transaction subscription - let mut progress = client - .tx() - .sign_and_submit_then_watch_default( - &dynamic_tx_payload, - &signer, - ) + let mut progress = signed_extrinsic + .submit_and_watch() .map_err(Into::into) .map_err(backoff::Error::transient) .await?; diff --git a/event-watchers/substrate/src/signature_bridge_watcher.rs b/event-watchers/substrate/src/signature_bridge_watcher.rs index 2e8fdc5fa..c717bcb62 100644 --- a/event-watchers/substrate/src/signature_bridge_watcher.rs +++ b/event-watchers/substrate/src/signature_bridge_watcher.rs @@ -19,21 +19,20 @@ use sp_core::hashing::keccak_256; use webb::substrate::subxt::config::SubstrateConfig; use webb::substrate::subxt::events::StaticEvent; -use webb::substrate::subxt::{self, dynamic::Value, OnlineClient}; - -use webb::substrate::protocol_substrate_runtime::api::signature_bridge::calls::{ExecuteProposal,SetMaintainer}; -use webb_event_watcher_traits::substrate::{SubstrateBridgeWatcher, EventHandler}; +use sp_core::sr25519::Pair as Sr25519Pair; +use webb::substrate::subxt::tx::PairSigner; +use webb::substrate::subxt::{self, OnlineClient}; +use webb_event_watcher_traits::substrate::{ + EventHandler, SubstrateBridgeWatcher, +}; use webb_event_watcher_traits::SubstrateEventWatcher; -use webb_relayer_store::sled::{SledQueueKey,SledStore}; +use webb_relayer_store::sled::{SledQueueKey, SledStore}; use webb_relayer_store::{BridgeCommand, QueueStore}; use webb::evm::ethers::utils; use webb::substrate::protocol_substrate_runtime::api as RuntimeApi; use webb::substrate::protocol_substrate_runtime::api::signature_bridge::events::MaintainerSet; - -use std::borrow::Cow; use webb::substrate::scale::Encode; -use webb_relayer_types::dynamic_payload::WebbDynamicTxPayload; use webb_relayer_utils::{metric, Error}; use webb::substrate::protocol_substrate_runtime::api::runtime_types::sp_core::bounded::bounded_vec::BoundedVec; @@ -110,6 +109,7 @@ impl SubstrateBridgeWatcher for SubstrateBridgeEventWatcher { chain_id: u32, store: Arc, client: Arc, + pair: Sr25519Pair, cmd: BridgeCommand, ) -> webb_relayer_utils::Result<()> { use BridgeCommand::*; @@ -120,6 +120,7 @@ impl SubstrateBridgeWatcher for SubstrateBridgeEventWatcher { chain_id, store, client.clone(), + pair.clone(), (data, signature), ) .await? @@ -133,6 +134,7 @@ impl SubstrateBridgeWatcher for SubstrateBridgeEventWatcher { chain_id, store, client.clone(), + pair.clone(), (public_key, nonce, signature), ) .await? @@ -152,6 +154,7 @@ where chain_id: u32, store: Arc<>::Store>, api: Arc<>::Client>, + pair: Sr25519Pair, (proposal_data, signature): (Vec, Vec), ) -> webb_relayer_utils::Result<()> { let proposal_data_hex = hex::encode(&proposal_data); @@ -210,37 +213,35 @@ where let typed_chain_id = webb_proposals::TypedChainId::Substrate(chain_id); - // Enqueue transaction call data in protocol-substrate transaction queue - let execute_proposal_call = ExecuteProposal { - src_id: typed_chain_id.chain_id(), - proposal_data: BoundedVec(proposal_data.clone()), - signature: BoundedVec(signature.clone()), - }; - // webb dynamic payload - let execute_proposal_tx = WebbDynamicTxPayload { - pallet_name: Cow::Borrowed("SignatureBridge"), - call_name: Cow::Borrowed("execute_proposal"), - fields: vec![ - Value::u128(u128::from(typed_chain_id.chain_id())), - Value::from_bytes(proposal_data), - Value::from_bytes(signature), - ], - }; + let execute_proposal_tx = + RuntimeApi::tx().signature_bridge().execute_proposal( + typed_chain_id.chain_id(), + BoundedVec(proposal_data), + BoundedVec(signature), + ); + + let signer: PairSigner = + subxt::tx::PairSigner::new(pair); + let signed_execute_proposal_tx = api + .tx() + .create_signed(&execute_proposal_tx, &signer, Default::default()) + .await?; - let data_hash = utils::keccak256(execute_proposal_call.encode()); + // Enqueue transaction in protocol-substrate transaction queue + let data_hash = + utils::keccak256(execute_proposal_tx.call_data().encode()); let tx_key = SledQueueKey::from_substrate_with_custom_key( chain_id, make_execute_proposal_key(data_hash), ); - // Enqueue WebbDynamicTxPayload in protocol-substrate transaction queue - QueueStore::::enqueue_item( + QueueStore::>::enqueue_item( &store, tx_key, - execute_proposal_tx, + signed_execute_proposal_tx.into_encoded(), )?; tracing::debug!( data_hash = ?hex::encode(data_hash), - "Enqueued execute-proposal call for execution through protocol-substrate tx queue", + "Enqueued execute-proposal tx for execution through protocol-substrate tx queue", ); Ok(()) } @@ -251,6 +252,7 @@ where chain_id: u32, store: Arc<>::Store>, api: Arc<>::Client>, + pair: Sr25519Pair, (public_key, nonce, signature): (Vec, u32, Vec), ) -> webb_relayer_utils::Result<()> { let new_maintainer = public_key.clone(); @@ -317,36 +319,32 @@ where let mut message = nonce.to_be_bytes().to_vec(); message.extend_from_slice(&new_maintainer); - let set_maintainer_call = SetMaintainer { - message: BoundedVec(message.clone()), - signature: BoundedVec(signature.clone()), - }; + let set_maintainer_tx = RuntimeApi::tx() + .signature_bridge() + .set_maintainer(BoundedVec(message), BoundedVec(signature)); - // webb dynamic payload - tracing::debug!("DKG Message Payload : {:?}", message); - let set_maintainer_tx = WebbDynamicTxPayload { - pallet_name: Cow::Borrowed("SignatureBridge"), - call_name: Cow::Borrowed("set_maintainer"), - fields: vec![ - Value::from_bytes(message), - Value::from_bytes(signature), - ], - }; + let signer: PairSigner = + subxt::tx::PairSigner::new(pair); + let signed_set_maintainer_tx = api + .tx() + .create_signed(&set_maintainer_tx, &signer, Default::default()) + .await?; - let data_hash = utils::keccak256(set_maintainer_call.encode()); + let data_hash = + utils::keccak256(set_maintainer_tx.call_data().encode()); let tx_key = SledQueueKey::from_substrate_with_custom_key( chain_id, make_execute_proposal_key(data_hash), ); - // Enqueue WebbDynamicTxPayload in protocol-substrate transaction queue - QueueStore::::enqueue_item( + // Enqueue transaction in protocol-substrate transaction queue + QueueStore::>::enqueue_item( &store, tx_key, - set_maintainer_tx, + signed_set_maintainer_tx.into_encoded(), )?; tracing::debug!( data_hash = ?hex::encode(data_hash), - "Enqueued set-maintainer call for execution through protocol-substrate tx queue", + "Enqueued set-maintainer tx for execution through protocol-substrate tx queue", ); Ok(()) } diff --git a/services/webb-relayer/src/service/mod.rs b/services/webb-relayer/src/service/mod.rs index 2aa4901e3..e273683c7 100644 --- a/services/webb-relayer/src/service/mod.rs +++ b/services/webb-relayer/src/service/mod.rs @@ -133,12 +133,12 @@ pub async fn make_proposal_signing_backend( ) .await?; let pair = ctx.substrate_wallet(&c.chain_id.to_string()).await?; - let backend = DkgProposalSigningBackend::new( - dkg_client, - subxt::tx::PairSigner::new(pair), - typed_chain_id, - store.clone(), - ); + let backend = DkgProposalSigningBackend::builder() + .client(dkg_client) + .pair(subxt::tx::PairSigner::new(pair)) + .src_chain_id(typed_chain_id) + .store(store.clone()) + .build(); Ok(ProposalSigningBackendSelector::Dkg(backend)) } Some(ProposalSigningBackendConfig::Mocked(mocked)) => { diff --git a/services/webb-relayer/src/service/substrate.rs b/services/webb-relayer/src/service/substrate.rs index dfc177b72..3eec10f42 100644 --- a/services/webb-relayer/src/service/substrate.rs +++ b/services/webb-relayer/src/service/substrate.rs @@ -503,6 +503,7 @@ pub async fn start_substrate_signature_bridge_events_watcher( } let mut shutdown_signal = ctx.shutdown_signal(); let my_config = config.clone(); + let pair = ctx.substrate_wallet(&chain_id.to_string()).await?; let task = async move { tracing::debug!( "Substrate Signature Bridge watcher for ({}) Started.", @@ -523,6 +524,7 @@ pub async fn start_substrate_signature_bridge_events_watcher( &substrate_bridge_watcher, chain_id, client.into(), + pair.clone(), store.clone(), ); tokio::select! {