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>
This commit is contained in:
Demi Obenour
2020-05-14 22:01:56 +00:00
committed by GitHub
parent d169a48dfb
commit ddea306044
9 changed files with 82 additions and 26 deletions
+9 -4
View File
@@ -602,12 +602,16 @@ mod tests {
let from: Address = AccountPublic::from(charlie.public()).into_account().into();
let genesis_hash = service.client().block_hash(0).unwrap().unwrap();
let best_block_id = BlockId::number(service.client().chain_info().best_number);
let version = service.client().runtime_version_at(&best_block_id).unwrap().spec_version;
let (spec_version, transaction_version) = {
let version = service.client().runtime_version_at(&best_block_id).unwrap();
(version.spec_version, version.transaction_version)
};
let signer = charlie.clone();
let function = Call::Balances(BalancesCall::transfer(to.into(), amount));
let check_version = frame_system::CheckVersion::new();
let check_spec_version = frame_system::CheckSpecVersion::new();
let check_tx_version = frame_system::CheckTxVersion::new();
let check_genesis = frame_system::CheckGenesis::new();
let check_era = frame_system::CheckEra::from(Era::Immortal);
let check_nonce = frame_system::CheckNonce::from(index);
@@ -615,7 +619,8 @@ mod tests {
let payment = pallet_transaction_payment::ChargeTransactionPayment::from(0);
let validate_grandpa_equivocation = pallet_grandpa::ValidateEquivocationReport::new();
let extra = (
check_version,
check_spec_version,
check_tx_version,
check_genesis,
check_era,
check_nonce,
@@ -626,7 +631,7 @@ mod tests {
let raw_payload = SignedPayload::from_raw(
function,
extra,
(version, genesis_hash, genesis_hash, (), (), (), ())
(spec_version, transaction_version, genesis_hash, genesis_hash, (), (), (), ())
);
let signature = raw_payload.using_encoded(|payload| {
signer.sign(payload)
+4 -2
View File
@@ -39,7 +39,9 @@ const COMPACT_CODE: &[u8] = node_runtime::WASM_BINARY;
const GENESIS_HASH: [u8; 32] = [69u8; 32];
const VERSION: u32 = node_runtime::VERSION.spec_version;
const TRANSACTION_VERSION: u32 = node_runtime::VERSION.transaction_version;
const SPEC_VERSION: u32 = node_runtime::VERSION.spec_version;
const HEAP_PAGES: u64 = 20;
@@ -52,7 +54,7 @@ enum ExecutionMethod {
}
fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic {
node_testing::keyring::sign(xt, VERSION, GENESIS_HASH)
node_testing::keyring::sign(xt, SPEC_VERSION, TRANSACTION_VERSION, GENESIS_HASH)
}
fn new_test_ext(genesis_config: &GenesisConfig) -> TestExternalities<BlakeTwo256> {
+4 -2
View File
@@ -71,12 +71,14 @@ pub const COMPACT_CODE: &[u8] = node_runtime::WASM_BINARY;
pub const GENESIS_HASH: [u8; 32] = [69u8; 32];
pub const VERSION: u32 = node_runtime::VERSION.spec_version;
pub const SPEC_VERSION: u32 = node_runtime::VERSION.spec_version;
pub const TRANSACTION_VERSION: u32 = node_runtime::VERSION.transaction_version;
pub type TestExternalities<H> = CoreTestExternalities<H, u64>;
pub fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic {
node_testing::keyring::sign(xt, VERSION, GENESIS_HASH)
node_testing::keyring::sign(xt, SPEC_VERSION, TRANSACTION_VERSION, GENESIS_HASH)
}
pub fn default_transfer_call() -> pallet_balances::Call<Runtime> {
@@ -122,7 +122,7 @@ fn should_submit_signed_twice_from_the_same_account() {
let s = state.read();
fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce<Runtime> {
let extra = tx.signature.unwrap().2;
extra.3
extra.4
}
let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap());
let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap());
@@ -170,7 +170,7 @@ fn should_submit_signed_twice_from_all_accounts() {
let s = state.read();
fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce<Runtime> {
let extra = tx.signature.unwrap().2;
extra.3
extra.4
}
let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap());
let nonce2 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[1]).unwrap());
+8 -2
View File
@@ -535,7 +535,8 @@ impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for R
.saturating_sub(1);
let tip = 0;
let extra: SignedExtra = (
frame_system::CheckVersion::<Runtime>::new(),
frame_system::CheckSpecVersion::<Runtime>::new(),
frame_system::CheckTxVersion::<Runtime>::new(),
frame_system::CheckGenesis::<Runtime>::new(),
frame_system::CheckEra::<Runtime>::from(generic::Era::mortal(period, current_block)),
frame_system::CheckNonce::<Runtime>::from(nonce),
@@ -745,8 +746,13 @@ pub type SignedBlock = generic::SignedBlock<Block>;
/// BlockId type as expected by this runtime.
pub type BlockId = generic::BlockId<Block>;
/// The SignedExtension to the basic transaction logic.
///
/// When you change this, you **MUST** modify [`sign`] in `bin/node/testing/src/keyring.rs`!
///
/// [`sign`]: <../../testing/src/keyring.rs.html>
pub type SignedExtra = (
frame_system::CheckVersion<Runtime>,
frame_system::CheckSpecVersion<Runtime>,
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
+4 -3
View File
@@ -68,7 +68,8 @@ pub fn to_session_keys(
/// Returns transaction extra.
pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra {
(
frame_system::CheckVersion::new(),
frame_system::CheckSpecVersion::new(),
frame_system::CheckTxVersion::new(),
frame_system::CheckGenesis::new(),
frame_system::CheckEra::from(Era::mortal(256, 0)),
frame_system::CheckNonce::from(nonce),
@@ -79,10 +80,10 @@ pub fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra {
}
/// Sign given `CheckedExtrinsic`.
pub fn sign(xt: CheckedExtrinsic, version: u32, genesis_hash: [u8; 32]) -> UncheckedExtrinsic {
pub fn sign(xt: CheckedExtrinsic, spec_version: u32, tx_version: u32, genesis_hash: [u8; 32]) -> UncheckedExtrinsic {
match xt.signed {
Some((signed, extra)) => {
let payload = (xt.function, extra.clone(), version, genesis_hash, genesis_hash);
let payload = (xt.function, extra.clone(), spec_version, tx_version, genesis_hash, genesis_hash);
let key = AccountKeyring::from_account_id(&signed).unwrap();
let signature = payload.using_encoded(|b| {
if b.len() > 256 {