Extensible transactions (and tips) (#3102)

* Make extrinsics extensible.

Also Remove old extrinsic types.

* Rest of mockup. Add tips.

* Fix some build issues

* Runtiem builds :)

* Substrate builds.

* Fix a doc test

* Compact encoding

* Extract out the era logic into an extension

* Weight Check signed extension. (#3115)

* Weight signed extension.

* Revert a bit + test for check era.

* Update Cargo.toml

* Update node/cli/src/factory_impl.rs

* Update node/executor/src/lib.rs

* Update node/executor/src/lib.rs

* Don't use len for weight - use data.

* Operational Transaction; second attempt (#3138)

* working poc added.

* some fixes.

* Update doc.

* Fix all tests + final logic.

* more refactoring.

* nits.

* System block limit in bytes.

* Silent the storage macro warnings.

* More logic more tests.

* Fix import.

* Refactor names.

* Fix build.

* Update srml/balances/src/lib.rs

* Final refactor.

* Bump transaction version

* Fix weight mult test.

* Fix more tests and improve doc.

* Bump.

* Make some tests work again.

* Fix subkey.

* Remove todos + bump.

* Ignore expensive test.

* Bump.
This commit is contained in:
Gavin Wood
2019-07-23 01:06:49 +08:00
committed by Kian Peymani
parent 4f5654b67d
commit 78bc5edc14
55 changed files with 1965 additions and 1646 deletions
+75 -130
View File
@@ -40,24 +40,25 @@ mod tests {
use substrate_executor::{WasmExecutor, NativeExecutionDispatch};
use parity_codec::{Encode, Decode, Joiner};
use keyring::{AuthorityKeyring, AccountKeyring};
use runtime_support::{Hashable, StorageValue, StorageMap, traits::Currency};
use runtime_support::{Hashable, StorageValue, StorageMap, traits::{Currency, Get}};
use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities};
use primitives::{
twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue,
NativeOrEncoded
};
use node_primitives::{Hash, BlockNumber, AccountId};
use node_primitives::{Hash, BlockNumber, AccountId, Balance, Index};
use runtime_primitives::traits::{Header as HeaderT, Hash as HashT};
use runtime_primitives::{generic::Era, ApplyOutcome, ApplyError, ApplyResult, Perbill};
use runtime_primitives::weights::{IDEAL_TRANSACTIONS_WEIGHT, WeightMultiplier};
use runtime_primitives::weights::{WeightMultiplier, SimpleDispatchInfo, WeighData};
use {balances, contracts, indices, staking, system, timestamp};
use contracts::ContractAddressFor;
use system::{EventRecord, Phase};
use node_runtime::{
Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, BuildStorage,
GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, System, SystemConfig,
GrandpaConfig, IndicesConfig, ContractsConfig, Event, SessionKeys,
CENTS, DOLLARS, MILLICENTS,
GrandpaConfig, IndicesConfig, ContractsConfig, Event, SessionKeys, CreationFee,
CENTS, DOLLARS, MILLICENTS, SignedExtra, TransactionBaseFee, TransactionByteFee,
MaximumBlockWeight,
};
use wabt;
use primitives::map;
@@ -78,13 +79,25 @@ mod tests {
const BLOATY_CODE: &[u8] = node_runtime::WASM_BINARY_BLOATY;
const GENESIS_HASH: [u8; 32] = [69u8; 32];
// from weight
const TX_FEE: u128 = 146;
// regardless of creation of transfer
const TRANSFER_FEE: u128 = 1 * CENTS;
type TestExternalities<H> = CoreTestExternalities<H, u64>;
fn transfer_fee<E: Encode>(extrinsic: &E) -> Balance {
let length_fee = <TransactionBaseFee as Get<Balance>>::get() +
<TransactionByteFee as Get<Balance>>::get() *
(extrinsic.encode().len() as Balance);
let weight_fee = SimpleDispatchInfo::default().weigh_data(()) as Balance;
length_fee + weight_fee
}
fn multiplier_ideal() -> u32 {
<MaximumBlockWeight as Get<u32>>::get() / 4 / 4
}
fn creation_fee() -> Balance {
<CreationFee as Get<Balance>>::get()
}
fn alice() -> AccountId {
AccountKeyring::Alice.into()
}
@@ -111,9 +124,8 @@ mod tests {
fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic {
match xt.signed {
Some((signed, index)) => {
let era = Era::mortal(256, 0);
let payload = (index.into(), xt.function, era, GENESIS_HASH);
Some((signed, extra)) => {
let payload = (xt.function, extra.clone(), GENESIS_HASH);
let key = AccountKeyring::from_public(&signed).unwrap();
let signature = payload.using_encoded(|b| {
if b.len() > 256 {
@@ -123,8 +135,8 @@ mod tests {
}
}).into();
UncheckedExtrinsic {
signature: Some((indices::address::Address::Id(signed), signature, payload.0, era)),
function: payload.1,
signature: Some((indices::address::Address::Id(signed), signature, extra)),
function: payload.0,
}
}
None => UncheckedExtrinsic {
@@ -134,9 +146,18 @@ mod tests {
}
}
fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra {
(
system::CheckEra::from(Era::mortal(256, 0)),
system::CheckNonce::from(nonce),
system::CheckWeight::from(),
balances::TakeFees::from(extra_fee)
)
}
fn xt() -> UncheckedExtrinsic {
sign(CheckedExtrinsic {
signed: Some((alice(), 0)),
signed: Some((alice(), signed_extra(0, 0))),
function: Call::Balances(balances::Call::transfer::<Runtime>(bob().into(), 69 * DOLLARS)),
})
}
@@ -252,7 +273,7 @@ mod tests {
assert!(r.is_ok());
runtime_io::with_externalities(&mut t, || {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - TX_FEE - TRANSFER_FEE);
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt()) - creation_fee());
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
@@ -288,7 +309,7 @@ mod tests {
assert!(r.is_ok());
runtime_io::with_externalities(&mut t, || {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - TX_FEE - TRANSFER_FEE);
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt()) - creation_fee());
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
@@ -433,7 +454,7 @@ mod tests {
function: Call::Timestamp(timestamp::Call::set(42)),
},
CheckedExtrinsic {
signed: Some((alice(), 0)),
signed: Some((alice(), signed_extra(0, 0))),
function: Call::Balances(balances::Call::transfer(bob().into(), 69 * DOLLARS)),
},
]
@@ -455,7 +476,7 @@ mod tests {
function: Call::Timestamp(timestamp::Call::set(42)),
},
CheckedExtrinsic {
signed: Some((alice(), 0)),
signed: Some((alice(), signed_extra(0, 0))),
function: Call::Balances(balances::Call::transfer(bob().into(), 69 * DOLLARS)),
},
]
@@ -470,11 +491,11 @@ mod tests {
function: Call::Timestamp(timestamp::Call::set(52)),
},
CheckedExtrinsic {
signed: Some((bob(), 0)),
signed: Some((bob(), signed_extra(0, 0))),
function: Call::Balances(balances::Call::transfer(alice().into(), 5 * DOLLARS)),
},
CheckedExtrinsic {
signed: Some((alice(), 1)),
signed: Some((alice(), signed_extra(1, 0))),
function: Call::Balances(balances::Call::transfer(bob().into(), 15 * DOLLARS)),
}
]
@@ -498,7 +519,7 @@ mod tests {
function: Call::Timestamp(timestamp::Call::set(time)),
},
CheckedExtrinsic {
signed: Some((charlie(), nonce)),
signed: Some((alice(), signed_extra(nonce, 0))),
function: Call::System(system::Call::remark(vec![0; size])),
}
]
@@ -520,9 +541,7 @@ mod tests {
).0.unwrap();
runtime_io::with_externalities(&mut t, || {
// block1 transfers from alice 69 to bob.
// -1 is the default fee
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - TX_FEE - TRANSFER_FEE);
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt()) - creation_fee());
assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS);
let events = vec![
EventRecord {
@@ -557,11 +576,9 @@ mod tests {
).0.unwrap();
runtime_io::with_externalities(&mut t, || {
// bob sends 5, alice sends 15 | bob += 10, alice -= 10
// 111 - 69 - 10 = 32
assert_eq!(Balances::total_balance(&alice()), 32 * DOLLARS - 2 * (TX_FEE + TRANSFER_FEE));
// 100 + 69 + 10 = 179
assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - TX_FEE - TRANSFER_FEE);
// TODO TODO: this needs investigating: why are we deducting creation fee twice here? and why bob also pays it?
assert_eq!(Balances::total_balance(&alice()), 32 * DOLLARS - 2 * transfer_fee(&xt()) - 2 * creation_fee());
assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - transfer_fee(&xt()) - creation_fee());
let events = vec![
EventRecord {
phase: Phase::ApplyExtrinsic(0),
@@ -616,19 +633,15 @@ mod tests {
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0).unwrap();
runtime_io::with_externalities(&mut t, || {
// block1 transfers from alice 69 to bob.
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - (TX_FEE + TRANSFER_FEE));
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt()) - creation_fee());
assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS);
});
WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2.0).unwrap();
runtime_io::with_externalities(&mut t, || {
// bob sends 5, alice sends 15 | bob += 10, alice -= 10
// 111 - 69 - 10 = 32
assert_eq!(Balances::total_balance(&alice()), 32 * DOLLARS - 2 * (TX_FEE + TRANSFER_FEE));
// 100 + 69 + 10 = 179
assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - (TX_FEE + TRANSFER_FEE));
assert_eq!(Balances::total_balance(&alice()), 32 * DOLLARS - 2 * transfer_fee(&xt()) - 2 * creation_fee());
assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * transfer_fee(&xt()) - creation_fee());
});
}
@@ -745,19 +758,19 @@ mod tests {
function: Call::Timestamp(timestamp::Call::set(42)),
},
CheckedExtrinsic {
signed: Some((charlie(), 0)),
signed: Some((charlie(), signed_extra(0, 0))),
function: Call::Contracts(
contracts::Call::put_code::<Runtime>(10_000, transfer_code)
),
},
CheckedExtrinsic {
signed: Some((charlie(), 1)),
signed: Some((charlie(), signed_extra(1, 0))),
function: Call::Contracts(
contracts::Call::create::<Runtime>(1 * DOLLARS, 10_000, transfer_ch, Vec::new())
),
},
CheckedExtrinsic {
signed: Some((charlie(), 2)),
signed: Some((charlie(), signed_extra(2, 0))),
function: Call::Contracts(
contracts::Call::call::<Runtime>(
indices::address::Address::Id(addr.clone()),
@@ -873,7 +886,7 @@ mod tests {
assert_eq!(r, Ok(ApplyOutcome::Success));
runtime_io::with_externalities(&mut t, || {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - TX_FEE - TRANSFER_FEE);
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(&xt()) - creation_fee());
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
@@ -923,7 +936,8 @@ mod tests {
#[test]
fn weight_multiplier_increases_on_big_block() {
#[ignore]
fn weight_multiplier_increases_and_decreases_on_big_weight() {
let mut t = new_test_ext(COMPACT_CODE, false);
let mut prev_multiplier = WeightMultiplier::default();
@@ -933,21 +947,28 @@ mod tests {
});
let mut tt = new_test_ext(COMPACT_CODE, false);
// NOTE: This assumes that system::remark has the default.
let num_to_exhaust = multiplier_ideal() * 2 / SimpleDispatchInfo::default().weigh_data(());
println!("++ Generating {} transactions to fill {} weight units", num_to_exhaust, multiplier_ideal() * 2);
let mut xts = (0..num_to_exhaust).map(|i| CheckedExtrinsic {
signed: Some((charlie(), signed_extra(i.into(), 0))),
function: Call::System(system::Call::remark(vec![0; 1])),
}).collect::<Vec<CheckedExtrinsic>>();
xts.insert(0, CheckedExtrinsic {
signed: None,
function: Call::Timestamp(timestamp::Call::set(42)),
});
// big one in terms of weight.
let block1 = construct_block(
&mut tt,
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
signed: None,
function: Call::Timestamp(timestamp::Call::set(42)),
},
CheckedExtrinsic {
signed: Some((charlie(), 0)),
function: Call::System(system::Call::remark(vec![0; (IDEAL_TRANSACTIONS_WEIGHT*2) as usize])),
}
]
xts
);
// small one in terms of weight.
let block2 = construct_block(
&mut tt,
2,
@@ -958,8 +979,8 @@ mod tests {
function: Call::Timestamp(timestamp::Call::set(52)),
},
CheckedExtrinsic {
signed: Some((charlie(), 1)),
function: Call::System(system::Call::remark(vec![0; (IDEAL_TRANSACTIONS_WEIGHT*2) as usize])),
signed: Some((charlie(), signed_extra(num_to_exhaust.into(), 0))),
function: Call::System(system::Call::remark(vec![0; 1])),
}
]
);
@@ -990,82 +1011,6 @@ mod tests {
None,
).0.unwrap();
// weight multiplier is increased for next block.
runtime_io::with_externalities(&mut t, || {
let fm = System::next_weight_multiplier();
println!("After a big block: {:?} -> {:?}", prev_multiplier, fm);
assert!(fm > prev_multiplier);
});
}
#[test]
fn weight_multiplier_decreases_on_small_block() {
let mut t = new_test_ext(COMPACT_CODE, false);
let mut prev_multiplier = WeightMultiplier::default();
runtime_io::with_externalities(&mut t, || {
assert_eq!(System::next_weight_multiplier(), prev_multiplier);
});
let mut tt = new_test_ext(COMPACT_CODE, false);
let block1 = construct_block(
&mut tt,
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
signed: None,
function: Call::Timestamp(timestamp::Call::set(42)),
},
CheckedExtrinsic {
signed: Some((charlie(), 0)),
function: Call::System(system::Call::remark(vec![0; 120])),
}
]
);
let block2 = construct_block(
&mut tt,
2,
block1.1.clone(),
vec![
CheckedExtrinsic {
signed: None,
function: Call::Timestamp(timestamp::Call::set(52)),
},
CheckedExtrinsic {
signed: Some((charlie(), 1)),
function: Call::System(system::Call::remark(vec![0; 120])),
}
]
);
// execute a big block.
executor().call::<_, NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block1.0,
true,
None,
).0.unwrap();
// weight multiplier is increased for next block.
runtime_io::with_externalities(&mut t, || {
let fm = System::next_weight_multiplier();
println!("After a small block: {:?} -> {:?}", prev_multiplier, fm);
assert!(fm < prev_multiplier);
prev_multiplier = fm;
});
// execute a big block.
executor().call::<_, NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block2.0,
true,
None,
).0.unwrap();
// weight multiplier is increased for next block.
runtime_io::with_externalities(&mut t, || {
let fm = System::next_weight_multiplier();