diff --git a/Cargo.lock b/Cargo.lock index f024a6e33..2e3f618ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9373,7 +9373,10 @@ dependencies = [ "sp-runtime", "tokio 1.28.1", "tracing", + "tracing-subscriber 0.3.16", + "url", "webb 0.5.24", + "webb-relayer-config", "webb-relayer-context", "webb-relayer-store", "webb-relayer-types 0.1.0", @@ -9456,6 +9459,8 @@ dependencies = [ "native-tls", "prometheus 0.13.3", "reqwest", + "serde", + "serde_bytes", "serde_json", "serde_path_to_error", "sled", diff --git a/Cargo.toml b/Cargo.toml index b35290174..edaa3657c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,7 @@ libsecp256k1 = "0.7.1" serde = { version = "^1", default-features = false, features = ["derive"] } glob = "^0.3" serde_path_to_error = "0.1.9" +serde_bytes = "0.11" # eth2 light client crates eth-rpc-client = { package = "eth_rpc_client", git = "https://github.com/webb-tools/pallet-eth2-light-client" } diff --git a/crates/event-watcher-traits/src/substrate/bridge_watcher.rs b/crates/event-watcher-traits/src/substrate/bridge_watcher.rs index 83f017639..0686f8de1 100644 --- a/crates/event-watcher-traits/src/substrate/bridge_watcher.rs +++ b/crates/event-watcher-traits/src/substrate/bridge_watcher.rs @@ -60,9 +60,8 @@ where webb_proposals::TypedChainId::Substrate(chain_id); let bridge_key = BridgeKey::new(typed_chain_id); let key = SledQueueKey::from_bridge_key(bridge_key); - let client = ctx - .substrate_provider::(&chain_id.to_string()) - .await?; + let client = + ctx.substrate_provider::(chain_id).await?; let client = Arc::new(client); loop { diff --git a/crates/event-watcher-traits/src/substrate/event_watcher.rs b/crates/event-watcher-traits/src/substrate/event_watcher.rs index 388b8716b..d9a82fe04 100644 --- a/crates/event-watcher-traits/src/substrate/event_watcher.rs +++ b/crates/event-watcher-traits/src/substrate/event_watcher.rs @@ -156,9 +156,8 @@ where }; let metrics_clone = metrics.clone(); let task = || async { - let maybe_client = ctx - .substrate_provider::(&chain_id.to_string()) - .await; + let maybe_client = + ctx.substrate_provider::(chain_id).await; let client = match maybe_client { Ok(client) => client, Err(err) => { diff --git a/crates/proposal-signing-backends/src/dkg.rs b/crates/proposal-signing-backends/src/dkg.rs index 2b81034de..aebb5cc6e 100644 --- a/crates/proposal-signing-backends/src/dkg.rs +++ b/crates/proposal-signing-backends/src/dkg.rs @@ -4,7 +4,6 @@ use webb::substrate::tangle_runtime::api::runtime_types::bounded_collections::bo use webb::substrate::tangle_runtime::api::runtime_types::webb_proposals::header::{TypedChainId, ResourceId}; use webb::substrate::tangle_runtime::api::runtime_types::webb_proposals::nonce::Nonce; use webb::substrate::subxt::{OnlineClient, PolkadotConfig}; -use sp_core::sr25519::Pair as Sr25519Pair; use webb::evm::ethers::utils; use webb::substrate::tangle_runtime::api::runtime_types::webb_proposals::proposal::{Proposal, ProposalKind}; use webb_proposals::ProposalTrait; @@ -13,7 +12,7 @@ use webb_relayer_utils::metric; use webb::substrate::tangle_runtime::api as RuntimeApi; use webb_relayer_store::{QueueStore, SledStore}; use webb_relayer_store::sled::SledQueueKey; -use webb::substrate::subxt::tx::PairSigner; +use webb_relayer_utils::static_tx_payload::TypeErasedStaticTxPayload; type DkgConfig = PolkadotConfig; type DkgClient = OnlineClient; @@ -22,7 +21,6 @@ type DkgClient = OnlineClient; pub struct DkgProposalSigningBackend { #[builder(setter(into))] pub client: DkgClient, - pub pair: PairSigner, /// Something that implements the QueueStore trait. #[builder(setter(into))] store: Arc, @@ -102,10 +100,10 @@ impl super::ProposalSigningBackend for DkgProposalSigningBackend { let src_chain_id = webb_proposals_typed_chain_converter(self.src_chain_id); tracing::debug!( - ?nonce, - resource_id = %hex::encode(resource_id.into_bytes()), + nonce = nonce.0, + resource_id = hex::encode(resource_id.into_bytes()), src_chain_id = ?self.src_chain_id, - proposal = %hex::encode(proposal.to_vec()), + proposal = hex::encode(proposal.to_vec()), "sending proposal to DKG runtime" ); @@ -115,41 +113,21 @@ impl super::ProposalSigningBackend for DkgProposalSigningBackend { data: BoundedVec(proposal.to_vec()), }; let acknowledge_proposal_tx = tx_api.acknowledge_proposal( - nonce.clone(), + nonce, src_chain_id, ResourceId(resource_id.into_bytes()), unsigned_proposal, ); - let signer = &self.pair; - let maybe_signed_acknowledge_proposal_tx = self - .client - .tx() - .create_signed(&acknowledge_proposal_tx, signer, Default::default()) - .await; - let signed_acknowledge_proposal_tx = - match maybe_signed_acknowledge_proposal_tx { - Ok(tx) => tx, - Err(e) => { - tracing::error!(?e, "failed to sign tx"); - return Err(webb_relayer_utils::Error::Generic( - "failed to sign tx", - )); - } - }; let data_hash = utils::keccak256(acknowledge_proposal_tx.call_data().encode()); let tx_key = SledQueueKey::from_substrate_with_custom_key( my_chain_id, make_acknowledge_proposal_key(data_hash), ); + let tx = TypeErasedStaticTxPayload::try_from(acknowledge_proposal_tx)?; // Enqueue transaction in protocol-substrate transaction queue - QueueStore::>::enqueue_item( - &self.store, - tx_key, - signed_acknowledge_proposal_tx.into_encoded(), - )?; - + QueueStore::enqueue_item(&self.store, tx_key, tx)?; Ok(()) } } diff --git a/crates/proposal-signing-backends/src/proposal_handler.rs b/crates/proposal-signing-backends/src/proposal_handler.rs index be7cd14a3..5f7470c07 100644 --- a/crates/proposal-signing-backends/src/proposal_handler.rs +++ b/crates/proposal-signing-backends/src/proposal_handler.rs @@ -45,15 +45,15 @@ where Ok(()) } -// create anchor update proposal for Evm target system +/// create anchor update proposal for Evm target system #[tracing::instrument( skip_all, fields( proposal_type = "AnchorUpdateProposal", from = ?src_resource_id.typed_chain_id(), to = ?target_resource_id.typed_chain_id(), - leaf_index, - merkle_root = ?hex::encode(merkle_root), + nonce = leaf_index, + merkle_root = hex::encode(merkle_root), ) )] pub fn evm_anchor_update_proposal( @@ -82,6 +82,16 @@ pub fn evm_anchor_update_proposal( } // create anchor update proposal for substrate system +#[tracing::instrument( + skip_all, + fields( + proposal_type = "AnchorUpdateProposal", + from = ?src_resource_id.typed_chain_id(), + to = ?target_resource_id.typed_chain_id(), + nonce = leaf_index, + merkle_root = hex::encode(merkle_root), + ) +)] pub fn substrate_anchor_update_proposal( merkle_root: [u8; 32], leaf_index: u32, diff --git a/crates/relayer-context/src/lib.rs b/crates/relayer-context/src/lib.rs index 72d42cfa3..1561bb6ab 100644 --- a/crates/relayer-context/src/lib.rs +++ b/crates/relayer-context/src/lib.rs @@ -202,12 +202,14 @@ impl RelayerContext { /// /// * `chain_id` - A string representing the chain ID. #[cfg(feature = "substrate")] - pub async fn substrate_provider( + pub async fn substrate_provider>( &self, - chain_id: &str, + chain_id: I, ) -> webb_relayer_utils::Result> { + let chain_id: types::U256 = chain_id.into(); + let chain_name = chain_id.to_string(); let node_config = - self.config.substrate.get(chain_id).ok_or_else(|| { + self.config.substrate.get(&chain_name).ok_or_else(|| { webb_relayer_utils::Error::NodeNotFound { chain_id: chain_id.to_string(), } @@ -224,18 +226,18 @@ impl RelayerContext { /// /// * `chain_id` - A string representing the chain ID. #[cfg(feature = "substrate")] - pub async fn substrate_wallet( + pub async fn substrate_wallet>( &self, - chain_id: &str, + chain_id: I, ) -> webb_relayer_utils::Result { - let node_config = self - .config - .substrate - .get(chain_id) - .cloned() - .ok_or_else(|| webb_relayer_utils::Error::NodeNotFound { - chain_id: chain_id.to_string(), - })?; + let chain_id: types::U256 = chain_id.into(); + let chain_name = chain_id.to_string(); + let node_config = + self.config.substrate.get(&chain_name).cloned().ok_or_else( + || webb_relayer_utils::Error::NodeNotFound { + chain_id: chain_id.to_string(), + }, + )?; let suri_key = node_config .suri .ok_or(webb_relayer_utils::Error::MissingSecrets)?; diff --git a/crates/relayer-types/src/suri.rs b/crates/relayer-types/src/suri.rs index 435113cc6..c3a0ff74d 100644 --- a/crates/relayer-types/src/suri.rs +++ b/crates/relayer-types/src/suri.rs @@ -4,7 +4,7 @@ use sp_core::Pair; /// [`Substrate Uri`](https://polkadot.js.org/docs/keyring/start/suri/) #[derive(Clone)] -pub struct Suri(Sr25519Pair); +pub struct Suri(pub Sr25519Pair); impl std::fmt::Debug for Suri { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/crates/relayer-utils/Cargo.toml b/crates/relayer-utils/Cargo.toml index c1dfa559a..7dfe71ea3 100644 --- a/crates/relayer-utils/Cargo.toml +++ b/crates/relayer-utils/Cargo.toml @@ -17,6 +17,8 @@ backoff = { workspace = true } serde_path_to_error = { workspace = true } webb-proposals = { workspace = true } webb = { workspace = true } +serde = { workspace = true } +serde_bytes = { workspace = true } # Used by ethers (but we need it to be vendored with the lib). native-tls = { workspace = true, optional = true } glob = { workspace = true } diff --git a/crates/relayer-utils/src/lib.rs b/crates/relayer-utils/src/lib.rs index 89a57281c..62d4aa2a7 100644 --- a/crates/relayer-utils/src/lib.rs +++ b/crates/relayer-utils/src/lib.rs @@ -27,6 +27,8 @@ pub mod metric; pub mod probe; /// Retry functionality pub mod retry; +/// type-erased StaticTxPayload for Substrate Transaction queue. +pub mod static_tx_payload; /// An enum of all possible errors that could be encountered during the execution of the Webb /// Relayer. @@ -202,6 +204,11 @@ pub enum Error { /// Invalid Merkle root #[error("Invalid Merkle root at index {}", _0)] InvalidMerkleRootError(u32), + /// Missing Static Transaction Validation Details + /// This error is raised when the static transaction validation details + /// are missing. + #[error("Missing Substrate Static Transaction Validation Details")] + MissingValidationDetails, } /// A type alias for the result for webb relayer, that uses the `Error` enum. diff --git a/crates/relayer-utils/src/static_tx_payload.rs b/crates/relayer-utils/src/static_tx_payload.rs new file mode 100644 index 000000000..31aa86f0e --- /dev/null +++ b/crates/relayer-utils/src/static_tx_payload.rs @@ -0,0 +1,72 @@ +use core::fmt; + +use webb::substrate::{ + scale::Encode, + subxt::tx::{StaticTxPayload, TxPayload}, +}; + +#[derive(Clone, serde::Serialize, serde::Deserialize)] +pub struct TypeErasedStaticTxPayload { + pub pallet_name: String, + pub call_name: String, + #[serde(with = "serde_bytes")] + pub call_data: Vec, +} + +impl std::fmt::Debug for TypeErasedStaticTxPayload { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TypeErasedStaticTxPayload") + .field("pallet_name", &self.pallet_name) + .field("call_name", &self.call_name) + .field("call_data", &hex::encode(&self.call_data)) + .finish() + } +} + +impl fmt::Display for TypeErasedStaticTxPayload { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}.{}({})", + self.pallet_name, + self.call_name, + hex::encode(&self.call_data) + ) + } +} + +impl TryFrom> + for TypeErasedStaticTxPayload +{ + type Error = super::Error; + fn try_from( + payload: StaticTxPayload, + ) -> Result { + let details = payload + .validation_details() + .ok_or_else(|| Self::Error::MissingValidationDetails)?; + let call_data = payload.call_data().encode(); + Ok(Self { + pallet_name: details.pallet_name.to_owned(), + call_name: details.call_name.to_owned(), + call_data, + }) + } +} + +impl TxPayload for TypeErasedStaticTxPayload { + fn encode_call_data_to( + &self, + metadata: &webb::substrate::subxt::Metadata, + out: &mut Vec, + ) -> Result<(), webb::substrate::subxt::Error> { + let pallet = metadata.pallet(&self.pallet_name)?; + let pallet_index = pallet.index(); + let call_index = pallet.call_index(&self.call_name)?; + + pallet_index.encode_to(out); + call_index.encode_to(out); + out.extend_from_slice(&self.call_data); + Ok(()) + } +} diff --git a/crates/tx-queue/Cargo.toml b/crates/tx-queue/Cargo.toml index ccc76f43b..f686b4144 100644 --- a/crates/tx-queue/Cargo.toml +++ b/crates/tx-queue/Cargo.toml @@ -36,3 +36,8 @@ default = ["std", "evm", "substrate"] std = [] evm = ["webb-relayer-context/evm"] substrate = ["webb-relayer-context/substrate", "sp-core", "sp-runtime"] + +[dev-dependencies] +webb-relayer-config = { workspace = true } +url = { workspace = true } +tracing-subscriber = { workspace = true } diff --git a/crates/tx-queue/src/evm/evm_tx_queue.rs b/crates/tx-queue/src/evm/evm_tx_queue.rs index 862f1df3d..a540184db 100644 --- a/crates/tx-queue/src/evm/evm_tx_queue.rs +++ b/crates/tx-queue/src/evm/evm_tx_queue.rs @@ -105,7 +105,6 @@ where let metrics_clone = self.ctx.metrics.clone(); let task = || async { loop { - // tracing::trace!("Checking for any txs in the queue ..."); let maybe_tx = store .dequeue_item(SledQueueKey::from_evm_chain_id(chain_id))?; let maybe_explorer = &chain_config.explorer; @@ -115,6 +114,7 @@ where raw_tx.set_chain_id(U64::from(chain_id)).clone(); let my_tx_hash = raw_tx.sighash(); tx_hash = my_tx_hash; + tracing::debug!(?tx_hash, tx = ?raw_tx, "Found tx in queue"); // dry run test let dry_run_outcome = client.call(&raw_tx.clone(), None).await; diff --git a/crates/tx-queue/src/substrate/mod.rs b/crates/tx-queue/src/substrate/mod.rs index bc9b4eb5e..1e2c7d1c9 100644 --- a/crates/tx-queue/src/substrate/mod.rs +++ b/crates/tx-queue/src/substrate/mod.rs @@ -15,3 +15,88 @@ mod substrate_tx_queue; #[doc(hidden)] pub use substrate_tx_queue::*; + +#[cfg(test)] +mod tests { + use std::{collections::HashMap, sync::Arc}; + + use sp_core::{sr25519::Pair as Sr25519Pair, Pair}; + use webb::substrate::subxt::PolkadotConfig; + use webb::substrate::tangle_runtime::api as RuntimeApi; + use webb_relayer_store::sled::SledQueueKey; + use webb_relayer_store::QueueStore; + use webb_relayer_types::suri::Suri; + use webb_relayer_utils::static_tx_payload::TypeErasedStaticTxPayload; + + use super::*; + + pub fn setup_tracing() -> tracing::subscriber::DefaultGuard { + // Setup tracing for tests + let env_filter = tracing_subscriber::EnvFilter::builder() + .with_default_directive( + tracing_subscriber::filter::LevelFilter::DEBUG.into(), + ) + .from_env_lossy(); + let s = tracing_subscriber::fmt() + .with_env_filter(env_filter) + .with_test_writer() + .without_time() + .with_target(false) + .compact() + .finish(); + tracing::subscriber::set_default(s) + } + + #[tokio::test] + #[ignore = "needs substrate node"] + async fn should_handle_many_txs() -> webb_relayer_utils::Result<()> { + let _guard = setup_tracing(); + let chain_id = 1081u32; + let config = webb_relayer_config::WebbRelayerConfig { + substrate: HashMap::from([( + chain_id.to_string(), + webb_relayer_config::substrate::SubstrateConfig { + name: String::from("tangle"), + enabled: true, + http_endpoint: "http://localhost:9933" + .parse::() + .unwrap() + .into(), + ws_endpoint: "ws://localhost:9944" + .parse::() + .unwrap() + .into(), + explorer: None, + chain_id, + suri: Some(Suri( + Sr25519Pair::from_string_with_seed("//Alice", None) + .unwrap() + .0, + )), + beneficiary: None, + pallets: Default::default(), + tx_queue: Default::default(), + }, + )]), + ..Default::default() + }; + let store = webb_relayer_store::SledStore::temporary()?; + let context = + webb_relayer_context::RelayerContext::new(config, store.clone())?; + let store = Arc::new(store); + let tx_queue = SubstrateTxQueue::new(context, chain_id, store.clone()); + let _handle = tokio::spawn(tx_queue.run::()); + let tx_count = 5; + let tx_api = RuntimeApi::tx().system(); + for i in 0..tx_count { + let tx = tx_api + .remark_with_event(format!("tx {}", i).as_bytes().to_vec()); + let tx = TypeErasedStaticTxPayload::try_from(tx)?; + let tx_key = SledQueueKey::from_substrate_chain_id(chain_id); + QueueStore::enqueue_item(&store, tx_key, tx)?; + } + // Wait for txs to be processed. + tokio::time::sleep(tokio::time::Duration::from_secs(120)).await; + Ok(()) + } +} diff --git a/crates/tx-queue/src/substrate/substrate_tx_queue.rs b/crates/tx-queue/src/substrate/substrate_tx_queue.rs index 2bd991e5e..e0f77b3c9 100644 --- a/crates/tx-queue/src/substrate/substrate_tx_queue.rs +++ b/crates/tx-queue/src/substrate/substrate_tx_queue.rs @@ -17,11 +17,11 @@ use futures::TryFutureExt; use rand::Rng; use webb::substrate::subxt; use webb::substrate::subxt::config::ExtrinsicParams; -use webb::substrate::subxt::tx::SubmittableExtrinsic; use webb::substrate::subxt::PolkadotConfig; use webb_relayer_context::RelayerContext; use webb_relayer_store::sled::SledQueueKey; use webb_relayer_store::QueueStore; +use webb_relayer_utils::static_tx_payload::TypeErasedStaticTxPayload; use std::sync::Arc; use std::time::Duration; @@ -36,15 +36,16 @@ use webb::substrate::subxt::tx::TxStatus as TransactionStatus; #[derive(Clone)] pub struct SubstrateTxQueue where - S: QueueStore, Key = SledQueueKey>, + S: QueueStore, { ctx: RelayerContext, chain_id: u32, store: Arc, } + impl SubstrateTxQueue where - S: QueueStore, Key = SledQueueKey>, + S: QueueStore, { /// Creates a new SubstrateTxQueue instance. /// @@ -103,7 +104,7 @@ where // Tangle node connection let maybe_client = self .ctx - .substrate_provider::(&chain_id.to_string()) + .substrate_provider::(chain_id) .await; let client = match maybe_client { Ok(client) => client, @@ -115,18 +116,20 @@ where return Err(backoff::Error::transient(err)); } }; + let pair = self.ctx.substrate_wallet(chain_id).await?; + let signer = subxt::tx::PairSigner::::new(pair); loop { - tracing::trace!("Checking for any txs in the queue ..."); // dequeue signed transaction - let maybe_call_data = store.dequeue_item( + let tx_call_data = store.dequeue_item( SledQueueKey::from_substrate_chain_id(chain_id), )?; - if let Some(payload) = maybe_call_data { - let signed_extrinsic = SubmittableExtrinsic::from_bytes( - client.clone(), - payload, - ); - + if let Some(payload) = tx_call_data { + let signed_extrinsic = client + .tx() + .create_signed(&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 { @@ -137,6 +140,7 @@ where kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", chain_id = %chain_id, + tx = %payload, dry_run = "passed" ); } @@ -147,6 +151,7 @@ where kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", chain_id = %chain_id, + tx = %payload, errored = true, error = %err, dry_run = "failed" @@ -157,6 +162,19 @@ where // watch_extrinsic submits and returns transaction subscription let mut progress = signed_extrinsic .submit_and_watch() + .inspect_err(|e| { + tracing::event!( + target: webb_relayer_utils::probe::TARGET, + tracing::Level::DEBUG, + kind = %webb_relayer_utils::probe::Kind::TxQueue, + ty = "SUBSTRATE", + chain_id = %chain_id, + tx = %payload, + errored = true, + error = %e, + progress = "failed", + ); + }) .map_err(Into::into) .map_err(backoff::Error::transient) .await?; @@ -171,6 +189,7 @@ where kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", chain_id = %chain_id, + tx = %payload, errored = true, error = %err, ); @@ -185,6 +204,7 @@ where tracing::Level::DEBUG, kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", + tx = %payload, chain_id = %chain_id, status = "Future", ); @@ -195,6 +215,7 @@ where tracing::Level::DEBUG, kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", + tx = %payload, chain_id = %chain_id, status = "Ready", ); @@ -205,6 +226,7 @@ where tracing::Level::DEBUG, kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", + tx = %payload, chain_id = %chain_id, status = "Broadcast", ); @@ -215,6 +237,7 @@ where tracing::Level::DEBUG, kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", + tx = %payload, chain_id = %chain_id, block_hash = ?data.block_hash(), status = "InBlock", @@ -225,6 +248,7 @@ where target: webb_relayer_utils::probe::TARGET, tracing::Level::DEBUG, kind = %webb_relayer_utils::probe::Kind::TxQueue, + tx = %payload, ty = "SUBSTRATE", chain_id = %chain_id, status = "Retracted", @@ -235,6 +259,7 @@ where target: webb_relayer_utils::probe::TARGET, tracing::Level::DEBUG, kind = %webb_relayer_utils::probe::Kind::TxQueue, + tx = %payload, ty = "SUBSTRATE", chain_id = %chain_id, status = "FinalityTimeout", @@ -246,6 +271,7 @@ where tracing::Level::DEBUG, kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", + tx = %payload, chain_id = %chain_id, status = "Finalized", finalized = true, @@ -264,6 +290,7 @@ where tracing::Level::DEBUG, kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", + tx = %payload, chain_id = %chain_id, status = "Usurped", ); @@ -274,6 +301,7 @@ where tracing::Level::DEBUG, kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", + tx = %payload, chain_id = %chain_id, status = "Dropped", ); @@ -284,6 +312,7 @@ where tracing::Level::DEBUG, kind = %webb_relayer_utils::probe::Kind::TxQueue, ty = "SUBSTRATE", + tx = %payload, chain_id = %chain_id, status = "Invalid", ); diff --git a/crates/tx-relay/src/substrate/fees.rs b/crates/tx-relay/src/substrate/fees.rs index 744692e8a..5b760a490 100644 --- a/crates/tx-relay/src/substrate/fees.rs +++ b/crates/tx-relay/src/substrate/fees.rs @@ -32,7 +32,7 @@ pub async fn get_substrate_fee_info( ctx: &RelayerContext, ) -> webb_relayer_utils::Result { let client = ctx - .substrate_provider::(&chain_id.to_string()) + .substrate_provider::(chain_id) .await?; let decimals: i32 = client .rpc() @@ -50,7 +50,7 @@ pub async fn get_substrate_fee_info( let refund_exchange_rate = native_token_to_unit(1., decimals); let max_refund = native_token_to_unit(MAX_REFUND_USD / TOKEN_PRICE_USD, decimals); - let pair = ctx.substrate_wallet(&chain_id.to_string()).await?; + let pair = ctx.substrate_wallet(chain_id).await?; let signer = PairSigner::new(pair.clone()); let max_refund = diff --git a/crates/tx-relay/src/substrate/mixer.rs b/crates/tx-relay/src/substrate/mixer.rs index ee71a0d07..89aaf57e3 100644 --- a/crates/tx-relay/src/substrate/mixer.rs +++ b/crates/tx-relay/src/substrate/mixer.rs @@ -27,18 +27,15 @@ pub async fn handle_substrate_mixer_relay_tx<'a>( let requested_chain = cmd.chain_id; let client = ctx - .substrate_provider::(&requested_chain.to_string()) + .substrate_provider::(requested_chain) .await .map_err(|e| { Error(format!("Error while getting Substrate client: {e}")) })?; - let pair = ctx - .substrate_wallet(&cmd.chain_id.to_string()) - .await - .map_err(|e| { - Error(format!("Misconfigured Network {:?}: {e}", cmd.chain_id)) - })?; + let pair = ctx.substrate_wallet(requested_chain).await.map_err(|e| { + Error(format!("Misconfigured Network {:?}: {e}", cmd.chain_id)) + })?; let signer = PairSigner::new(pair); diff --git a/crates/tx-relay/src/substrate/vanchor.rs b/crates/tx-relay/src/substrate/vanchor.rs index b6c7c2d3f..d3a0d3231 100644 --- a/crates/tx-relay/src/substrate/vanchor.rs +++ b/crates/tx-relay/src/substrate/vanchor.rs @@ -62,18 +62,15 @@ pub async fn handle_substrate_vanchor_relay_tx<'a>( let requested_chain = cmd.chain_id; let maybe_client = ctx - .substrate_provider::(&requested_chain.to_string()) + .substrate_provider::(requested_chain) .await; let client = maybe_client.map_err(|e| { Error(format!("Error while getting Substrate client: {e}")) })?; - let pair = ctx - .substrate_wallet(&cmd.chain_id.to_string()) - .await - .map_err(|e| { - Error(format!("Misconfigured Network {:?}: {e}", cmd.chain_id)) - })?; + let pair = ctx.substrate_wallet(requested_chain).await.map_err(|e| { + Error(format!("Misconfigured Network {:?}: {e}", cmd.chain_id)) + })?; let signer = PairSigner::new(pair.clone()); diff --git a/event-watchers/substrate/src/signature_bridge_watcher.rs b/event-watchers/substrate/src/signature_bridge_watcher.rs index d707564f2..3efba293a 100644 --- a/event-watchers/substrate/src/signature_bridge_watcher.rs +++ b/event-watchers/substrate/src/signature_bridge_watcher.rs @@ -20,7 +20,6 @@ use webb::substrate::subxt::config::PolkadotConfig; use webb::substrate::subxt::events::StaticEvent; 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, @@ -34,6 +33,7 @@ use webb::substrate::tangle_runtime::api as RuntimeApi; use webb::substrate::tangle_runtime::api::signature_bridge::events::MaintainerSet; use webb::substrate::scale::Encode; +use webb_relayer_utils::static_tx_payload::TypeErasedStaticTxPayload; use webb_relayer_utils::{metric, Error}; use webb::substrate::tangle_runtime::api::runtime_types::bounded_collections::bounded_vec::BoundedVec; @@ -109,7 +109,7 @@ impl SubstrateBridgeWatcher for SubstrateBridgeEventWatcher { chain_id: u32, store: Arc, client: Arc>, - pair: Sr25519Pair, + _pair: Sr25519Pair, cmd: BridgeCommand, ) -> webb_relayer_utils::Result<()> { use BridgeCommand::*; @@ -120,7 +120,6 @@ impl SubstrateBridgeWatcher for SubstrateBridgeEventWatcher { chain_id, store, client.clone(), - pair.clone(), (data, signature), ) .await? @@ -134,7 +133,6 @@ impl SubstrateBridgeWatcher for SubstrateBridgeEventWatcher { chain_id, store, client.clone(), - pair.clone(), (public_key, nonce, signature), ) .await? @@ -154,7 +152,6 @@ where chain_id: u32, store: Arc<>::Store>, api: Arc>, - pair: Sr25519Pair, (proposal_data, signature): (Vec, Vec), ) -> webb_relayer_utils::Result<()> { let proposal_data_hex = hex::encode(&proposal_data); @@ -162,7 +159,7 @@ where if proposal_data.len() < 40 { tracing::warn!( proposal_data = ?proposal_data_hex, - "Skipping execution of this proposal : Invalid Proposal", + "Skipping execution of this proposal: Invalid Proposal", ); return Ok(()); } @@ -220,13 +217,6 @@ where 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?; - // Enqueue transaction in protocol-substrate transaction queue let data_hash = utils::keccak256(execute_proposal_tx.call_data().encode()); @@ -234,11 +224,8 @@ where chain_id, make_execute_proposal_key(data_hash), ); - QueueStore::>::enqueue_item( - &store, - tx_key, - signed_execute_proposal_tx.into_encoded(), - )?; + let tx = TypeErasedStaticTxPayload::try_from(execute_proposal_tx)?; + QueueStore::enqueue_item(&store, tx_key, tx)?; tracing::debug!( data_hash = ?hex::encode(data_hash), "Enqueued execute-proposal tx for execution through protocol-substrate tx queue", @@ -252,7 +239,6 @@ where chain_id: u32, store: Arc<>::Store>, api: Arc>, - pair: Sr25519Pair, (public_key, nonce, signature): (Vec, u32, Vec), ) -> webb_relayer_utils::Result<()> { let new_maintainer = public_key.clone(); @@ -323,25 +309,16 @@ where .signature_bridge() .set_maintainer(BoundedVec(message), BoundedVec(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_tx.call_data().encode()); let tx_key = SledQueueKey::from_substrate_with_custom_key( chain_id, make_execute_proposal_key(data_hash), ); + + let tx = TypeErasedStaticTxPayload::try_from(set_maintainer_tx)?; // Enqueue transaction in protocol-substrate transaction queue - QueueStore::>::enqueue_item( - &store, - tx_key, - signed_set_maintainer_tx.into_encoded(), - )?; + QueueStore::enqueue_item(&store, tx_key, tx)?; tracing::debug!( data_hash = ?hex::encode(data_hash), "Enqueued set-maintainer tx for execution through protocol-substrate tx queue", diff --git a/services/webb-relayer/src/service/mod.rs b/services/webb-relayer/src/service/mod.rs index 383cd8db8..8ae4ff834 100644 --- a/services/webb-relayer/src/service/mod.rs +++ b/services/webb-relayer/src/service/mod.rs @@ -128,14 +128,10 @@ pub async fn make_proposal_signing_backend( // if it is the dkg backend, we will need to connect to that node first, // and then use the DkgProposalSigningBackend to sign the proposal. let dkg_client = ctx - .substrate_provider::( - &c.chain_id.to_string(), - ) + .substrate_provider::(c.chain_id) .await?; - let pair = ctx.substrate_wallet(&c.chain_id.to_string()).await?; let backend = DkgProposalSigningBackend::builder() .client(dkg_client) - .pair(subxt::tx::PairSigner::new(pair)) .src_chain_id(typed_chain_id) .store(store.clone()) .build(); diff --git a/services/webb-relayer/src/service/substrate.rs b/services/webb-relayer/src/service/substrate.rs index f695381a0..1e393cf9c 100644 --- a/services/webb-relayer/src/service/substrate.rs +++ b/services/webb-relayer/src/service/substrate.rs @@ -432,7 +432,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 pair = ctx.substrate_wallet(chain_id).await?; let task = async move { tracing::debug!( "Substrate Signature Bridge watcher for ({}) Started.", diff --git a/tests/test/evm/governorUpdates.test.ts b/tests/test/evm/governorUpdates.test.ts index e2e298e67..7e6515a32 100644 --- a/tests/test/evm/governorUpdates.test.ts +++ b/tests/test/evm/governorUpdates.test.ts @@ -43,8 +43,9 @@ import { MintableToken } from '@webb-tools/tokens'; // to support chai-as-promised Chai.use(ChaiAsPromised); -// FIXME: this test is skipped since there is an issue with manual DKG Refresh. -describe('SignatureBridge Governor Updates', function () { +// FIXME: This test is currently broken. It needs to be fixed. +// The node hangs at 30 blocks and does not proceed further. +describe.skip('SignatureBridge Governor Updates', function() { const tmpDirPath = temp.mkdirSync(); let localChain1: LocalChain; let localChain2: LocalChain; @@ -64,11 +65,11 @@ describe('SignatureBridge Governor Updates', function () { const usageMode: UsageMode = isCi ? { mode: 'docker', forcePullImage: false } : { - mode: 'host', - nodePath: path.resolve( - '../../tangle/target/release/tangle-standalone' - ), - }; + mode: 'host', + nodePath: path.resolve( + '../../tangle/target/release/tangle-standalone' + ), + }; const enabledPallets: Pallet[] = [ { pallet: 'DKGProposalHandler', @@ -110,7 +111,7 @@ describe('SignatureBridge Governor Updates', function () { // we need to wait until the public key is on chain. await charlieNode.waitForEvent({ section: 'dkg', - method: 'PublicKeySignatureChanged', + method: 'PublicKeySubmitted', }); // next we need to start local evm node. diff --git a/tests/test/substrate/governorUpdate.test.ts b/tests/test/substrate/governorUpdate.test.ts index 7fa1b57f7..fe7f79368 100644 --- a/tests/test/substrate/governorUpdate.test.ts +++ b/tests/test/substrate/governorUpdate.test.ts @@ -29,7 +29,7 @@ import { u8aToHex } from '@polkadot/util'; import { UsageMode } from '@webb-tools/test-utils'; import { defaultEventsWatcherValue } from '../../lib/utils.js'; -describe('Substrate SignatureBridge Governor Update', function () { +describe('Substrate SignatureBridge Governor Update', function() { const tmpDirPath = temp.mkdirSync(); // Tangle nodes let aliceNode: LocalTangle; @@ -41,11 +41,11 @@ describe('Substrate SignatureBridge Governor Update', function () { const usageMode: UsageMode = isCi ? { mode: 'docker', forcePullImage: false } : { - mode: 'host', - nodePath: path.resolve( - '../../tangle/target/release/tangle-standalone' - ), - }; + mode: 'host', + nodePath: path.resolve( + '../../tangle/target/release/tangle-standalone' + ), + }; const enabledPallets: Pallet[] = [ { pallet: 'SignatureBridge', @@ -88,7 +88,7 @@ describe('Substrate SignatureBridge Governor Update', function () { // Step 2. We need to wait until the public key is on chain. await aliceNode.waitForEvent({ section: 'dkg', - method: 'PublicKeySignatureChanged', + method: 'PublicKeySubmitted', }); await aliceNode.writeConfig(`${tmpDirPath}/${aliceNode.name}.json`, { @@ -127,6 +127,12 @@ describe('Substrate SignatureBridge Governor Update', function () { // Now we just need to force the DKG to rotate/refresh. const api = await aliceNode.api(); const chainId = await aliceNode.getChainId(); + + await aliceNode.waitForEvent({ + section: 'dkg', + method: 'PublicKeySignatureChanged', + }); + await webbRelayer.waitForEvent({ kind: 'signature_bridge', event: {