From f25124aee9be1da6700f4b025826b1aa9b5d2ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bigna=20H=C3=A4rdi?= Date: Mon, 24 Jul 2023 15:14:30 +0200 Subject: [PATCH] Add EventReport and failed xt check to examples (#615) * update author tests * fix comment * use submit_and_watch_extrinsic_until instead of without_events in examples * add Txstatus * add .clone * update examples * rename files * fix file comments * also update custom_nonce * fix typos * fix tests * add some tests * fix typo --- .github/workflows/ci.yml | 4 +- examples/examples/benchmark_bulk_xt.rs | 9 +- examples/examples/check_extrinsic_events.rs | 142 ++++++++++++++++++ .../examples/compose_extrinsic_offline.rs | 10 +- .../contract_instantiate_with_code.rs | 10 +- examples/examples/custom_nonce.rs | 8 +- examples/examples/event_error_details.rs | 77 ---------- examples/examples/get_account_identity.rs | 8 +- examples/examples/get_blocks_async.rs | 6 +- examples/examples/get_storage.rs | 6 +- examples/examples/print_metadata.rs | 6 +- examples/examples/staking_batch_payout.rs | 10 +- ...{event_callback.rs => subscribe_events.rs} | 6 +- examples/examples/sudo.rs | 8 +- .../transfer_with_tungstenite_client.rs | 8 +- examples/examples/transfer_with_ws_client.rs | 8 +- src/api/rpc_api/author.rs | 3 +- testing/examples/author_tests.rs | 60 ++++---- 18 files changed, 240 insertions(+), 149 deletions(-) create mode 100644 examples/examples/check_extrinsic_events.rs delete mode 100644 examples/examples/event_error_details.rs rename examples/examples/{event_callback.rs => subscribe_events.rs} (88%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ed139b05..b84224d1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,13 +134,13 @@ jobs: benchmark_bulk_xt, compose_extrinsic_offline, custom_nonce, - event_callback, - event_error_details, + check_extrinsic_events, get_account_identity, get_blocks_async, get_storage, print_metadata, staking_batch_payout, + subscribe_events, sudo, transfer_with_tungstenite_client, transfer_with_ws_client, diff --git a/examples/examples/benchmark_bulk_xt.rs b/examples/examples/benchmark_bulk_xt.rs index a48c3ec65..b42156566 100644 --- a/examples/examples/benchmark_bulk_xt.rs +++ b/examples/examples/benchmark_bulk_xt.rs @@ -15,9 +15,6 @@ //! This example floods the node with a series of transactions. -// run this against test node with -// > substrate-test-node --dev --execution native --ws-port 9979 -ltxpool=debug - use kitchensink_runtime::{AccountId, BalancesCall, RuntimeCall}; use sp_keyring::AccountKeyring; use substrate_api_client::{ @@ -26,8 +23,10 @@ use substrate_api_client::{ Api, SubmitExtrinsic, }; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. // Define an extrinsic signer type which sets the generic types of the `GenericExtrinsicSigner`. // This way, the types don't have to be reassigned with every usage of this type and makes diff --git a/examples/examples/check_extrinsic_events.rs b/examples/examples/check_extrinsic_events.rs new file mode 100644 index 000000000..6cb85ca3d --- /dev/null +++ b/examples/examples/check_extrinsic_events.rs @@ -0,0 +1,142 @@ +/* + Copyright 2019 Supercomputing Systems AG + 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 sp_keyring::AccountKeyring; +use substrate_api_client::{ + ac_node_api::EventDetails, + ac_primitives::{AssetRuntimeConfig, Config, ExtrinsicSigner}, + extrinsic::BalancesExtrinsics, + rpc::JsonrpseeClient, + Api, GetAccountInformation, SubmitAndWatch, TransactionStatus, XtStatus, +}; + +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. + +type Hash = ::Hash; + +#[tokio::main] +async fn main() { + env_logger::init(); + + // Initialize api and set the signer (sender) that is used to sign the extrinsics. + let alice_signer = AccountKeyring::Alice.pair(); + let client = JsonrpseeClient::with_default_url().unwrap(); + let mut api = Api::::new(client).unwrap(); + api.set_signer(ExtrinsicSigner::::new(alice_signer)); + + let alice = AccountKeyring::Alice.to_account_id(); + let balance_of_alice = api.get_account_data(&alice).unwrap().unwrap().free; + println!("[+] Alice's Free Balance is {balance_of_alice}\n"); + + let bob = AccountKeyring::Bob.to_account_id(); + let balance_of_bob = api.get_account_data(&bob).unwrap().unwrap_or_default().free; + println!("[+] Bob's Free Balance is {balance_of_bob}\n"); + + // First we want to see the events of a failed extrinsic. + // So lets create an extrinsic that will not succeed: + // Alice tries so transfer all her balance, but that will not work, because + // she will not have enough balance left to pay the fees. + let bad_transfer_extrinsic = + api.balance_transfer_allow_death(bob.clone().into(), balance_of_alice); + println!("[+] Composed extrinsic: {bad_transfer_extrinsic:?}\n",); + + // Send and watch extrinsic until InBlock. + let result = api.submit_and_watch_extrinsic_until(bad_transfer_extrinsic, XtStatus::InBlock); + println!("[+] Sent the transfer extrinsic. Result {result:?}"); + + // Check if the transfer really has failed: + match result { + Ok(_report) => { + panic!("Exptected the call to fail."); + }, + Err(e) => { + println!("[+] Couldn't execute the extrinsic due to {e:?}\n"); + let string_error = format!("{e:?}"); + assert!(string_error.contains("FundsUnavailable")); + }, + }; + + // Verify that Bob's free Balance hasn't changed. + let new_balance_of_bob = api.get_account_data(&bob).unwrap().unwrap().free; + println!("[+] Bob's Free Balance is now {}\n", new_balance_of_bob); + assert_eq!(balance_of_bob, new_balance_of_bob); + + // Verify that Alice's free Balance decreased: paid fees. + let new_balance_of_alice = api.get_account_data(&alice).unwrap().unwrap().free; + println!("[+] Alice's Free Balance is now {}\n", new_balance_of_alice); + assert!(balance_of_alice > new_balance_of_alice); + + // Next, we send an extrinsic that should succeed: + let balance_to_transfer = 1000; + let good_transfer_extrinsic = + api.balance_transfer_allow_death(bob.clone().into(), balance_to_transfer); + // Send and watch extrinsic until InBlock. + let result = api.submit_and_watch_extrinsic_until(good_transfer_extrinsic, XtStatus::InBlock); + println!("[+] Sent the transfer extrinsic."); + + // Check if the transfer really was successful: + match result { + Ok(report) => { + let extrinsic_hash = report.extrinsic_hash; + let block_hash = report.block_hash.unwrap(); + let extrinsic_status = report.status; + let extrinsic_events = report.events.unwrap(); + + println!("[+] Extrinsic with hash {extrinsic_hash:?} was successfully executed.",); + println!("[+] Extrinsic got included in block with hash {block_hash:?}"); + println!("[+] Watched extrinsic until it reached the status {extrinsic_status:?}"); + println!("[+] The following events were thrown when the extrinsic was executed: {extrinsic_events:?}"); + + assert!(matches!(extrinsic_status, TransactionStatus::InBlock(_block_hash))); + assert_associated_events_match_expected(extrinsic_events); + }, + Err(e) => { + panic!("Expected the transfer to succeed. Instead, it failed due to {e:?}"); + }, + }; + + // Verify that Bob release has received the transferred amount. + let new_balance_of_bob = api.get_account_data(&bob).unwrap().unwrap().free; + println!("[+] Bob's Free Balance is now {}\n", new_balance_of_bob); + let expected_balance_of_bob = balance_of_bob + balance_to_transfer; + assert_eq!(expected_balance_of_bob, new_balance_of_bob); +} + +fn assert_associated_events_match_expected(events: Vec>) { + // First event + assert_eq!(events[0].pallet_name(), "Balances"); + assert_eq!(events[0].variant_name(), "Withdraw"); + + assert_eq!(events[1].pallet_name(), "Balances"); + assert_eq!(events[1].variant_name(), "Transfer"); + + assert_eq!(events[2].pallet_name(), "Balances"); + assert_eq!(events[2].variant_name(), "Deposit"); + + assert_eq!(events[3].pallet_name(), "Treasury"); + assert_eq!(events[3].variant_name(), "Deposit"); + + assert_eq!(events[4].pallet_name(), "Balances"); + assert_eq!(events[4].variant_name(), "Deposit"); + + assert_eq!(events[5].pallet_name(), "TransactionPayment"); + assert_eq!(events[5].variant_name(), "TransactionFeePaid"); + + assert_eq!(events[6].pallet_name(), "System"); + assert_eq!(events[6].variant_name(), "ExtrinsicSuccess"); +} diff --git a/examples/examples/compose_extrinsic_offline.rs b/examples/examples/compose_extrinsic_offline.rs index cb206d42a..a69f3e795 100644 --- a/examples/examples/compose_extrinsic_offline.rs +++ b/examples/examples/compose_extrinsic_offline.rs @@ -14,7 +14,7 @@ */ //! This example shows how to use the compose_extrinsic_offline macro which generates an extrinsic -//! without asking the node for nonce and does not need to know the metadata +//! without asking the node for nonce and does not need to know the metadata. use kitchensink_runtime::{BalancesCall, RuntimeCall}; use sp_keyring::AccountKeyring; @@ -25,8 +25,10 @@ use substrate_api_client::{ Api, GetChainInfo, SubmitAndWatch, XtStatus, }; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. #[tokio::main] async fn main() { @@ -66,7 +68,7 @@ async fn main() { // Send and watch extrinsic until in block (online). let block_hash = api - .submit_and_watch_extrinsic_until_without_events(xt, XtStatus::InBlock) + .submit_and_watch_extrinsic_until(xt, XtStatus::InBlock) .unwrap() .block_hash .unwrap(); diff --git a/examples/examples/contract_instantiate_with_code.rs b/examples/examples/contract_instantiate_with_code.rs index 1f2759f61..7f017ab33 100644 --- a/examples/examples/contract_instantiate_with_code.rs +++ b/examples/examples/contract_instantiate_with_code.rs @@ -24,8 +24,10 @@ use substrate_api_client::{ SubmitAndWatch, XtStatus, }; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. #[allow(unused)] #[derive(Decode)] @@ -89,8 +91,6 @@ async fn main() { let xt = api.contract_call(contract.into(), 500_000, 500_000, vec![0u8]); println!("[+] Calling the contract with extrinsic Extrinsic:\n{:?}\n\n", xt); - let report = api - .submit_and_watch_extrinsic_until_without_events(xt, XtStatus::Finalized) - .unwrap(); + let report = api.submit_and_watch_extrinsic_until(xt, XtStatus::Finalized).unwrap(); println!("[+] Extrinsic got finalized. Extrinsic Hash: {:?}", report.extrinsic_hash); } diff --git a/examples/examples/custom_nonce.rs b/examples/examples/custom_nonce.rs index d07395fd0..546b80e73 100644 --- a/examples/examples/custom_nonce.rs +++ b/examples/examples/custom_nonce.rs @@ -25,8 +25,10 @@ use substrate_api_client::{ Api, Error, GetChainInfo, SubmitAndWatch, UnexpectedTxStatus, XtStatus, }; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig. -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. #[tokio::main] async fn main() { @@ -61,7 +63,7 @@ async fn main() { println!("[+] Composed Extrinsic:\n {:?}\n", xt); // Send and watch extrinsic until InBlock. - let result = api.submit_and_watch_extrinsic_until_without_events(xt, XtStatus::InBlock); + let result = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock); println!("Returned Result {:?}", result); match result { Err(Error::UnexpectedTxStatus(UnexpectedTxStatus::Future)) => { diff --git a/examples/examples/event_error_details.rs b/examples/examples/event_error_details.rs deleted file mode 100644 index 062520d1f..000000000 --- a/examples/examples/event_error_details.rs +++ /dev/null @@ -1,77 +0,0 @@ -/* - Copyright 2019 Supercomputing Systems AG - 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 sp_keyring::AccountKeyring; -use sp_runtime::MultiAddress; -use substrate_api_client::{ - ac_primitives::{AssetRuntimeConfig, ExtrinsicSigner}, - extrinsic::BalancesExtrinsics, - rpc::JsonrpseeClient, - Api, GetAccountInformation, SubmitAndWatch, XtStatus, -}; - -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. - -#[tokio::main] -async fn main() { - env_logger::init(); - - // Initialize api and set the signer (sender) that is used to sign the extrinsics. - let alice_signer = AccountKeyring::Alice.pair(); - let client = JsonrpseeClient::with_default_url().unwrap(); - let mut api = Api::::new(client).unwrap(); - api.set_signer(ExtrinsicSigner::::new(alice_signer)); - - let alice = AccountKeyring::Alice.to_account_id(); - let balance_of_alice = api.get_account_data(&alice).unwrap().unwrap().free; - println!("[+] Alice's Free Balance is {}\n", balance_of_alice); - - let bob = AccountKeyring::Bob.to_account_id(); - let balance_of_bob = api.get_account_data(&bob).unwrap().unwrap_or_default().free; - println!("[+] Bob's Free Balance is {}\n", balance_of_bob); - - // Generate a transfer extrinsic. - let xt = api.balance_transfer_allow_death(MultiAddress::Id(bob.clone()), balance_of_alice); - println!("Sending an extrinsic from Alice (Key = {}),\n\nto Bob (Key = {})\n", alice, bob); - println!("[+] Composed extrinsic: {:?}\n", xt); - - // Send and watch extrinsic until InBlock. - let result = api.submit_and_watch_extrinsic_until(xt, XtStatus::InBlock); - println!("[+] Transaction got included into the TxPool."); - - // We expect the transfer to fail as Alice wants to transfer all her balance. - // Therefore, she will not have enough money to pay the fees. - match result { - Ok(_report) => { - panic!("Exptected the call to fail."); - }, - Err(e) => { - println!("[+] Couldn't execute the extrinsic due to {:?}\n", e); - let string_error = format!("{:?}", e); - assert!(string_error.contains("FundsUnavailable")); - }, - }; - - // Verify that Bob's free Balance hasn't changed. - let new_balance_of_bob = api.get_account_data(&bob).unwrap().unwrap().free; - println!("[+] Bob's Free Balance is now {}\n", new_balance_of_bob); - assert_eq!(balance_of_bob, new_balance_of_bob); - - // Verify that Alice's free Balance decreased: paid fees. - let new_balance_of_alice = api.get_account_data(&alice).unwrap().unwrap().free; - println!("[+] Alice's Free Balance is now {}\n", new_balance_of_alice); - assert!(balance_of_alice > new_balance_of_alice); -} diff --git a/examples/examples/get_account_identity.rs b/examples/examples/get_account_identity.rs index 14778a783..0e6f9ca77 100644 --- a/examples/examples/get_account_identity.rs +++ b/examples/examples/get_account_identity.rs @@ -33,8 +33,10 @@ type BalanceOf = <::Currency as Currency< type MaxRegistrarsOf = ::MaxRegistrars; type MaxAdditionalFieldsOf = ::MaxAdditionalFields; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. #[tokio::main] async fn main() { @@ -65,7 +67,7 @@ async fn main() { // Send and watch extrinsic until InBlock. let _block_hash = api - .submit_and_watch_extrinsic_until_without_events(xt, XtStatus::InBlock) + .submit_and_watch_extrinsic_until(xt, XtStatus::InBlock) .unwrap() .block_hash .unwrap(); diff --git a/examples/examples/get_blocks_async.rs b/examples/examples/get_blocks_async.rs index a2ab63d09..5ab46485c 100644 --- a/examples/examples/get_blocks_async.rs +++ b/examples/examples/get_blocks_async.rs @@ -30,8 +30,10 @@ async fn main() { println!("Please compile this example with `--no-default-features` for it to run properly.") } -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. #[cfg(not(feature = "sync-examples"))] #[tokio::main] diff --git a/examples/examples/get_storage.rs b/examples/examples/get_storage.rs index 1a3b19890..0cb715f0a 100644 --- a/examples/examples/get_storage.rs +++ b/examples/examples/get_storage.rs @@ -25,8 +25,10 @@ use substrate_api_client::{ Api, GetAccountInformation, GetStorage, }; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. type AccountInfo = GenericAccountInfo< ::Index, diff --git a/examples/examples/print_metadata.rs b/examples/examples/print_metadata.rs index 4c61b32f7..5362e7f0a 100644 --- a/examples/examples/print_metadata.rs +++ b/examples/examples/print_metadata.rs @@ -18,8 +18,10 @@ use substrate_api_client::{ac_primitives::AssetRuntimeConfig, rpc::JsonrpseeClient, Api}; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. #[tokio::main] async fn main() { diff --git a/examples/examples/staking_batch_payout.rs b/examples/examples/staking_batch_payout.rs index fbd196a0a..e66c2787f 100644 --- a/examples/examples/staking_batch_payout.rs +++ b/examples/examples/staking_batch_payout.rs @@ -24,8 +24,10 @@ use substrate_api_client::{ const MAX_BATCHED_TRANSACTION: u32 = 9; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. pub type EraIndex = u32; @@ -130,9 +132,7 @@ async fn main() { num_of_unclaimed_payouts -= tx_limit_in_current_batch; let batch_xt = api.batch(payout_calls); - let report = api - .submit_and_watch_extrinsic_until_without_events(batch_xt, XtStatus::InBlock) - .unwrap(); + let report = api.submit_and_watch_extrinsic_until(batch_xt, XtStatus::InBlock).unwrap(); results.push(format!("{report:?}")); } println!("{:?}", results); diff --git a/examples/examples/event_callback.rs b/examples/examples/subscribe_events.rs similarity index 88% rename from examples/examples/event_callback.rs rename to examples/examples/subscribe_events.rs index dc1bc5b74..c068fd635 100644 --- a/examples/examples/event_callback.rs +++ b/examples/examples/subscribe_events.rs @@ -26,8 +26,10 @@ use substrate_api_client::{ // Replace this crate by your own if you run a custom substrate node to get your custom events. use kitchensink_runtime::RuntimeEvent; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. #[tokio::main] async fn main() { diff --git a/examples/examples/sudo.rs b/examples/examples/sudo.rs index b947435f9..850ec65f6 100644 --- a/examples/examples/sudo.rs +++ b/examples/examples/sudo.rs @@ -29,8 +29,10 @@ use substrate_api_client::{ Api, GetAccountInformation, SubmitAndWatch, XtStatus, }; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. // Define an extrinsic signer type which sets the generic types of the `GenericExtrinsicSigner`. // This way, the types don't have to be reassigned with every usage of this type and makes @@ -75,7 +77,7 @@ async fn main() { // Send and watch extrinsic until in block. let block_hash = api - .submit_and_watch_extrinsic_until_without_events(xt, XtStatus::InBlock) + .submit_and_watch_extrinsic_until(xt, XtStatus::InBlock) .unwrap() .block_hash .unwrap(); diff --git a/examples/examples/transfer_with_tungstenite_client.rs b/examples/examples/transfer_with_tungstenite_client.rs index 198e88f05..e60695190 100755 --- a/examples/examples/transfer_with_tungstenite_client.rs +++ b/examples/examples/transfer_with_tungstenite_client.rs @@ -27,8 +27,10 @@ use substrate_api_client::{ Api, GetAccountInformation, SubmitAndWatch, XtStatus, }; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. fn main() { env_logger::init(); @@ -64,7 +66,7 @@ fn main() { // Send and watch extrinsic until in block. let block_hash = api - .submit_and_watch_extrinsic_until_without_events(xt, XtStatus::InBlock) + .submit_and_watch_extrinsic_until(xt, XtStatus::InBlock) .unwrap() .block_hash .unwrap(); diff --git a/examples/examples/transfer_with_ws_client.rs b/examples/examples/transfer_with_ws_client.rs index f15988ebe..14581bd07 100755 --- a/examples/examples/transfer_with_ws_client.rs +++ b/examples/examples/transfer_with_ws_client.rs @@ -27,8 +27,10 @@ use substrate_api_client::{ Api, GetAccountInformation, SubmitAndWatch, XtStatus, }; -// To test this example in CI, we run it against the Substrate kitchensink node. Therefore, we use the AssetRuntimeConfig -// ! Careful: Most runtimes uses plain as tips, they need a polkadot config. +// To test this example with CI we run it against the Substrate kitchensink node, which uses the asset pallet. +// Therefore, we need to use the `AssetRuntimeConfig` in this example. +// ! However, most Substrate runtimes do not use the asset pallet at all. So if you run an example against your own node +// you most likely should use `DefaultRuntimeConfig` instead. fn main() { env_logger::init(); @@ -63,7 +65,7 @@ fn main() { // Send and watch extrinsic until in block. let block_hash = api - .submit_and_watch_extrinsic_until_without_events(xt, XtStatus::InBlock) + .submit_and_watch_extrinsic_until(xt, XtStatus::InBlock) .unwrap() .block_hash .unwrap(); diff --git a/src/api/rpc_api/author.rs b/src/api/rpc_api/author.rs index 75c53ac87..14515db49 100644 --- a/src/api/rpc_api/author.rs +++ b/src/api/rpc_api/author.rs @@ -321,7 +321,8 @@ where let block_hash = report.block_hash.ok_or(Error::BlockHashNotFound)?; let extrinsic_events = self.fetch_events_for_extrinsic(block_hash, report.extrinsic_hash).await?; - // Ensure that the extrins has been successful. If not, return an error. + + // Ensure that the extrinsic has been successful. If not, return an error. for event in &extrinsic_events { event.check_if_failed()?; } diff --git a/testing/examples/author_tests.rs b/testing/examples/author_tests.rs index 878b817f8..0b9ac7868 100644 --- a/testing/examples/author_tests.rs +++ b/testing/examples/author_tests.rs @@ -63,60 +63,66 @@ async fn main() { println!("Success: submit_and_watch_extrinsic"); }); - // Test different _watch_untils. - + // Test different _watch_untils with events thread::sleep(Duration::from_secs(6)); // Wait a little to avoid transaction too low priority error. let xt2 = api.balance_transfer_allow_death(bob.clone(), 1000); let report = api.submit_and_watch_extrinsic_until(xt2, XtStatus::Ready).unwrap(); assert!(report.block_hash.is_none()); + assert!(matches!(report.status, TransactionStatus::Ready)); assert!(report.events.is_none()); println!("Success: submit_and_watch_extrinsic_until Ready"); thread::sleep(Duration::from_secs(6)); // Wait a little to avoid transaction too low priority error. let xt3 = api.balance_transfer_allow_death(bob.clone(), 1000); + let report = api.submit_and_watch_extrinsic_until(xt3, XtStatus::Broadcast).unwrap(); // The xt is not broadcast - we only have one node running. Therefore, InBlock is returned. - let _some_hash = api - .submit_and_watch_extrinsic_until_without_events(xt3, XtStatus::Broadcast) - .unwrap() - .block_hash - .unwrap(); - println!("Success: submit_and_watch_extrinsic_until_without_events Broadcast"); + assert!(report.block_hash.is_some()); + assert!(matches!(report.status, TransactionStatus::InBlock(_))); + // But we still don't fetch events, since we originally only waited for Broadcast. + assert!(report.events.is_none()); + println!("Success: submit_and_watch_extrinsic_until Broadcast"); let api2 = api.clone(); thread::sleep(Duration::from_secs(6)); // Wait a little to avoid transaction too low priority error. let xt4 = api2.balance_transfer_allow_death(bob.clone(), 1000); let until_in_block_handle = thread::spawn(move || { - let _block_hash = api2 - .submit_and_watch_extrinsic_until_without_events(xt4, XtStatus::InBlock) - .unwrap() - .block_hash - .unwrap(); - println!("Success: submit_and_watch_extrinsic_until_without_events InBlock"); + let report = api2.submit_and_watch_extrinsic_until(xt4, XtStatus::InBlock).unwrap(); + assert!(report.block_hash.is_some()); + assert!(matches!(report.status, TransactionStatus::InBlock(_))); + assert_associated_events_match_expected(report.events.unwrap()); + println!("Success: submit_and_watch_extrinsic_until InBlock"); }); let api3 = api.clone(); thread::sleep(Duration::from_secs(6)); // Wait a little to avoid transaction too low priority error. let xt5 = api.balance_transfer_allow_death(bob.clone(), 1000); let until_finalized_handle = thread::spawn(move || { - let _block_hash = api3 - .submit_and_watch_extrinsic_until_without_events(xt5, XtStatus::Finalized) - .unwrap() - .block_hash - .unwrap(); - println!("Success: submit_and_watch_extrinsic_until_without_events Finalized"); + let report = api3.submit_and_watch_extrinsic_until(xt5, XtStatus::Finalized).unwrap(); + assert!(report.block_hash.is_some()); + assert!(matches!(report.status, TransactionStatus::Finalized(_))); + assert_associated_events_match_expected(report.events.unwrap()); + println!("Success: submit_and_watch_extrinsic_until Finalized"); }); - // Test Success. + // Test some _watch_untils_without_events. One is enough, because it is tested implicitly by `submit_and_watch_extrinsic_until` + // as internal call. thread::sleep(Duration::from_secs(6)); // Wait a little to avoid transaction too low priority error. - let xt6 = api.balance_transfer_allow_death(bob, 1000); + let xt6 = api.balance_transfer_allow_death(bob.clone(), 1000); + let report = api + .submit_and_watch_extrinsic_until_without_events(xt6, XtStatus::Ready) + .unwrap(); + assert!(report.block_hash.is_none()); + assert!(report.events.is_none()); + println!("Success: submit_and_watch_extrinsic_until_without_events Ready!"); - let events = api - .submit_and_watch_extrinsic_until(xt6, XtStatus::InBlock) - .unwrap() - .events + thread::sleep(Duration::from_secs(6)); // Wait a little to avoid transaction too low priority error. + let xt7 = api.balance_transfer_allow_death(bob, 1000); + let report = api + .submit_and_watch_extrinsic_until_without_events(xt7, XtStatus::InBlock) .unwrap(); println!("Extrinsic got successfully included in Block!"); - assert_associated_events_match_expected(events); + assert!(report.block_hash.is_some()); + assert!(report.events.is_none()); watch_handle.join().unwrap(); until_in_block_handle.join().unwrap();