mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 00:37:57 +00:00
Rework Subxt API to support offline and dynamic transactions (#593)
* WIP API changes * debug impls * Get main crate compiling with first round of changes * Some tidy up * Add WithExtrinsicParams, and have SubstrateConfig + PolkadotConfig, not DefaultConfig * move transaction into extrinsic folder * Add runtime updates back to OnlineClient * rework to be 'client first' to fit better with storage + events * add support for events to Client * tidy dupe trait bound * Wire storage into client, but need to remove static reliance * various tidy up and start stripping codegen to remove bits we dont need now * First pass updating calls and constants codegen * WIP storage client updates * First pass migrated runtime storage over to new format * pass over codegen to generate StorageAddresses and throw other stuff out * don't need a Call trait any more * shuffle things around a bit * Various proc_macro fixes to get 'cargo check' working * organise what's exposed from subxt * Get first example working; balance_transfer_with_params * get balance_transfer example compiling * get concurrent_storage_requests.rs example compiling * get fetch_all_accounts example compiling * get a bunch more of the examples compiling * almost get final example working; type mismatch to look into * wee tweaks * move StorageAddress to separate file * pass Defaultable/Iterable info to StorageAddress in codegen * fix storage validation ne, and partial run through example code * Remove static iteration and strip a generic param from everything * fix doc tests in subxt crate * update test utils and start fixing frame tests * fix frame staking tests * fix the rest of the test compile issues, Borrow on storage values * cargo fmt * remove extra logging during tests * Appease clippy and no more need for into_iter on events * cargo fmt * fix dryRun tests by waiting for blocks * wait for blocks instead of sleeping or other test hacks * cargo fmt * Fix doc links * Traitify StorageAddress * remove out-of-date doc comments * optimise decoding storage a little * cleanup tx stuff, trait for TxPayload, remove Err type param and decode at runtime * clippy fixes * fix doc links * fix doc example * constant address trait for consistency * fix a typo and remove EncodeWithMetadata stuff * Put EventDetails behind a proper interface and allow decoding into top level event, too * fix docs * tweak StorageAddress docs * re-export StorageAddress at root for consistency * fix clippy things * Add support for dynamic values * fix double encoding of storage map key after refactor * clippy fix * Fixes and add a dynamic usage example (needs new scale_value release) * bump scale_value version * cargo fmt * Tweak event bits * cargo fmt * Add a test and bump scale-value to 0.4.0 to support this * remove unnecessary vec from dynamic example * Various typo/grammar fixes Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> * Address PR nits * Undo accidental rename in changelog * Small PR nits/tidyups * fix tests; codegen change against latest substrate * tweak storage address util names * move error decoding to DecodeError and expose * impl some basic traits on the extrinsic param builder Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com>
This commit is contained in:
@@ -3,24 +3,29 @@
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::{
|
||||
test_node_process,
|
||||
test_node_process_with,
|
||||
utils::node_runtime::system,
|
||||
pair_signer,
|
||||
test_context,
|
||||
test_context_with,
|
||||
utils::{
|
||||
node_runtime,
|
||||
wait_for_blocks,
|
||||
},
|
||||
};
|
||||
|
||||
use sp_core::storage::{
|
||||
well_known_keys,
|
||||
StorageKey,
|
||||
use sp_core::{
|
||||
sr25519::Pair as Sr25519Pair,
|
||||
storage::well_known_keys,
|
||||
Pair,
|
||||
};
|
||||
use sp_keyring::AccountKeyring;
|
||||
use subxt::error::DispatchError;
|
||||
|
||||
#[tokio::test]
|
||||
async fn insert_key() {
|
||||
let test_node_process = test_node_process_with(AccountKeyring::Bob).await;
|
||||
let client = test_node_process.client();
|
||||
let ctx = test_context_with(AccountKeyring::Bob).await;
|
||||
let api = ctx.client();
|
||||
|
||||
let public = AccountKeyring::Alice.public().as_array_ref().to_vec();
|
||||
client
|
||||
.rpc()
|
||||
api.rpc()
|
||||
.insert_key(
|
||||
"aura".to_string(),
|
||||
"//Alice".to_string(),
|
||||
@@ -28,7 +33,7 @@ async fn insert_key() {
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(client
|
||||
assert!(api
|
||||
.rpc()
|
||||
.has_key(public.clone().into(), "aura".to_string())
|
||||
.await
|
||||
@@ -37,29 +42,30 @@ async fn insert_key() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn fetch_block_hash() {
|
||||
let node_process = test_node_process().await;
|
||||
node_process.client().rpc().block_hash(None).await.unwrap();
|
||||
let ctx = test_context().await;
|
||||
ctx.client().rpc().block_hash(None).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fetch_block() {
|
||||
let node_process = test_node_process().await;
|
||||
let client = node_process.client();
|
||||
let block_hash = client.rpc().block_hash(None).await.unwrap();
|
||||
client.rpc().block(block_hash).await.unwrap();
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
let block_hash = api.rpc().block_hash(None).await.unwrap();
|
||||
api.rpc().block(block_hash).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fetch_read_proof() {
|
||||
let node_process = test_node_process().await;
|
||||
let client = node_process.client();
|
||||
let block_hash = client.rpc().block_hash(None).await.unwrap();
|
||||
client
|
||||
.rpc()
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
let block_hash = api.rpc().block_hash(None).await.unwrap();
|
||||
api.rpc()
|
||||
.read_proof(
|
||||
vec![
|
||||
StorageKey(well_known_keys::HEAP_PAGES.to_vec()),
|
||||
StorageKey(well_known_keys::EXTRINSIC_INDEX.to_vec()),
|
||||
well_known_keys::HEAP_PAGES,
|
||||
well_known_keys::EXTRINSIC_INDEX,
|
||||
],
|
||||
block_hash,
|
||||
)
|
||||
@@ -69,27 +75,31 @@ async fn fetch_read_proof() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn chain_subscribe_blocks() {
|
||||
let node_process = test_node_process().await;
|
||||
let client = node_process.client();
|
||||
let mut blocks = client.rpc().subscribe_blocks().await.unwrap();
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
let mut blocks = api.rpc().subscribe_blocks().await.unwrap();
|
||||
blocks.next().await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn chain_subscribe_finalized_blocks() {
|
||||
let node_process = test_node_process().await;
|
||||
let client = node_process.client();
|
||||
let mut blocks = client.rpc().subscribe_finalized_blocks().await.unwrap();
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
let mut blocks = api.rpc().subscribe_finalized_blocks().await.unwrap();
|
||||
blocks.next().await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fetch_keys() {
|
||||
let node_process = test_node_process().await;
|
||||
let client = node_process.client();
|
||||
let keys = client
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
let addr = node_runtime::storage().system().account_root();
|
||||
let keys = api
|
||||
.storage()
|
||||
.fetch_keys::<system::storage::Account>(4, None, None)
|
||||
.fetch_keys(&addr.to_root_bytes(), 4, None, None)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(keys.len(), 4)
|
||||
@@ -97,13 +107,11 @@ async fn fetch_keys() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_iter() {
|
||||
let node_process = test_node_process().await;
|
||||
let client = node_process.client();
|
||||
let mut iter = client
|
||||
.storage()
|
||||
.iter::<system::storage::Account>(None)
|
||||
.await
|
||||
.unwrap();
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
let addr = node_runtime::storage().system().account_root();
|
||||
let mut iter = api.storage().iter(addr, 10, None).await.unwrap();
|
||||
let mut i = 0;
|
||||
while iter.next().await.unwrap().is_some() {
|
||||
i += 1;
|
||||
@@ -113,9 +121,96 @@ async fn test_iter() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn fetch_system_info() {
|
||||
let node_process = test_node_process().await;
|
||||
let client = node_process.client();
|
||||
assert_eq!(client.rpc().system_chain().await.unwrap(), "Development");
|
||||
assert_eq!(client.rpc().system_name().await.unwrap(), "Substrate Node");
|
||||
assert!(!client.rpc().system_version().await.unwrap().is_empty());
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
assert_eq!(api.rpc().system_chain().await.unwrap(), "Development");
|
||||
assert_eq!(api.rpc().system_name().await.unwrap(), "Substrate Node");
|
||||
assert!(!api.rpc().system_version().await.unwrap().is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dry_run_passes() {
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let bob = pair_signer(AccountKeyring::Bob.pair());
|
||||
|
||||
wait_for_blocks(&api).await;
|
||||
|
||||
let tx = node_runtime::tx()
|
||||
.balances()
|
||||
.transfer(bob.account_id().clone().into(), 10_000);
|
||||
|
||||
let signed_extrinsic = api
|
||||
.tx()
|
||||
.create_signed(&tx, &alice, Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
api.rpc()
|
||||
.dry_run(signed_extrinsic.encoded(), None)
|
||||
.await
|
||||
.expect("dryrunning failed")
|
||||
.expect("expected dryrunning to be successful")
|
||||
.unwrap();
|
||||
|
||||
signed_extrinsic
|
||||
.submit_and_watch()
|
||||
.await
|
||||
.unwrap()
|
||||
.wait_for_finalized_success()
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dry_run_fails() {
|
||||
let ctx = test_context().await;
|
||||
let api = ctx.client();
|
||||
|
||||
wait_for_blocks(&api).await;
|
||||
|
||||
let alice = pair_signer(AccountKeyring::Alice.pair());
|
||||
let hans = pair_signer(Sr25519Pair::generate().0);
|
||||
|
||||
let tx = node_runtime::tx().balances().transfer(
|
||||
hans.account_id().clone().into(),
|
||||
100_000_000_000_000_000_000_000_000_000_000_000,
|
||||
);
|
||||
|
||||
let signed_extrinsic = api
|
||||
.tx()
|
||||
.create_signed(&tx, &alice, Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let dry_run_res = api
|
||||
.rpc()
|
||||
.dry_run(signed_extrinsic.encoded(), None)
|
||||
.await
|
||||
.expect("dryrunning failed")
|
||||
.expect("expected dryrun transaction to be valid");
|
||||
|
||||
if let Err(sp_runtime::DispatchError::Module(module_error)) = dry_run_res {
|
||||
assert_eq!(module_error.index, 6);
|
||||
assert_eq!(module_error.error, 2);
|
||||
} else {
|
||||
panic!("expected a module error when dryrunning");
|
||||
}
|
||||
|
||||
let res = signed_extrinsic
|
||||
.submit_and_watch()
|
||||
.await
|
||||
.unwrap()
|
||||
.wait_for_finalized_success()
|
||||
.await;
|
||||
|
||||
if let Err(subxt::error::Error::Runtime(DispatchError::Module(err))) = res {
|
||||
assert_eq!(err.pallet, "Balances");
|
||||
assert_eq!(err.error, "InsufficientBalance");
|
||||
} else {
|
||||
panic!("expected a runtime module error");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user