mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 13:31:10 +00:00
[do-not-merge] Bridge hub sample call with custom ExtrinsicParams
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
//! ```bash
|
||||
//! ./target/release/subxt metadata --url ws://localhost:9946 > artifacts/bridge_metadata.scale
|
||||
//! ```
|
||||
|
||||
use sp_keyring::AccountKeyring;
|
||||
use subxt::{
|
||||
extrinsic::{
|
||||
BridgeHubExtrinsicParams,
|
||||
BridgeHubExtrinsicParamsBuilder,
|
||||
},
|
||||
ClientBuilder,
|
||||
DefaultConfig,
|
||||
PairSigner,
|
||||
};
|
||||
|
||||
#[subxt::subxt(runtime_metadata_path = "../artifacts/bridge_metadata.scale")]
|
||||
pub mod polkadot {}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
tracing_subscriber::fmt::init();
|
||||
// max_size 50 is pallet's config T::StringMaxLength in runtime, so only 50 will pass
|
||||
|
||||
let result = call_set_name("123456", 51, 1).await;
|
||||
assert!(result.is_err());
|
||||
eprintln!("Result failed as expected: {:?}", result);
|
||||
|
||||
let result = call_set_name("123456", 50, 51).await;
|
||||
assert!(result.is_err());
|
||||
eprintln!("Result failed as expected: {:?}", result);
|
||||
|
||||
let result = call_set_name("12345678910", 50, 1).await;
|
||||
assert!(result.is_err());
|
||||
eprintln!("Result failed as expected: {:?}", result);
|
||||
|
||||
let result = call_set_name("123456789", 50, 1).await;
|
||||
assert!(result.is_err());
|
||||
eprintln!("Result failed as expected: {:?}", result);
|
||||
|
||||
assert!(call_set_name("1234567", 50, 1).await.is_ok());
|
||||
assert!(call_set_name("123", 50, 1).await.is_ok());
|
||||
|
||||
println!("Hurraaa, test passed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This is the highest level approach to using this API. We use `wait_for_finalized_success`
|
||||
/// to wait for the transaction to make it into a finalized block, and also ensure that the
|
||||
/// transaction was successful according to the associated events.
|
||||
async fn call_set_name(
|
||||
data: &str,
|
||||
max_size: u32,
|
||||
priority: u8,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let signer = PairSigner::new(AccountKeyring::Alice.pair());
|
||||
|
||||
let params = BridgeHubExtrinsicParamsBuilder::new(max_size, priority);
|
||||
|
||||
let api = ClientBuilder::new()
|
||||
.set_url("ws://127.0.0.1:9946")
|
||||
.build()
|
||||
.await?
|
||||
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, BridgeHubExtrinsicParams<DefaultConfig>>>();
|
||||
|
||||
let data = data.as_bytes().to_vec();
|
||||
let data =
|
||||
polkadot::runtime_types::sp_runtime::bounded::bounded_vec::BoundedVec::<u8>(data);
|
||||
|
||||
let result = api
|
||||
.tx()
|
||||
.bridge_hub_sample()
|
||||
.set_name(data)?
|
||||
.sign_and_submit_then_watch(&signer, params)
|
||||
.await?
|
||||
.wait_for_finalized_success()
|
||||
.await?;
|
||||
|
||||
for (idx, event) in result.iter().enumerate() {
|
||||
println!("Bridge event ({}): {:?}", idx, event);
|
||||
}
|
||||
|
||||
let success_event = result
|
||||
.find_first::<polkadot::system::events::ExtrinsicSuccess>()
|
||||
.expect("decode error");
|
||||
|
||||
if let Some(event) = success_event {
|
||||
println!("Bridge success: {:?}", event);
|
||||
} else {
|
||||
panic!("Failed to call bridge: {:?}", result);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -26,6 +26,8 @@ pub use self::{
|
||||
AssetTip,
|
||||
BaseExtrinsicParams,
|
||||
BaseExtrinsicParamsBuilder,
|
||||
BridgeHubExtrinsicParams,
|
||||
BridgeHubExtrinsicParamsBuilder,
|
||||
Era,
|
||||
ExtrinsicParams,
|
||||
PlainTip,
|
||||
|
||||
@@ -56,6 +56,13 @@ pub type SubstrateExtrinsicParams<T> = BaseExtrinsicParams<T, AssetTip>;
|
||||
/// This is what you provide to methods like `sign_and_submit()`.
|
||||
pub type SubstrateExtrinsicParamsBuilder<T> = BaseExtrinsicParamsBuilder<T, AssetTip>;
|
||||
|
||||
/// A struct representing the signed extra and additional parameters required
|
||||
/// to construct a transaction for the default substrate node.
|
||||
pub type BridgeHubExtrinsicParams<T> = ExtendedExtrinsicParams<T, PlainTip>;
|
||||
/// A builder which leads to [`SubstrateExtrinsicParams`] being constructed.
|
||||
/// This is what you provide to methods like `sign_and_submit()`.
|
||||
pub type BridgeHubExtrinsicParamsBuilder<T> = ExtendedExtrinsicParamsBuilder<T, PlainTip>;
|
||||
|
||||
/// A struct representing the signed extra and additional parameters required
|
||||
/// to construct a transaction for a polkadot node.
|
||||
pub type PolkadotExtrinsicParams<T> = BaseExtrinsicParams<T, PlainTip>;
|
||||
@@ -175,6 +182,126 @@ impl<T: Config, Tip: Debug + Encode> ExtrinsicParams<T> for BaseExtrinsicParams<
|
||||
}
|
||||
}
|
||||
|
||||
/// An implementation of [`ExtrinsicParams`] that is suitable for constructing
|
||||
/// extrinsics that can be sent to a node with the same signed extra and additional
|
||||
/// parameters as a Polkadot/Substrate node. The way that tip payments are specified
|
||||
/// differs between Substrate and Polkadot nodes, and so we are generic over that in
|
||||
/// order to support both here with relative ease.
|
||||
///
|
||||
/// If your node differs in the "signed extra" and "additional" parameters expected
|
||||
/// to be sent/signed with a transaction, then you can define your own type which
|
||||
/// implements the [`ExtrinsicParams`] trait.
|
||||
#[derive(Debug)]
|
||||
pub struct ExtendedExtrinsicParams<T: Config, Tip: Debug> {
|
||||
era: Era,
|
||||
nonce: T::Index,
|
||||
tip: Tip,
|
||||
max_size: u32,
|
||||
priority: u8,
|
||||
spec_version: u32,
|
||||
transaction_version: u32,
|
||||
genesis_hash: T::Hash,
|
||||
mortality_checkpoint: T::Hash,
|
||||
marker: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
/// This builder allows you to provide the parameters that can be configured in order to
|
||||
/// construct a [`BaseExtrinsicParams`] value. This implements [`Default`], which allows
|
||||
/// [`BaseExtrinsicParams`] to be used with convenience methods like `sign_and_submit_default()`.
|
||||
///
|
||||
/// Prefer to use [`SubstrateExtrinsicParamsBuilder`] for a version of this tailored towards
|
||||
/// Substrate, or [`PolkadotExtrinsicParamsBuilder`] for a version tailored to Polkadot.
|
||||
pub struct ExtendedExtrinsicParamsBuilder<T: Config, Tip> {
|
||||
era: Era,
|
||||
mortality_checkpoint: Option<T::Hash>,
|
||||
tip: Tip,
|
||||
max_size: u32,
|
||||
priority: u8,
|
||||
}
|
||||
|
||||
impl<T: Config, Tip: Default> ExtendedExtrinsicParamsBuilder<T, Tip> {
|
||||
/// Instantiate the default set of [`BaseExtrinsicParamsBuilder`]
|
||||
pub fn new(max_size: u32, priority: u8) -> Self {
|
||||
Self {
|
||||
era: Era::Immortal,
|
||||
mortality_checkpoint: None,
|
||||
tip: Tip::default(),
|
||||
max_size,
|
||||
priority,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the [`Era`], which defines how long the transaction will be valid for
|
||||
/// (it can be either immortal, or it can be mortal and expire after a certain amount
|
||||
/// of time). The second argument is the block hash after which the transaction
|
||||
/// becomes valid, and must align with the era phase (see the [`Era::Mortal`] docs
|
||||
/// for more detail on that).
|
||||
pub fn era(mut self, era: Era, checkpoint: T::Hash) -> Self {
|
||||
self.era = era;
|
||||
self.mortality_checkpoint = Some(checkpoint);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the tip you'd like to give to the block author
|
||||
/// for this transaction.
|
||||
pub fn tip(mut self, tip: impl Into<Tip>) -> Self {
|
||||
self.tip = tip.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the priority
|
||||
pub fn priority(mut self, priority: u8) -> Self {
|
||||
self.priority = priority;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config, Tip: Debug + Encode> ExtrinsicParams<T> for ExtendedExtrinsicParams<T, Tip> {
|
||||
type OtherParams = ExtendedExtrinsicParamsBuilder<T, Tip>;
|
||||
|
||||
fn new(
|
||||
// Provided from subxt client:
|
||||
spec_version: u32,
|
||||
transaction_version: u32,
|
||||
nonce: T::Index,
|
||||
genesis_hash: T::Hash,
|
||||
// Provided externally:
|
||||
other_params: Self::OtherParams,
|
||||
) -> Self {
|
||||
ExtendedExtrinsicParams {
|
||||
era: other_params.era,
|
||||
mortality_checkpoint: other_params
|
||||
.mortality_checkpoint
|
||||
.unwrap_or(genesis_hash),
|
||||
tip: other_params.tip,
|
||||
max_size: other_params.max_size,
|
||||
priority: other_params.priority,
|
||||
nonce,
|
||||
spec_version,
|
||||
transaction_version,
|
||||
genesis_hash,
|
||||
marker: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_extra_to(&self, v: &mut Vec<u8>) {
|
||||
let nonce: u64 = self.nonce.into();
|
||||
let tip = Encoded(self.tip.encode());
|
||||
(self.era, Compact(nonce), tip, self.priority).encode_to(v);
|
||||
}
|
||||
|
||||
fn encode_additional_to(&self, v: &mut Vec<u8>) {
|
||||
(
|
||||
self.spec_version,
|
||||
self.transaction_version,
|
||||
self.genesis_hash,
|
||||
self.mortality_checkpoint,
|
||||
self.max_size,
|
||||
)
|
||||
.encode_to(v);
|
||||
}
|
||||
}
|
||||
|
||||
/// A tip payment.
|
||||
#[derive(Copy, Clone, Debug, Default, Encode)]
|
||||
pub struct PlainTip {
|
||||
|
||||
Reference in New Issue
Block a user