Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit ea501c2

Browse files
Demi-Mariebkchrandresilva
authored
Add ‘transaction_version’ to the signed transaction (#5979)
* Add ‘transaction_version’ to the signed transaction This allows hardware wallets to know which transactions they can safely sign. To reduce transaction size, I reduced it to a ‘u8’ from a ‘u32’. Fixes #5951. * Restore transaction_version to a u32 * Fix comments `transaction_version` is not part of a tx, but is still signed. Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Fix the test suite I had forgotten to change the production of transactions in the test code. * Fix benchmarks * Improve docs for `CheckTxVersion` in `frame_system` Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Remove spurious cast Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
1 parent e1e3848 commit ea501c2

File tree

9 files changed

+81
-25
lines changed

9 files changed

+81
-25
lines changed

bin/node-template/runtime/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,8 @@ pub type SignedBlock = generic::SignedBlock<Block>;
281281
pub type BlockId = generic::BlockId<Block>;
282282
/// The SignedExtension to the basic transaction logic.
283283
pub type SignedExtra = (
284-
system::CheckVersion<Runtime>,
284+
system::CheckSpecVersion<Runtime>,
285+
system::CheckTxVersion<Runtime>,
285286
system::CheckGenesis<Runtime>,
286287
system::CheckEra<Runtime>,
287288
system::CheckNonce<Runtime>,

bin/node/cli/src/service.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -602,20 +602,25 @@ mod tests {
602602
let from: Address = AccountPublic::from(charlie.public()).into_account().into();
603603
let genesis_hash = service.client().block_hash(0).unwrap().unwrap();
604604
let best_block_id = BlockId::number(service.client().chain_info().best_number);
605-
let version = service.client().runtime_version_at(&best_block_id).unwrap().spec_version;
605+
let (spec_version, transaction_version) = {
606+
let version = service.client().runtime_version_at(&best_block_id).unwrap();
607+
(version.spec_version, version.transaction_version)
608+
};
606609
let signer = charlie.clone();
607610

608611
let function = Call::Balances(BalancesCall::transfer(to.into(), amount));
609612

610-
let check_version = frame_system::CheckVersion::new();
613+
let check_spec_version = frame_system::CheckSpecVersion::new();
614+
let check_tx_version = frame_system::CheckTxVersion::new();
611615
let check_genesis = frame_system::CheckGenesis::new();
612616
let check_era = frame_system::CheckEra::from(Era::Immortal);
613617
let check_nonce = frame_system::CheckNonce::from(index);
614618
let check_weight = frame_system::CheckWeight::new();
615619
let payment = pallet_transaction_payment::ChargeTransactionPayment::from(0);
616620
let validate_grandpa_equivocation = pallet_grandpa::ValidateEquivocationReport::new();
617621
let extra = (
618-
check_version,
622+
check_spec_version,
623+
check_tx_version,
619624
check_genesis,
620625
check_era,
621626
check_nonce,
@@ -626,7 +631,7 @@ mod tests {
626631
let raw_payload = SignedPayload::from_raw(
627632
function,
628633
extra,
629-
(version, genesis_hash, genesis_hash, (), (), (), ())
634+
(spec_version, transaction_version, genesis_hash, genesis_hash, (), (), (), ())
630635
);
631636
let signature = raw_payload.using_encoded(|payload| {
632637
signer.sign(payload)

bin/node/executor/benches/bench.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ const COMPACT_CODE: &[u8] = node_runtime::WASM_BINARY;
3939

4040
const GENESIS_HASH: [u8; 32] = [69u8; 32];
4141

42-
const VERSION: u32 = node_runtime::VERSION.spec_version;
42+
const TRANSACTION_VERSION: u32 = node_runtime::VERSION.transaction_version;
43+
44+
const SPEC_VERSION: u32 = node_runtime::VERSION.spec_version;
4345

4446
const HEAP_PAGES: u64 = 20;
4547

@@ -52,7 +54,7 @@ enum ExecutionMethod {
5254
}
5355

5456
fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic {
55-
node_testing::keyring::sign(xt, VERSION, GENESIS_HASH)
57+
node_testing::keyring::sign(xt, SPEC_VERSION, TRANSACTION_VERSION, GENESIS_HASH)
5658
}
5759

5860
fn new_test_ext(genesis_config: &GenesisConfig) -> TestExternalities<BlakeTwo256> {

bin/node/executor/tests/common.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,14 @@ pub const COMPACT_CODE: &[u8] = node_runtime::WASM_BINARY;
7171

7272
pub const GENESIS_HASH: [u8; 32] = [69u8; 32];
7373

74-
pub const VERSION: u32 = node_runtime::VERSION.spec_version;
74+
pub const SPEC_VERSION: u32 = node_runtime::VERSION.spec_version;
75+
76+
pub const TRANSACTION_VERSION: u32 = node_runtime::VERSION.transaction_version;
7577

7678
pub type TestExternalities<H> = CoreTestExternalities<H, u64>;
7779

7880
pub fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic {
79-
node_testing::keyring::sign(xt, VERSION, GENESIS_HASH)
81+
node_testing::keyring::sign(xt, SPEC_VERSION, TRANSACTION_VERSION, GENESIS_HASH)
8082
}
8183

8284
pub fn default_transfer_call() -> pallet_balances::Call<Runtime> {

bin/node/executor/tests/submit_transaction.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ fn should_submit_signed_twice_from_the_same_account() {
122122
let s = state.read();
123123
fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce<Runtime> {
124124
let extra = tx.signature.unwrap().2;
125-
extra.3
125+
extra.4
126126
}
127127
let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap());
128128
let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap());
@@ -170,7 +170,7 @@ fn should_submit_signed_twice_from_all_accounts() {
170170
let s = state.read();
171171
fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce<Runtime> {
172172
let extra = tx.signature.unwrap().2;
173-
extra.3
173+
extra.4
174174
}
175175
let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap());
176176
let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap());

bin/node/runtime/src/lib.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,8 @@ impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for R
535535
.saturating_sub(1);
536536
let tip = 0;
537537
let extra: SignedExtra = (
538-
frame_system::CheckVersion::<Runtime>::new(),
538+
frame_system::CheckSpecVersion::<Runtime>::new(),
539+
frame_system::CheckTxVersion::<Runtime>::new(),
539540
frame_system::CheckGenesis::<Runtime>::new(),
540541
frame_system::CheckEra::<Runtime>::from(generic::Era::mortal(period, current_block)),
541542
frame_system::CheckNonce::<Runtime>::from(nonce),
@@ -745,8 +746,13 @@ pub type SignedBlock = generic::SignedBlock<Block>;
745746
/// BlockId type as expected by this runtime.
746747
pub type BlockId = generic::BlockId<Block>;
747748
/// The SignedExtension to the basic transaction logic.
749+
///
750+
/// When you change this, you **MUST** modify [`sign`] in `bin/node/testing/src/keyring.rs`!
751+
///
752+
/// [`sign`]: <../../testing/src/keyring.rs.html>
748753
pub type SignedExtra = (
749-
frame_system::CheckVersion<Runtime>,
754+
frame_system::CheckSpecVersion<Runtime>,
755+
frame_system::CheckTxVersion<Runtime>,
750756
frame_system::CheckGenesis<Runtime>,
751757
frame_system::CheckEra<Runtime>,
752758
frame_system::CheckNonce<Runtime>,

bin/node/testing/src/keyring.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ pub fn to_session_keys(
6868
/// Returns transaction extra.
6969
pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra {
7070
(
71-
frame_system::CheckVersion::new(),
71+
frame_system::CheckSpecVersion::new(),
72+
frame_system::CheckTxVersion::new(),
7273
frame_system::CheckGenesis::new(),
7374
frame_system::CheckEra::from(Era::mortal(256, 0)),
7475
frame_system::CheckNonce::from(nonce),
@@ -79,10 +80,10 @@ pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra {
7980
}
8081

8182
/// Sign given `CheckedExtrinsic`.
82-
pub fn sign(xt: CheckedExtrinsic, version: u32, genesis_hash: [u8; 32]) -> UncheckedExtrinsic {
83+
pub fn sign(xt: CheckedExtrinsic, spec_version: u32, tx_version: u32, genesis_hash: [u8; 32]) -> UncheckedExtrinsic {
8384
match xt.signed {
8485
Some((signed, extra)) => {
85-
let payload = (xt.function, extra.clone(), version, genesis_hash, genesis_hash);
86+
let payload = (xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash);
8687
let key = AccountKeyring::from_account_id(&signed).unwrap();
8788
let signature = payload.using_encoded(|b| {
8889
if b.len() > 256 {

bin/utils/subkey/src/main.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,8 @@ fn create_extrinsic<C: Crypto>(
702702
{
703703
let extra = |i: Index, f: Balance| {
704704
(
705-
frame_system::CheckVersion::<Runtime>::new(),
705+
frame_system::CheckSpecVersion::<Runtime>::new(),
706+
frame_system::CheckTxVersion::<Runtime>::new(),
706707
frame_system::CheckGenesis::<Runtime>::new(),
707708
frame_system::CheckEra::<Runtime>::from(Era::Immortal),
708709
frame_system::CheckNonce::<Runtime>::from(i),
@@ -715,7 +716,8 @@ fn create_extrinsic<C: Crypto>(
715716
function,
716717
extra(index, 0),
717718
(
718-
VERSION.spec_version as u32,
719+
VERSION.spec_version,
720+
VERSION.transaction_version,
719721
genesis_hash,
720722
genesis_hash,
721723
(),

frame/system/src/lib.rs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@
5353
//! - [`CheckEra`]: Checks the era of the transaction. Contains a single payload of type `Era`.
5454
//! - [`CheckGenesis`]: Checks the provided genesis hash of the transaction. Must be a part of the
5555
//! signed payload of the transaction.
56-
//! - [`CheckVersion`]: Checks that the runtime version is the same as the one encoded in the
56+
//! - [`CheckSpecVersion`]: Checks that the runtime version is the same as the one used to sign the
57+
//! transaction.
58+
//! - [`CheckTxVersion`]: Checks that the transaction version is the same as the one used to sign the
5759
//! transaction.
5860
//!
5961
//! Lookup the runtime aggregator file (e.g. `node/runtime`) to see the full list of signed
@@ -1735,14 +1737,49 @@ impl<T: Trait + Send + Sync> SignedExtension for CheckGenesis<T> {
17351737
}
17361738
}
17371739

1740+
/// Ensure the transaction version registered in the transaction is the same as at present.
1741+
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
1742+
pub struct CheckTxVersion<T: Trait + Send + Sync>(sp_std::marker::PhantomData<T>);
1743+
1744+
impl<T: Trait + Send + Sync> Debug for CheckTxVersion<T> {
1745+
#[cfg(feature = "std")]
1746+
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
1747+
write!(f, "CheckTxVersion")
1748+
}
1749+
1750+
#[cfg(not(feature = "std"))]
1751+
fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
1752+
Ok(())
1753+
}
1754+
}
1755+
1756+
impl<T: Trait + Send + Sync> CheckTxVersion<T> {
1757+
/// Create new `SignedExtension` to check transaction version.
1758+
pub fn new() -> Self {
1759+
Self(sp_std::marker::PhantomData)
1760+
}
1761+
}
1762+
1763+
impl<T: Trait + Send + Sync> SignedExtension for CheckTxVersion<T> {
1764+
type AccountId = T::AccountId;
1765+
type Call = <T as Trait>::Call;
1766+
type AdditionalSigned = u32;
1767+
type Pre = ();
1768+
const IDENTIFIER: &'static str = "CheckTxVersion";
1769+
1770+
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
1771+
Ok(<Module<T>>::runtime_version().transaction_version)
1772+
}
1773+
}
1774+
17381775
/// Ensure the runtime version registered in the transaction is the same as at present.
17391776
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
1740-
pub struct CheckVersion<T: Trait + Send + Sync>(sp_std::marker::PhantomData<T>);
1777+
pub struct CheckSpecVersion<T: Trait + Send + Sync>(sp_std::marker::PhantomData<T>);
17411778

1742-
impl<T: Trait + Send + Sync> Debug for CheckVersion<T> {
1779+
impl<T: Trait + Send + Sync> Debug for CheckSpecVersion<T> {
17431780
#[cfg(feature = "std")]
17441781
fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
1745-
write!(f, "CheckVersion")
1782+
write!(f, "CheckSpecVersion")
17461783
}
17471784

17481785
#[cfg(not(feature = "std"))]
@@ -1751,19 +1788,19 @@ impl<T: Trait + Send + Sync> Debug for CheckVersion<T> {
17511788
}
17521789
}
17531790

1754-
impl<T: Trait + Send + Sync> CheckVersion<T> {
1791+
impl<T: Trait + Send + Sync> CheckSpecVersion<T> {
17551792
/// Create new `SignedExtension` to check runtime version.
17561793
pub fn new() -> Self {
17571794
Self(sp_std::marker::PhantomData)
17581795
}
17591796
}
17601797

1761-
impl<T: Trait + Send + Sync> SignedExtension for CheckVersion<T> {
1798+
impl<T: Trait + Send + Sync> SignedExtension for CheckSpecVersion<T> {
17621799
type AccountId = T::AccountId;
17631800
type Call = <T as Trait>::Call;
17641801
type AdditionalSigned = u32;
17651802
type Pre = ();
1766-
const IDENTIFIER: &'static str = "CheckVersion";
1803+
const IDENTIFIER: &'static str = "CheckSpecVersion";
17671804

17681805
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
17691806
Ok(<Module<T>>::runtime_version().spec_version)

0 commit comments

Comments
 (0)