mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-22 07:58:02 +00:00
ef89752904
* rpc/types: Decode `SubstrateTxStatus` for substrate and smoldot Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Add light client Error Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Add background task to manage RPC responses Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Implement the light client RPC in subxt Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * subxt: Expose light client under experimental feature-flag Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * artifacts: Add development chain spec for local nodes Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update cargo lock Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * examples: Add light client example Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update sp-* crates and smoldot to use git with branch / rev Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Apply cargo fmt Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Fix clippy Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Import hashmap entry Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Fetch spec only if jsonrpsee feature is enabled Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update subxt/src/rpc/lightclient/background.rs Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com> * Fix typo Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * artifacts: Update dev chain spec Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * types: Handle storage replies from chainHead_storage Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * artifacts: Add polkadot spec Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Handle RPC error responses Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * examples: Tx basic with light client for local nodes Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * example: Light client coprehensive example for live chains Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * examples: Remove prior light client example Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * feature: Rename experimental to unstable Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * book: Add light client section Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * testing: Fix clippy Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Ignore validated events Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust tests for light-clients and normal clients Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * testing: Keep lightclient variant Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Remove support for chainHead_storage for light client Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update light client to point to crates.io Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update sp-crates from crates.io Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Replace Atomic with u64 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add LightClientBuilder Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust chainspec with provided bootnodes Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add potential_relay_chains to light client builder Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Move the light-client to the background task Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust tracing logs Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update book and example Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Apply cargo fmt Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Remove dev_spec.json artifact Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Examples fix duplicate Cargo.toml Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Use tracing_subscriber crate Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Fix clippy for different features Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add comment about bootNodes Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add comment about tracing-sub dependency Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Run integration-tests with light-client Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Feature guard some incompatible tests Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * ci: Enable light-client tests under feature flag Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * ci: Fix git step name Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust flags for testing Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust warnings Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Rename feature flag jsonrpsee-ws to jsonrpsee Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Fix cargo check Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * ci: Run tests on just 2 threads Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Move light-client to subxt/src/client Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust LightClientBuilder Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Use ws_url to construct light client for testing Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Refactor background Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Address feedback Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Remove polkadot.spec and trim sub_id Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Wait for substrate to produce block before connecting light client Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust builder and tests Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Apply fmt Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * ci: Use release for light client testing Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Add single test for light-client Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Wait for more blocks Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Use polkadot endpoint for testing Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust cargo check Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * examples: Remove light client chain connection example Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust cargo.toml section for the old example Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust background task to use usize for subscription Id Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Build bootnodes with serde_json::Value directly Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Make channel between subxt user and subxt background unbounded Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Update subxt/src/client/lightclient/builder.rs Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com> * Switch to smoldot 0.6.0 from 0.5.0 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Move testing to `full_client` and `light_client` higher modules Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Remove subscriptionID type Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Remove subxt/integration-testing feature flag Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust wait_for_blocks documentation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust utils import for testing Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Remove into_iter from builder construction Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>
409 lines
11 KiB
Rust
409 lines
11 KiB
Rust
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
|
// see LICENSE for license details.
|
|
|
|
use crate::{
|
|
node_runtime::{self, balances, runtime_types, system},
|
|
test_context,
|
|
};
|
|
use codec::Decode;
|
|
use subxt::{
|
|
error::{DispatchError, Error, TokenError},
|
|
utils::{AccountId32, MultiAddress},
|
|
};
|
|
use subxt_signer::sr25519::dev;
|
|
|
|
#[tokio::test]
|
|
async fn tx_basic_transfer() -> Result<(), subxt::Error> {
|
|
let alice = dev::alice();
|
|
let bob = dev::bob();
|
|
let bob_address = bob.public_key().to_address();
|
|
let ctx = test_context().await;
|
|
let api = ctx.client();
|
|
|
|
let alice_account_addr = node_runtime::storage()
|
|
.system()
|
|
.account(alice.public_key().to_account_id());
|
|
let bob_account_addr = node_runtime::storage()
|
|
.system()
|
|
.account(bob.public_key().to_account_id());
|
|
|
|
let alice_pre = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&alice_account_addr)
|
|
.await?;
|
|
let bob_pre = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&bob_account_addr)
|
|
.await?;
|
|
|
|
let tx = node_runtime::tx().balances().transfer(bob_address, 10_000);
|
|
|
|
let events = api
|
|
.tx()
|
|
.sign_and_submit_then_watch_default(&tx, &alice)
|
|
.await?
|
|
.wait_for_finalized_success()
|
|
.await?;
|
|
let event = events
|
|
.find_first::<balances::events::Transfer>()
|
|
.expect("Failed to decode balances::events::Transfer")
|
|
.expect("Failed to find balances::events::Transfer");
|
|
let _extrinsic_success = events
|
|
.find_first::<system::events::ExtrinsicSuccess>()
|
|
.expect("Failed to decode ExtrinisicSuccess")
|
|
.expect("Failed to find ExtrinisicSuccess");
|
|
|
|
let expected_event = balances::events::Transfer {
|
|
from: alice.public_key().to_account_id(),
|
|
to: bob.public_key().to_account_id(),
|
|
amount: 10_000,
|
|
};
|
|
assert_eq!(event, expected_event);
|
|
|
|
let alice_post = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&alice_account_addr)
|
|
.await?;
|
|
let bob_post = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&bob_account_addr)
|
|
.await?;
|
|
|
|
assert!(alice_pre.data.free - 10_000 >= alice_post.data.free);
|
|
assert_eq!(bob_pre.data.free + 10_000, bob_post.data.free);
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn tx_dynamic_transfer() -> Result<(), subxt::Error> {
|
|
use subxt::ext::scale_value::{At, Composite, Value};
|
|
|
|
let alice = dev::alice();
|
|
let bob = dev::bob();
|
|
let ctx = test_context().await;
|
|
let api = ctx.client();
|
|
|
|
let alice_account_addr = subxt::dynamic::storage(
|
|
"System",
|
|
"Account",
|
|
vec![Value::from_bytes(alice.public_key().to_account_id())],
|
|
);
|
|
let bob_account_addr = subxt::dynamic::storage(
|
|
"System",
|
|
"Account",
|
|
vec![Value::from_bytes(bob.public_key().to_account_id())],
|
|
);
|
|
|
|
let alice_pre = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&alice_account_addr)
|
|
.await?;
|
|
let bob_pre = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&bob_account_addr)
|
|
.await?;
|
|
|
|
let tx = subxt::dynamic::tx(
|
|
"Balances",
|
|
"transfer",
|
|
vec![
|
|
Value::unnamed_variant(
|
|
"Id",
|
|
vec![Value::from_bytes(bob.public_key().to_account_id())],
|
|
),
|
|
Value::u128(10_000u128),
|
|
],
|
|
);
|
|
|
|
let events = api
|
|
.tx()
|
|
.sign_and_submit_then_watch_default(&tx, &alice)
|
|
.await?
|
|
.wait_for_finalized_success()
|
|
.await?;
|
|
|
|
let event_fields = events
|
|
.iter()
|
|
.filter_map(|ev| ev.ok())
|
|
.find(|ev| ev.pallet_name() == "Balances" && ev.variant_name() == "Transfer")
|
|
.expect("Failed to find Transfer event")
|
|
.field_values()?
|
|
.map_context(|_| ());
|
|
|
|
let expected_fields = Composite::Named(vec![
|
|
(
|
|
"from".into(),
|
|
Value::unnamed_composite(vec![Value::from_bytes(alice.public_key().to_account_id())]),
|
|
),
|
|
(
|
|
"to".into(),
|
|
Value::unnamed_composite(vec![Value::from_bytes(bob.public_key().to_account_id())]),
|
|
),
|
|
("amount".into(), Value::u128(10_000)),
|
|
]);
|
|
assert_eq!(event_fields, expected_fields);
|
|
|
|
let alice_post = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&alice_account_addr)
|
|
.await?;
|
|
let bob_post = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&bob_account_addr)
|
|
.await?;
|
|
|
|
let alice_pre_free = alice_pre
|
|
.to_value()?
|
|
.at("data")
|
|
.at("free")
|
|
.unwrap()
|
|
.as_u128()
|
|
.unwrap();
|
|
let alice_post_free = alice_post
|
|
.to_value()?
|
|
.at("data")
|
|
.at("free")
|
|
.unwrap()
|
|
.as_u128()
|
|
.unwrap();
|
|
|
|
let bob_pre_free = bob_pre
|
|
.to_value()?
|
|
.at("data")
|
|
.at("free")
|
|
.unwrap()
|
|
.as_u128()
|
|
.unwrap();
|
|
let bob_post_free = bob_post
|
|
.to_value()?
|
|
.at("data")
|
|
.at("free")
|
|
.unwrap()
|
|
.as_u128()
|
|
.unwrap();
|
|
|
|
assert!(alice_pre_free - 10_000 >= alice_post_free);
|
|
assert_eq!(bob_pre_free + 10_000, bob_post_free);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn multiple_transfers_work_nonce_incremented() -> Result<(), subxt::Error> {
|
|
let alice = dev::alice();
|
|
let bob = dev::bob();
|
|
let bob_address: MultiAddress<AccountId32, u32> = bob.public_key().into();
|
|
let ctx = test_context().await;
|
|
let api = ctx.client();
|
|
|
|
let bob_account_addr = node_runtime::storage()
|
|
.system()
|
|
.account(bob.public_key().to_account_id());
|
|
|
|
let bob_pre = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&bob_account_addr)
|
|
.await?;
|
|
|
|
let tx = node_runtime::tx()
|
|
.balances()
|
|
.transfer(bob_address.clone(), 10_000);
|
|
for _ in 0..3 {
|
|
api.tx()
|
|
.sign_and_submit_then_watch_default(&tx, &alice)
|
|
.await?
|
|
.wait_for_in_block() // Don't need to wait for finalization; this is quicker.
|
|
.await?
|
|
.wait_for_success()
|
|
.await?;
|
|
}
|
|
|
|
let bob_post = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&bob_account_addr)
|
|
.await?;
|
|
|
|
assert_eq!(bob_pre.data.free + 30_000, bob_post.data.free);
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn storage_total_issuance() {
|
|
let ctx = test_context().await;
|
|
let api = ctx.client();
|
|
|
|
let addr = node_runtime::storage().balances().total_issuance();
|
|
let total_issuance = api
|
|
.storage()
|
|
.at_latest()
|
|
.await
|
|
.unwrap()
|
|
.fetch_or_default(&addr)
|
|
.await
|
|
.unwrap();
|
|
assert_ne!(total_issuance, 0);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn storage_balance_lock() -> Result<(), subxt::Error> {
|
|
let bob_signer = dev::bob();
|
|
let bob: AccountId32 = dev::bob().public_key().into();
|
|
let charlie: AccountId32 = dev::charlie().public_key().into();
|
|
let ctx = test_context().await;
|
|
let api = ctx.client();
|
|
|
|
let tx = node_runtime::tx().staking().bond(
|
|
charlie.into(),
|
|
100_000_000_000_000,
|
|
runtime_types::pallet_staking::RewardDestination::Stash,
|
|
);
|
|
|
|
api.tx()
|
|
.sign_and_submit_then_watch_default(&tx, &bob_signer)
|
|
.await?
|
|
.wait_for_finalized_success()
|
|
.await?
|
|
.find_first::<system::events::ExtrinsicSuccess>()?
|
|
.expect("No ExtrinsicSuccess Event found");
|
|
|
|
let locks_addr = node_runtime::storage().balances().locks(bob);
|
|
|
|
let locks = api
|
|
.storage()
|
|
.at_latest()
|
|
.await?
|
|
.fetch_or_default(&locks_addr)
|
|
.await?;
|
|
|
|
assert_eq!(
|
|
locks.0,
|
|
vec![runtime_types::pallet_balances::types::BalanceLock {
|
|
id: *b"staking ",
|
|
amount: 100_000_000_000_000,
|
|
reasons: runtime_types::pallet_balances::types::Reasons::All,
|
|
}]
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn transfer_error() {
|
|
let alice = dev::alice();
|
|
let alice_addr = alice.public_key().into();
|
|
let bob = dev::one(); // some dev account with no funds.
|
|
let bob_address = bob.public_key().into();
|
|
let ctx = test_context().await;
|
|
let api = ctx.client();
|
|
|
|
let to_bob_tx = node_runtime::tx()
|
|
.balances()
|
|
.transfer(bob_address, 100_000_000_000_000_000);
|
|
let to_alice_tx = node_runtime::tx()
|
|
.balances()
|
|
.transfer(alice_addr, 100_000_000_000_000_000);
|
|
|
|
api.tx()
|
|
.sign_and_submit_then_watch_default(&to_bob_tx, &alice)
|
|
.await
|
|
.unwrap()
|
|
.wait_for_finalized_success()
|
|
.await
|
|
.unwrap();
|
|
|
|
// When we try giving all of the funds back, Bob doesn't have
|
|
// anything left to pay transfer fees, so we hit an error.
|
|
let res = api
|
|
.tx()
|
|
.sign_and_submit_then_watch_default(&to_alice_tx, &bob)
|
|
.await
|
|
.unwrap()
|
|
.wait_for_finalized_success()
|
|
.await;
|
|
|
|
assert!(
|
|
matches!(
|
|
res,
|
|
Err(Error::Runtime(DispatchError::Token(
|
|
TokenError::FundsUnavailable
|
|
)))
|
|
),
|
|
"Expected an insufficient balance, got {res:?}"
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn transfer_implicit_subscription() {
|
|
let alice = dev::alice();
|
|
let bob: AccountId32 = dev::bob().public_key().into();
|
|
let ctx = test_context().await;
|
|
let api = ctx.client();
|
|
|
|
let to_bob_tx = node_runtime::tx()
|
|
.balances()
|
|
.transfer(bob.clone().into(), 10_000);
|
|
|
|
let event = api
|
|
.tx()
|
|
.sign_and_submit_then_watch_default(&to_bob_tx, &alice)
|
|
.await
|
|
.unwrap()
|
|
.wait_for_finalized_success()
|
|
.await
|
|
.unwrap()
|
|
.find_first::<balances::events::Transfer>()
|
|
.expect("Can decode events")
|
|
.expect("Can find balance transfer event");
|
|
|
|
assert_eq!(
|
|
event,
|
|
balances::events::Transfer {
|
|
from: alice.public_key().to_account_id(),
|
|
to: bob,
|
|
amount: 10_000
|
|
}
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn constant_existential_deposit() {
|
|
let ctx = test_context().await;
|
|
let api = ctx.client();
|
|
|
|
// get and decode constant manually via metadata:
|
|
let metadata = api.metadata();
|
|
let balances_metadata = metadata.pallet_by_name("Balances").unwrap();
|
|
let constant_metadata = balances_metadata
|
|
.constant_by_name("ExistentialDeposit")
|
|
.unwrap();
|
|
let existential_deposit = u128::decode(&mut constant_metadata.value()).unwrap();
|
|
assert_eq!(existential_deposit, 100_000_000_000_000);
|
|
|
|
// constant address for API access:
|
|
let addr = node_runtime::constants().balances().existential_deposit();
|
|
|
|
// Make sure thetwo are identical:
|
|
assert_eq!(existential_deposit, api.constants().at(&addr).unwrap());
|
|
}
|