Skip to content

Commit

Permalink
Add submit_and_watch_extrinsic_until_success method (#398)
Browse files Browse the repository at this point in the history
* add watch until sucess method and test

extract separate functions

move trait to top

fix ci

fix no-std build serde_full

fix clippy

remove no good test

remove comment

* remove spi-io patch

* add test utils for pub export

* remove assert matches

* add unit tests

* fix taplo
  • Loading branch information
haerdib committed Jan 3, 2023
1 parent 5cfedac commit c6cc7a9
Show file tree
Hide file tree
Showing 11 changed files with 450 additions and 106 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ ac-node-api = { path = "node-api", default-features = false }
ac-primitives = { path = "primitives", default-features = false }

[dev-dependencies]
ac-node-api = { path = "node-api", features = ["mocks"] }
kitchensink-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "master" }
scale-info = { version = "2.1.1", features = ["derive"] }

[features]
default = ["std", "jsonrpsee-client"]
Expand Down
2 changes: 2 additions & 0 deletions node-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@ std = [
# local
"ac-primitives/std",
]
# Enable import of test_utils also outside of crate (feature test does not allow to do so).
mocks = []
97 changes: 9 additions & 88 deletions node-api/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ impl<Hash: Copy> Events<Hash> {
self.block_hash
}

/// Return the encoded bytes of the Events.
pub fn event_bytes(&self) -> Arc<[u8]> {
self.event_bytes.clone()
}

/// Iterate over all of the events, using metadata to dynamically
/// decode them as we go, and returning the raw bytes and other associated
/// details. If an error occurs, all subsequent iterations return `None`.
Expand Down Expand Up @@ -323,100 +328,16 @@ impl EventDetails {
}
}

/// Event related test utilities used outside this module.
#[cfg(test)]
pub(crate) mod test_utils {
use super::*;
use codec::Encode;
use frame_metadata::{
v14::{ExtrinsicMetadata, PalletEventMetadata, PalletMetadata, RuntimeMetadataV14},
RuntimeMetadataPrefixed,
};
use scale_info::{meta_type, TypeInfo};
use std::convert::TryFrom;

/// An "outer" events enum containing exactly one event.
#[derive(Encode, Decode, TypeInfo, Clone, Debug, PartialEq, Eq)]
pub enum AllEvents<Ev> {
Test(Ev),
}

/// This encodes to the same format an event is expected to encode to
/// in node System.Events storage.
#[derive(Encode)]
pub struct EventRecord<E: Encode> {
phase: Phase,
event: AllEvents<E>,
topics: Vec<H256>,
}

/// Build an EventRecord, which encoded events in the format expected
/// to be handed back from storage queries to System.Events.
pub fn event_record<E: Encode>(phase: Phase, event: E) -> EventRecord<E> {
EventRecord { phase, event: AllEvents::Test(event), topics: vec![] }
}

/// Build fake metadata consisting of a single pallet that knows
/// about the event type provided.
pub fn metadata<E: TypeInfo + 'static>() -> Metadata {
let pallets = vec![PalletMetadata {
name: "Test",
storage: None,
calls: None,
event: Some(PalletEventMetadata { ty: meta_type::<E>() }),
constants: vec![],
error: None,
index: 0,
}];

let extrinsic =
ExtrinsicMetadata { ty: meta_type::<()>(), version: 0, signed_extensions: vec![] };

let v14 = RuntimeMetadataV14::new(pallets, extrinsic, meta_type::<()>());
let runtime_metadata: RuntimeMetadataPrefixed = v14.into();

Metadata::try_from(runtime_metadata).unwrap()
}

/// Build an `Events` object for test purposes, based on the details provided,
/// and with a default block hash.
pub fn events<E: Decode + Encode>(
metadata: Metadata,
event_records: Vec<EventRecord<E>>,
) -> Events<H256> {
let num_events = event_records.len() as u32;
let mut event_bytes = Vec::new();
for ev in event_records {
ev.encode_to(&mut event_bytes);
}
events_raw(metadata, event_bytes, num_events)
}

/// Much like [`events`], but takes pre-encoded events and event count, so that we can
/// mess with the bytes in tests if we need to.
pub fn events_raw(metadata: Metadata, event_bytes: Vec<u8>, num_events: u32) -> Events<H256> {
// Prepend compact encoded length to event bytes:
let mut all_event_bytes = Compact(num_events).encode();
all_event_bytes.extend(event_bytes);
Events::new(metadata, H256::default(), all_event_bytes)
}
}

#[cfg(test)]
mod tests {
use super::{
test_utils::{event_record, events, events_raw},
*,
use super::*;
use crate::{
decoder::Value,
test_utils::{event_record, events, events_raw, metadata},
};
use crate::decoder::Value;
use codec::Encode;
use scale_info::TypeInfo;

/// Build a fake wrapped metadata.
fn metadata<E: TypeInfo + 'static>() -> Metadata {
test_utils::metadata::<E>()
}

/// [`RawEventDetails`] can be annoying to test, because it contains
/// type info in the decoded field Values. Strip that here so that
/// we can compare fields more easily.
Expand Down
3 changes: 3 additions & 0 deletions node-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub mod events;
pub mod metadata;
pub mod storage;

#[cfg(any(feature = "mocks", test))]
pub mod test_utils;

#[cfg(feature = "std")]
mod print_metadata;

Expand Down
84 changes: 84 additions & 0 deletions node-api/src/test_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// This file was taken from subxt (Parity Technologies (UK))
// https://github.com/paritytech/subxt/
// And was adapted by Supercomputing Systems AG and Integritee AG.
//
// Copyright 2019-2022 Parity Technologies (UK) Ltd, Supercomputing Systems AG and Integritee AG.
// This file is licensed as Apache-2.0
// see LICENSE for license details.

use crate::{Events, Metadata, Phase};
/// Event related test utilities used outside this module.
use codec::Encode;
use codec::{Compact, Decode};
use frame_metadata::{
v14::{ExtrinsicMetadata, PalletEventMetadata, PalletMetadata, RuntimeMetadataV14},
RuntimeMetadataPrefixed,
};
use scale_info::{meta_type, TypeInfo};
use sp_core::H256;

/// An "outer" events enum containing exactly one event.
#[derive(Encode, Decode, TypeInfo, Clone, Debug, PartialEq, Eq)]
pub enum AllEvents<Ev> {
Test(Ev),
}

/// This encodes to the same format an event is expected to encode to
/// in node System.Events storage.
#[derive(Encode)]
pub struct EventRecord<E: Encode> {
phase: Phase,
event: AllEvents<E>,
topics: Vec<H256>,
}

/// Build an EventRecord, which encoded events in the format expected
/// to be handed back from storage queries to System.Events.
pub fn event_record<E: Encode>(phase: Phase, event: E) -> EventRecord<E> {
EventRecord { phase, event: AllEvents::Test(event), topics: vec![] }
}

/// Build fake metadata consisting of a single pallet that knows
/// about the event type provided.
pub fn metadata<E: TypeInfo + 'static>() -> Metadata {
let pallets = vec![PalletMetadata {
name: "Test",
storage: None,
calls: None,
event: Some(PalletEventMetadata { ty: meta_type::<E>() }),
constants: vec![],
error: None,
index: 0,
}];

let extrinsic =
ExtrinsicMetadata { ty: meta_type::<()>(), version: 0, signed_extensions: vec![] };

let v14 = RuntimeMetadataV14::new(pallets, extrinsic, meta_type::<()>());
let runtime_metadata: RuntimeMetadataPrefixed = v14.into();

Metadata::try_from(runtime_metadata).unwrap()
}

/// Build an `Events` object for test purposes, based on the details provided,
/// and with a default block hash.
pub fn events<E: Decode + Encode>(
metadata: Metadata,
event_records: Vec<EventRecord<E>>,
) -> Events<H256> {
let num_events = event_records.len() as u32;
let mut event_bytes = Vec::new();
for ev in event_records {
ev.encode_to(&mut event_bytes);
}
events_raw(metadata, event_bytes, num_events)
}

/// Much like [`events`], but takes pre-encoded events and event count, so that we can
/// mess with the bytes in tests if we need to.
pub fn events_raw(metadata: Metadata, event_bytes: Vec<u8>, num_events: u32) -> Events<H256> {
// Prepend compact encoded length to event bytes:
let mut all_event_bytes = Compact(num_events).encode();
all_event_bytes.extend(event_bytes);
Events::new(metadata, H256::default(), all_event_bytes)
}
4 changes: 4 additions & 0 deletions src/api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ pub enum Error {
Extrinsic(String),
#[error("Stream ended unexpectedly")]
NoStream,
#[error("Expected a block hash")]
NoBlockHash,
#[error("Did not find any block")]
NoBlock,
#[error(transparent)]
Other(#[from] Box<dyn core::error::Error + Send + Sync + 'static>),
}
Expand Down
10 changes: 10 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ impl<Hash, BlockHash> TransactionStatus<Hash, BlockHash> {
pub fn reached_status(&self, status: XtStatus) -> bool {
self.as_u8() >= status as u8
}

pub fn get_maybe_block_hash(&self) -> Option<&BlockHash> {
match self {
TransactionStatus::InBlock(block_hash) => Some(block_hash),
TransactionStatus::Retracted(block_hash) => Some(block_hash),
TransactionStatus::FinalityTimeout(block_hash) => Some(block_hash),
TransactionStatus::Finalized(block_hash) => Some(block_hash),
_ => None,
}
}
}

// Exact structure from
Expand Down
Loading

0 comments on commit c6cc7a9

Please sign in to comment.