Skip to content

Commit

Permalink
SubmitAndWatch: Return ExtrinsicReport instead of block hash (#386)
Browse files Browse the repository at this point in the history
* remove unnecessary demands

* add submit_and_watch_extrinsic_unti_success

* rename to xt_hash

* first compiling

* update examples

* fix tests

* fix tests

* add test

* add new encoding

* fix comment

* fix everything :)

* readd commented code

* remove extrinsic success

* fix clippy

* remove FainlityTimeout from is_final

* impl check_failed for EventDetails

* remove obsolete trait enforcements

* fix clippy

* rename check_failed to check_if_failed
  • Loading branch information
haerdib committed Dec 23, 2022
1 parent a282317 commit e5162ea
Show file tree
Hide file tree
Showing 25 changed files with 190 additions and 104 deletions.
4 changes: 3 additions & 1 deletion examples/examples/batch_payout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ async fn main() {
if payout_calls_len > 0 {
let batching = api.batch(payout_calls);
let results_hash = api
.submit_and_watch_extrinsic_until(&batching.hex_encode(), XtStatus::InBlock)
.submit_and_watch_extrinsic_until(batching.encode(), XtStatus::InBlock)
.unwrap()
.block_hash
.unwrap();
num_of_claimed_payouts += payout_calls_len;

Expand Down
3 changes: 2 additions & 1 deletion examples/examples/benchmark_bulk_xt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
// run this against test node with
// > substrate-test-node --dev --execution native --ws-port 9979 -ltxpool=debug

use codec::Encode;
use kitchensink_runtime::{BalancesCall, Runtime, RuntimeCall};
use sp_keyring::AccountKeyring;
use substrate_api_client::{
Expand Down Expand Up @@ -55,7 +56,7 @@ async fn main() {
);

println!("sending extrinsic with nonce {}", nonce);
let _tx_hash = api.submit_extrinsic(xt.hex_encode()).unwrap();
let _tx_hash = api.submit_extrinsic(xt.encode()).unwrap();

nonce += 1;
}
Expand Down
6 changes: 4 additions & 2 deletions examples/examples/compose_extrinsic_offline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//! This examples 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

use codec::Encode;
use kitchensink_runtime::{BalancesCall, Header, Runtime, RuntimeCall};
use sp_keyring::AccountKeyring;
use sp_runtime::{generic::Era, MultiAddress};
Expand Down Expand Up @@ -66,8 +67,9 @@ async fn main() {

// Send and watch extrinsic until in block.
let block_hash = api
.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::InBlock)
.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::InBlock)
.unwrap()
.block_hash
.unwrap();
println!("[+] Transaction got included in block {:?}", block_hash);
println!("[+] Extrinsic got included in block {:?}", block_hash);
}
14 changes: 7 additions & 7 deletions examples/examples/contract_instantiate_with_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

//! This example is community maintained and not CI tested, therefore it may not work as is.

use codec::Decode;
use codec::{Decode, Encode};
use kitchensink_runtime::Runtime;
use sp_keyring::AccountKeyring;
use substrate_api_client::{
Expand Down Expand Up @@ -68,9 +68,11 @@ async fn main() {

println!("[+] Creating a contract instance with extrinsic:\n\n{:?}\n", xt);
let block_hash = api
.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::InBlock)
.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::InBlock)
.unwrap()
.block_hash
.unwrap();
println!("[+] Transaction is in Block. Hash: {:?}\n", block_hash);
println!("[+] Extrinsic is in Block. Hash: {:?}\n", block_hash);

println!("[+] Waiting for the contracts.Instantiated event");

Expand All @@ -81,8 +83,6 @@ async fn main() {
let xt = api.contract_call(args.contract.into(), 500_000, 500_000, vec![0u8]);

println!("[+] Calling the contract with extrinsic Extrinsic:\n{:?}\n\n", xt);
let block_hash = api
.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::Finalized)
.unwrap();
println!("[+] Transaction got finalized. Hash: {:?}", block_hash);
let report = api.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::Finalized).unwrap();
println!("[+] Extrinsic got finalized. Extrinsic Hash: {:?}", report.extrinsic_hash);
}
3 changes: 2 additions & 1 deletion examples/examples/custom_nonce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//! This examples 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

use codec::Encode;
use kitchensink_runtime::{BalancesCall, Runtime, RuntimeCall};
use sp_keyring::AccountKeyring;
use sp_runtime::{generic::Era, MultiAddress};
Expand Down Expand Up @@ -65,7 +66,7 @@ async fn main() {
println!("[+] Composed Extrinsic:\n {:?}\n", xt);

// Send and watch extrinsic until InBlock.
match api.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::InBlock) {
match api.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::InBlock) {
Err(error) => {
println!("Retrieved error {:?}", error);
assert!(format!("{:?}", error).contains("Future"));
Expand Down
4 changes: 2 additions & 2 deletions examples/examples/event_error_details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

use codec::Decode;
use codec::{Decode, Encode};
use kitchensink_runtime::Runtime;
use sp_core::crypto::Pair;
use sp_keyring::AccountKeyring;
Expand Down Expand Up @@ -78,7 +78,7 @@ async fn main() {
println!("[+] Composed extrinsic: {:?}\n", xt);

// Send and watch extrinsic until Ready.
let _tx_hash = api.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::Ready).unwrap();
let _tx_hash = api.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::Ready).unwrap();
println!("[+] Transaction got included into the TxPool.");

// Transfer should fail as Alice wants to transfer all her balance. She does not have enough money to pay the fees.
Expand Down
9 changes: 5 additions & 4 deletions examples/examples/generic_event_callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
//! Very simple example that shows how to subscribe to events generically
//! implying no runtime needs to be imported

use codec::Decode;
use codec::{Decode, Encode};
use kitchensink_runtime::Runtime;
use sp_keyring::AccountKeyring;
use sp_runtime::{AccountId32 as AccountId, MultiAddress};
Expand Down Expand Up @@ -67,11 +67,12 @@ async fn main() {
println!("[+] Composed extrinsic: {:?}\n", xt);

// Send extrinsic.
let tx_hash = api
.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::InBlock)
let block_hash = api
.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::InBlock)
.unwrap()
.block_hash
.unwrap();
println!("[+] Transaction got included. Hash: {:?}\n", tx_hash);
println!("[+] Transaction got included. Hash: {:?}\n", block_hash);

let args = thread_output.join().unwrap();

Expand Down
7 changes: 3 additions & 4 deletions examples/examples/generic_extrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//! This examples shows how to use the compose_extrinsic macro to create an extrinsic for any (custom)
//! module, whereas the desired module and call are supplied as a string.

use codec::Encode;
use kitchensink_runtime::Runtime;
use sp_keyring::AccountKeyring;
use substrate_api_client::{
Expand Down Expand Up @@ -51,8 +52,6 @@ async fn main() {
println!("[+] Composed Extrinsic:\n {:?}\n", xt);

// send and watch extrinsic until InBlock
let tx_hash = api
.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::InBlock)
.unwrap();
println!("[+] Transaction got included. Hash: {:?}", tx_hash);
let report = api.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::InBlock).unwrap();
println!("[+] Extrinsic got included. Extrinsic Hash: {:?}", report.extrinsic_hash);
}
5 changes: 4 additions & 1 deletion examples/examples/get_account_identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

//! Example to show how to get the account identity display name from the identity pallet.

use codec::Encode;
use frame_support::traits::Currency;
use kitchensink_runtime::Runtime as KitchensinkRuntime;
use pallet_identity::{Data, IdentityInfo, Registration};
Expand Down Expand Up @@ -63,7 +64,9 @@ async fn main() {

// Send and watch extrinsic until InBlock.
let _block_hash = api
.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::InBlock)
.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::InBlock)
.unwrap()
.block_hash
.unwrap();

// Get the storage value from the pallet. Check out the pallet itself to know it's type:
Expand Down
8 changes: 4 additions & 4 deletions examples/examples/staking_payout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
limitations under the License.
*/

use codec::Encode;
use kitchensink_runtime::Runtime;
use pallet_staking::{ActiveEraInfo, Exposure};
use sp_keyring::AccountKeyring;
Expand Down Expand Up @@ -42,9 +43,8 @@ async fn main() {
}
if exposure.total > 0_u128 {
let call = api.payout_stakers(idx, account);
let result = api
.submit_and_watch_extrinsic_until(&call.hex_encode(), XtStatus::InBlock)
.unwrap();
println!("{:?}", result);
let report =
api.submit_and_watch_extrinsic_until(call.encode(), XtStatus::InBlock).unwrap();
println!("{:?}", report);
}
}
8 changes: 5 additions & 3 deletions examples/examples/sudo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
//! This examples shows how to use the compose_extrinsic macro to create an extrinsic for any (custom)
//! module, whereas the desired module and call are supplied as a string.

use codec::Compact;
use codec::{Compact, Encode};
use kitchensink_runtime::Runtime;
use sp_keyring::AccountKeyring;
use substrate_api_client::{
Expand Down Expand Up @@ -53,7 +53,9 @@ async fn main() {

// send and watch extrinsic until in block
let block_hash = api
.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::InBlock)
.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::InBlock)
.unwrap()
.block_hash
.unwrap();
println!("[+] Transaction got included. Hash: {:?}", block_hash);
println!("[+] Extrinsic got included. Block Hash: {:?}", block_hash);
}
7 changes: 5 additions & 2 deletions examples/examples/transfer_using_seed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

//! Very simple example that shows how to use a predefined extrinsic from the extrinsic module.

use codec::Encode;
use kitchensink_runtime::Runtime;
use sp_core::{
crypto::{Pair, Ss58Codec},
Expand Down Expand Up @@ -64,9 +65,11 @@ async fn main() {

// Send and watch extrinsic until in block.
let block_hash = api
.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::InBlock)
.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::InBlock)
.unwrap()
.block_hash
.unwrap();
println!("[+] Transaction got included. Hash: {:?}\n", block_hash);
println!("[+] Extrinsic got included. Hash: {:?}\n", block_hash);

// Verify that Bob's free Balance increased.
let bob_account_data = api.get_account_data(&bob.into()).unwrap().unwrap();
Expand Down
7 changes: 5 additions & 2 deletions examples/examples/transfer_with_tungstenite_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

//! Very simple example that shows how to use a predefined extrinsic from the extrinsic module.

use codec::Encode;
use kitchensink_runtime::Runtime;
use sp_core::{
crypto::{Pair, Ss58Codec},
Expand Down Expand Up @@ -63,9 +64,11 @@ fn main() {

// Send and watch extrinsic until in block.
let block_hash = api
.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::InBlock)
.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::InBlock)
.unwrap()
.block_hash
.unwrap();
println!("[+] Transaction got included. Hash: {:?}\n", block_hash);
println!("[+] Extrinsic got included. Hash: {:?}\n", block_hash);

// Verify that Bob's free Balance increased.
let bob_account_data = api.get_account_data(&bob.into()).unwrap().unwrap();
Expand Down
7 changes: 5 additions & 2 deletions examples/examples/transfer_with_ws_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

//! Very simple example that shows how to use a predefined extrinsic from the extrinsic module.

use codec::Encode;
use kitchensink_runtime::Runtime;
use sp_core::{
crypto::{Pair, Ss58Codec},
Expand Down Expand Up @@ -62,9 +63,11 @@ fn main() {

// Send and watch extrinsic until in block.
let block_hash = api
.submit_and_watch_extrinsic_until(&xt.hex_encode(), XtStatus::InBlock)
.submit_and_watch_extrinsic_until(xt.encode(), XtStatus::InBlock)
.unwrap()
.block_hash
.unwrap();
println!("[+] Transaction got included. Hash: {:?}\n", block_hash);
println!("[+] Extrinsic got included. Hash: {:?}\n", block_hash);

// Verify that Bob's free Balance increased.
let bob_account_data = api.get_account_data(&bob.into()).unwrap().unwrap();
Expand Down
13 changes: 12 additions & 1 deletion node-api/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use crate::{
alloc::{string::ToString, sync::Arc, vec, vec::Vec},
decoder::{decode_as_type, Composite, TypeId},
error::Error,
error::{DispatchError, Error},
metadata::EventMetadata,
Metadata, Phase, StaticEvent,
};
Expand Down Expand Up @@ -312,6 +312,17 @@ impl EventDetails {
}
}

impl EventDetails {
/// Checks if the extrinsic has failed. If so, the corresponding DispatchError is returned.
pub fn check_if_failed(&self) -> Result<(), DispatchError> {
if self.pallet_name() == "System" && self.variant_name() == "ExtrinsicFailed" {
let dispatch_error = DispatchError::decode_from(self.field_bytes(), &self.metadata);
return Err(dispatch_error)
}
Ok(())
}
}

/// Event related test utilities used outside this module.
#[cfg(test)]
pub(crate) mod test_utils {
Expand Down
6 changes: 0 additions & 6 deletions primitives/src/extrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,6 @@ where
) -> Self {
UncheckedExtrinsicV4 { signature: Some((signed, signature, extra)), function }
}

pub fn hex_encode(&self) -> alloc::string::String {
let mut hex_str = hex::encode(self.encode());
hex_str.insert_str(0, "0x");
hex_str
}
}

impl<Call, SignedExtra> fmt::Debug for UncheckedExtrinsicV4<Call, SignedExtra>
Expand Down
6 changes: 6 additions & 0 deletions src/api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,9 @@ impl From<ac_node_api::error::Error> for Error {
Error::NodeApi(error)
}
}

impl From<ac_node_api::error::DispatchError> for Error {
fn from(error: ac_node_api::error::DispatchError) -> Self {
Error::Dispatch(error)
}
}
33 changes: 33 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,37 @@ pub mod api_client;
pub mod error;
pub mod rpc_api;

use ac_node_api::EventDetails;
use serde::{Deserialize, Serialize};

/// Extrinsic report returned upon a submit_and_watch request.
/// Holds as much information as available.
#[derive(Debug, Clone)]
pub struct ExtrinsicReport<Hash> {
// Hash of the extrinsic.
pub extrinsic_hash: Hash,
// Block hash of the block the extrinsic was included in.
// Only available if watched until at least `InBlock`.
pub block_hash: Option<Hash>,
// Last known Transaction Status.
pub status: TransactionStatus<Hash, Hash>,
// Events assosciated to the extrinsic.
// Only available if explicitly stated, because
// extra node queries are necessary to fetch the events.
pub events: Option<Vec<EventDetails>>,
}

impl<Hash> ExtrinsicReport<Hash> {
pub fn new(
extrinsic_hash: Hash,
block_hash: Option<Hash>,
status: TransactionStatus<Hash, Hash>,
events: Option<Vec<EventDetails>>,
) -> Self {
Self { extrinsic_hash, block_hash, status, events }
}
}

/// Simplified TransactionStatus to allow the user to choose until when to watch
/// an extrinsic.
// Indexes must match the TransactionStatus::as_u8 from below.
Expand Down Expand Up @@ -93,6 +122,10 @@ impl<Hash, BlockHash> TransactionStatus<Hash, BlockHash> {
| TransactionStatus::Finalized(_)
)
}

pub fn is_final(&self) -> bool {
matches!(self, TransactionStatus::Finalized(_))
}
}

// Exact structure from
Expand Down
Loading

0 comments on commit e5162ea

Please sign in to comment.