From bdd1e8a2f05b82f0452327a2f7f99a2df9abb1fa Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 21 Mar 2024 17:37:09 +0200 Subject: [PATCH 1/9] unstable_rpc: Add transactionBroadcast and transactionStop Signed-off-by: Alexandru Vasile --- subxt/src/backend/unstable/rpc_methods.rs | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/subxt/src/backend/unstable/rpc_methods.rs b/subxt/src/backend/unstable/rpc_methods.rs index a1b04cad4a..730ba3683d 100644 --- a/subxt/src/backend/unstable/rpc_methods.rs +++ b/subxt/src/backend/unstable/rpc_methods.rs @@ -288,6 +288,32 @@ impl UnstableRpcMethods { Ok(TransactionSubscription { sub, done: false }) } + + /// Broadcast the transaction on the p2p network until the + ///[`Self::transaction_unstable_stop`] is called. + /// + /// Returns an operation ID that can be used to stop the broadcasting process. + /// Returns `None` if the server cannot handle the request at the moment. + pub async fn transaction_unstable_broadcast(&self, tx: &[u8]) -> Result, Error> { + let operation_id = self + .client + .request("transaction_unstable_broadcast", rpc_params![to_hex(tx)]) + .await?; + Ok(operation_id) + } + + /// Stop the broadcasting process of the transaction. + /// + /// The operation ID is obtained from the [`Self::transaction_unstable_broadcast`] method. + /// + /// Returns an error if the operation ID does not correspond to any active transaction for this connection. + pub async fn transaction_unstable_stop(&self, operation_id: &str) -> Result<(), Error> { + let operation_id = self + .client + .request("transaction_unstable_stop", rpc_params![operation_id]) + .await?; + Ok(operation_id) + } } /// This represents events generated by the `follow` method. From f9283b2132f399f7dc2573c8fefa9a16ac577da3 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 21 Mar 2024 17:37:24 +0200 Subject: [PATCH 2/9] tests: Check transactionBroadcast works Signed-off-by: Alexandru Vasile --- .../src/full_client/client/unstable_rpcs.rs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs index 66fcffdc9d..807b7d2ddf 100644 --- a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs +++ b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs @@ -309,3 +309,66 @@ async fn next_operation_event< panic!("Cannot find operation related event after {NUM_EVENTS} produced events"); } + +#[tokio::test] +async fn transaction_unstable_broadcast() { + let alice = dev::alice(); + let bob = dev::bob(); + let bob_address: MultiAddress = bob.public_key().into(); + + let ctx = test_context().await; + let api = ctx.client(); + let rpc = ctx.unstable_rpc_methods().await; + + let tx = node_runtime::tx() + .balances() + .transfer_allow_death(bob_address.clone(), 10_001); + + let tx_bytes = ctx + .client() + .tx() + .create_signed_offline(&payload, &dev::alice(), Default::default()) + .unwrap() + .into_encoded(); + + // Subscribe to finalized blocks. + let mut finalized_sub = api.blocks().subscribe_finalized().await.unwrap(); + // Expect the tx to be encountered in a maximum number of blocks. + let mut num_blocks: usize = 5; + + // Submit the transaction. + let operation_id = rpc + .transaction_unstable_broadcast(&tx_bytes) + .await + .unwrap() + .expect("Server is not overloaded by 1 tx; qed"); + + while let Some(finalized) = finalized_sub.next().await { + let finalized = finalized.unwrap(); + + // Started with positive, should not overflow. + num_blocks.saturating_sub(1); + if num_blocks == 0 { + panic!("Did not find the tx in due time"); + } + + let extrinsics = block.extrinsics().await.unwrap(); + let block_extrinsics = extrinsics + .iter() + .map(|res| res.unwrap()) + .collect::>(); + + // All blocks must contain the timestamp, we expect the next extrinsics to be our own. + let Some(tx) = block_extrinsics.get(1) else { + continue; + }; + + let ext = tx + .as_extrinsic::() + .unwrap() + .unwrap(); + assert_eq!(ext.value, 10_001); + assert!(tx.is_signed()); + return; + } +} From 85d6c7728e9182e7a4974d8dfc722e2cb7503d2a Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 21 Mar 2024 17:57:11 +0200 Subject: [PATCH 3/9] testing: Enable default feature for subxt-signer Signed-off-by: Alexandru Vasile --- testing/integration-tests/Cargo.toml | 2 +- .../src/full_client/client/unstable_rpcs.rs | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/testing/integration-tests/Cargo.toml b/testing/integration-tests/Cargo.toml index 27a2c83d9f..122af6a2d3 100644 --- a/testing/integration-tests/Cargo.toml +++ b/testing/integration-tests/Cargo.toml @@ -34,7 +34,7 @@ scale-info = { workspace = true, features = ["bit-vec"] } sp-core = { workspace = true } syn = { workspace = true } subxt = { workspace = true, features = ["unstable-metadata", "native", "jsonrpsee", "substrate-compat"] } -subxt-signer = { workspace = true } +subxt-signer = { workspace = true, features = ["default"] } subxt-codegen = { workspace = true } subxt-metadata = { workspace = true } test-runtime = { workspace = true } diff --git a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs index 807b7d2ddf..d092076176 100644 --- a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs +++ b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs @@ -14,7 +14,7 @@ use subxt::{ FollowEvent, Initialized, MethodResponse, RuntimeEvent, RuntimeVersionEvent, StorageQuery, StorageQueryType, }, - utils::AccountId32, + utils::{AccountId32, MultiAddress}, }; use subxt_signer::sr25519::dev; @@ -312,7 +312,6 @@ async fn next_operation_event< #[tokio::test] async fn transaction_unstable_broadcast() { - let alice = dev::alice(); let bob = dev::bob(); let bob_address: MultiAddress = bob.public_key().into(); @@ -327,7 +326,7 @@ async fn transaction_unstable_broadcast() { let tx_bytes = ctx .client() .tx() - .create_signed_offline(&payload, &dev::alice(), Default::default()) + .create_signed_offline(&tx, &dev::alice(), Default::default()) .unwrap() .into_encoded(); @@ -337,7 +336,7 @@ async fn transaction_unstable_broadcast() { let mut num_blocks: usize = 5; // Submit the transaction. - let operation_id = rpc + let _operation_id = rpc .transaction_unstable_broadcast(&tx_bytes) .await .unwrap() @@ -347,12 +346,12 @@ async fn transaction_unstable_broadcast() { let finalized = finalized.unwrap(); // Started with positive, should not overflow. - num_blocks.saturating_sub(1); + num_blocks = num_blocks.saturating_sub(1); if num_blocks == 0 { panic!("Did not find the tx in due time"); } - let extrinsics = block.extrinsics().await.unwrap(); + let extrinsics = finalized.extrinsics().await.unwrap(); let block_extrinsics = extrinsics .iter() .map(|res| res.unwrap()) From 6d3c7861527fd65fbc5d6b43208290d5717174c3 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 21 Mar 2024 18:05:32 +0200 Subject: [PATCH 4/9] tests: Increase number of blocks to look for Signed-off-by: Alexandru Vasile --- .../integration-tests/src/full_client/client/unstable_rpcs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs index d092076176..e1e750833f 100644 --- a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs +++ b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs @@ -333,7 +333,7 @@ async fn transaction_unstable_broadcast() { // Subscribe to finalized blocks. let mut finalized_sub = api.blocks().subscribe_finalized().await.unwrap(); // Expect the tx to be encountered in a maximum number of blocks. - let mut num_blocks: usize = 5; + let mut num_blocks: usize = 10; // Submit the transaction. let _operation_id = rpc From 06ae5e2b9bde6ce506abf8d809e7a3519961f2e0 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 21 Mar 2024 18:06:33 +0200 Subject: [PATCH 5/9] Fix clippy for unneed let binds Signed-off-by: Alexandru Vasile --- subxt/src/backend/unstable/rpc_methods.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/subxt/src/backend/unstable/rpc_methods.rs b/subxt/src/backend/unstable/rpc_methods.rs index 730ba3683d..3b68a377cb 100644 --- a/subxt/src/backend/unstable/rpc_methods.rs +++ b/subxt/src/backend/unstable/rpc_methods.rs @@ -295,11 +295,9 @@ impl UnstableRpcMethods { /// Returns an operation ID that can be used to stop the broadcasting process. /// Returns `None` if the server cannot handle the request at the moment. pub async fn transaction_unstable_broadcast(&self, tx: &[u8]) -> Result, Error> { - let operation_id = self - .client + self.client .request("transaction_unstable_broadcast", rpc_params![to_hex(tx)]) - .await?; - Ok(operation_id) + .await } /// Stop the broadcasting process of the transaction. @@ -308,11 +306,9 @@ impl UnstableRpcMethods { /// /// Returns an error if the operation ID does not correspond to any active transaction for this connection. pub async fn transaction_unstable_stop(&self, operation_id: &str) -> Result<(), Error> { - let operation_id = self - .client + self.client .request("transaction_unstable_stop", rpc_params![operation_id]) - .await?; - Ok(operation_id) + .await } } From a211e98c64b9fb42fafd4cd867ad439502527767 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Fri, 22 Mar 2024 11:44:30 +0200 Subject: [PATCH 6/9] Update subxt/src/backend/unstable/rpc_methods.rs Co-authored-by: Niklas Adolfsson --- subxt/src/backend/unstable/rpc_methods.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subxt/src/backend/unstable/rpc_methods.rs b/subxt/src/backend/unstable/rpc_methods.rs index 3b68a377cb..fd2a1dcf9c 100644 --- a/subxt/src/backend/unstable/rpc_methods.rs +++ b/subxt/src/backend/unstable/rpc_methods.rs @@ -290,7 +290,7 @@ impl UnstableRpcMethods { } /// Broadcast the transaction on the p2p network until the - ///[`Self::transaction_unstable_stop`] is called. + /// [`Self::transaction_unstable_stop`] is called. /// /// Returns an operation ID that can be used to stop the broadcasting process. /// Returns `None` if the server cannot handle the request at the moment. From 9b29a2e8246105fc96289bf311dea82da27bdf4e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 22 Mar 2024 11:53:48 +0200 Subject: [PATCH 7/9] tests: Adjust txBroadcast test Signed-off-by: Alexandru Vasile --- .../src/full_client/client/unstable_rpcs.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs index e1e750833f..b576698d5e 100644 --- a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs +++ b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs @@ -14,7 +14,9 @@ use subxt::{ FollowEvent, Initialized, MethodResponse, RuntimeEvent, RuntimeVersionEvent, StorageQuery, StorageQueryType, }, + config::Hasher, utils::{AccountId32, MultiAddress}, + SubstrateConfig, }; use subxt_signer::sr25519::dev; @@ -330,6 +332,9 @@ async fn transaction_unstable_broadcast() { .unwrap() .into_encoded(); + use subxt::config::Hasher; + let tx_hash = ::Hasher::hash(&tx_bytes); + // Subscribe to finalized blocks. let mut finalized_sub = api.blocks().subscribe_finalized().await.unwrap(); // Expect the tx to be encountered in a maximum number of blocks. @@ -357,17 +362,18 @@ async fn transaction_unstable_broadcast() { .map(|res| res.unwrap()) .collect::>(); - // All blocks must contain the timestamp, we expect the next extrinsics to be our own. - let Some(tx) = block_extrinsics.get(1) else { + let Some(ext) = block_extrinsics + .iter() + .find(|ext| ::Hasher::hash(ext.bytes()) == tx_hash) + else { continue; }; - let ext = tx + let ext = ext .as_extrinsic::() .unwrap() .unwrap(); assert_eq!(ext.value, 10_001); - assert!(tx.is_signed()); return; } } From 21553732b1295c61fe161f18c3777958bae4e9f0 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 22 Mar 2024 11:58:15 +0200 Subject: [PATCH 8/9] tests: Add test for txStop Signed-off-by: Alexandru Vasile --- .../src/full_client/client/unstable_rpcs.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs index b576698d5e..b6c32875d3 100644 --- a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs +++ b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs @@ -377,3 +377,44 @@ async fn transaction_unstable_broadcast() { return; } } + +#[tokio::test] +async fn transaction_unstable_stop() { + let bob = dev::bob(); + let bob_address: MultiAddress = bob.public_key().into(); + + let ctx = test_context().await; + let api = ctx.client(); + let rpc = ctx.unstable_rpc_methods().await; + + // Cannot stop an operation that was not started. + let _err = rpc + .transaction_unstable_stop("non-existent-operation-id") + .await + .unwrap_err(); + + // Submit a transaction and stop it. + let tx = node_runtime::tx() + .balances() + .transfer_allow_death(bob_address.clone(), 10_001); + let tx_bytes = ctx + .client() + .tx() + .create_signed_offline(&tx, &dev::alice(), Default::default()) + .unwrap() + .into_encoded(); + + // Submit the transaction. + let operation_id = rpc + .transaction_unstable_broadcast(&tx_bytes) + .await + .unwrap() + .expect("Server is not overloaded by 1 tx; qed"); + + let _ = rpc.transaction_unstable_stop(&operation_id).await.unwrap(); + // Cannot stop it twice. + let _err = rpc + .transaction_unstable_stop(&operation_id) + .await + .unwrap_err(); +} From b05a9383bc6ed35459f71086ee9572a4bb07a35f Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Fri, 22 Mar 2024 13:52:50 +0200 Subject: [PATCH 9/9] tests: Ignore compact encoded lenght prefix Signed-off-by: Alexandru Vasile --- .../integration-tests/src/full_client/client/unstable_rpcs.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs index b6c32875d3..ba46681433 100644 --- a/testing/integration-tests/src/full_client/client/unstable_rpcs.rs +++ b/testing/integration-tests/src/full_client/client/unstable_rpcs.rs @@ -332,8 +332,7 @@ async fn transaction_unstable_broadcast() { .unwrap() .into_encoded(); - use subxt::config::Hasher; - let tx_hash = ::Hasher::hash(&tx_bytes); + let tx_hash = ::Hasher::hash(&tx_bytes[2..]); // Subscribe to finalized blocks. let mut finalized_sub = api.blocks().subscribe_finalized().await.unwrap(); @@ -384,7 +383,6 @@ async fn transaction_unstable_stop() { let bob_address: MultiAddress = bob.public_key().into(); let ctx = test_context().await; - let api = ctx.client(); let rpc = ctx.unstable_rpc_methods().await; // Cannot stop an operation that was not started.