Files
pezkuwi-subxt/testing/integration-tests/src/full_client/transactions.rs
T
James Wilson b6b9ac65c7 Support constructing and submitting V5 transactions (#1931)
* TransactionExtensions basic support for V5 VerifySignature and renames

* WIP: subxt-core v5 transaction support

* Subxt to support V5 extrinsics

* WIP tests failing with wsm trap error

* Actually encode mortality to fix tx encode issue

* fmt

* rename to sign_with_account_and_signature

* Add explicit methods for v4 and v5 ext construction

* clippy

* fix wasm example and no mut self where not needed

* fix doc example

* another doc fix

* Add tests for tx encoding and fix v5 encode issue

* add copyright and todo

* refactor APIs to have clear v4/v5 split in core and slightly nicer split in subxt proper

* rename Partial/SubmittableExtrinsic to *Transaction

* Remove SignerT::address since it's not needed

* doc fixes

* fmt

* doc fixes

* Fix comment number

* Clarify panic behaviour of inject_signature

* fmt
2025-03-11 11:14:27 +00:00

150 lines
4.6 KiB
Rust

// Copyright 2019-2025 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::utils::node_runtime;
use crate::{subxt_test, test_context};
use core::ops::Deref;
use frame_decode::extrinsics::ExtrinsicType;
use subxt_signer::sr25519::dev;
// TODO: When VerifySignature exists on the substrate kitchensink runtime,
// let's try actuallty submitting v4 and v5 signed extrinsics to verify that
// they are actually accepted by the node.
#[subxt_test]
async fn v4_unsigned_encode_decode() -> Result<(), subxt::Error> {
let ctx = test_context().await;
let api = ctx.client();
let md = api.metadata();
let call = node_runtime::tx()
.balances()
.transfer_allow_death(dev::bob().public_key().into(), 1000);
let tx_bytes = api.tx().create_v4_unsigned(&call).unwrap().into_encoded();
let tx_bytes_cursor = &mut &*tx_bytes;
let decoded = frame_decode::extrinsics::decode_extrinsic(
tx_bytes_cursor,
md.deref(),
api.metadata().types(),
)
.unwrap();
assert_eq!(tx_bytes_cursor.len(), 0);
assert_eq!(decoded.version(), 4);
assert_eq!(decoded.ty(), ExtrinsicType::Bare);
assert_eq!(decoded.pallet_name(), "Balances");
assert_eq!(decoded.call_name(), "transfer_allow_death");
assert!(decoded.signature_payload().is_none());
Ok(())
}
#[subxt_test]
async fn v5_bare_encode_decode() -> Result<(), subxt::Error> {
let ctx = test_context().await;
let api = ctx.client();
let md = api.metadata();
let call = node_runtime::tx()
.balances()
.transfer_allow_death(dev::bob().public_key().into(), 1000);
let tx_bytes = api.tx().create_v5_bare(&call).unwrap().into_encoded();
let tx_bytes_cursor = &mut &*tx_bytes;
let decoded = frame_decode::extrinsics::decode_extrinsic(
tx_bytes_cursor,
md.deref(),
api.metadata().types(),
)
.unwrap();
assert_eq!(tx_bytes_cursor.len(), 0);
assert_eq!(decoded.version(), 5);
assert_eq!(decoded.ty(), ExtrinsicType::Bare);
assert_eq!(decoded.pallet_name(), "Balances");
assert_eq!(decoded.call_name(), "transfer_allow_death");
assert!(decoded.transaction_extension_payload().is_none());
assert!(decoded.signature_payload().is_none());
Ok(())
}
#[subxt_test]
async fn v4_signed_encode_decode() -> Result<(), subxt::Error> {
let ctx = test_context().await;
let api = ctx.client();
let md = api.metadata();
let call = node_runtime::tx()
.balances()
.transfer_allow_death(dev::bob().public_key().into(), 1000);
let tx_bytes = api
.tx()
.create_v4_partial(&call, &dev::alice().public_key().into(), Default::default())
.await
.unwrap()
.sign(&dev::alice())
.into_encoded();
let tx_bytes_cursor = &mut &*tx_bytes;
let decoded = frame_decode::extrinsics::decode_extrinsic(
tx_bytes_cursor,
md.deref(),
api.metadata().types(),
)
.unwrap();
assert_eq!(tx_bytes_cursor.len(), 0);
assert_eq!(decoded.version(), 4);
assert_eq!(decoded.ty(), ExtrinsicType::Signed);
assert_eq!(decoded.pallet_name(), "Balances");
assert_eq!(decoded.call_name(), "transfer_allow_death");
assert!(decoded.signature_payload().is_some());
Ok(())
}
#[subxt_test]
async fn v5_general_encode_decode() -> Result<(), subxt::Error> {
let ctx = test_context().await;
let api = ctx.client();
let md = api.metadata();
let dummy_signer = dev::alice();
let call = node_runtime::tx()
.balances()
.transfer_allow_death(dev::bob().public_key().into(), 1000);
let tx_bytes = api
.tx()
.create_v5_partial(&call, &dev::alice().public_key().into(), Default::default())
.await
.unwrap()
.sign(&dummy_signer) // No signature payload is added, but may be inserted into tx extensions.
.into_encoded();
let tx_bytes_cursor = &mut &*tx_bytes;
let decoded = frame_decode::extrinsics::decode_extrinsic(
tx_bytes_cursor,
md.deref(),
api.metadata().types(),
)
.unwrap();
assert_eq!(tx_bytes_cursor.len(), 0);
assert_eq!(decoded.version(), 5);
assert_eq!(decoded.ty(), ExtrinsicType::General);
assert_eq!(decoded.pallet_name(), "Balances");
assert_eq!(decoded.call_name(), "transfer_allow_death");
assert!(decoded.transaction_extension_payload().is_some());
// v5 general extrinsics have no signature payload; signature in tx extensions:
assert!(decoded.signature_payload().is_none());
Ok(())
}