mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 10:01:17 +00:00
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:
@@ -40,6 +40,8 @@ timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default
|
||||
rand = "0.6"
|
||||
finality_tracker = { package = "srml-finality-tracker", path = "../../srml/finality-tracker", default-features = false }
|
||||
contracts = { package = "srml-contracts", path = "../../srml/contracts" }
|
||||
system = { package = "srml-system", path = "../../srml/system" }
|
||||
balances = { package = "srml-balances", path = "../../srml/balances" }
|
||||
|
||||
[dev-dependencies]
|
||||
consensus-common = { package = "substrate-consensus-common", path = "../../core/consensus/common" }
|
||||
|
||||
@@ -23,13 +23,10 @@ use rand::rngs::StdRng;
|
||||
|
||||
use parity_codec::Decode;
|
||||
use keyring::sr25519::Keyring;
|
||||
use node_primitives::Hash;
|
||||
use node_runtime::{Call, CheckedExtrinsic, UncheckedExtrinsic, BalancesCall};
|
||||
use primitives::sr25519;
|
||||
use primitives::crypto::Pair;
|
||||
use node_runtime::{Call, CheckedExtrinsic, UncheckedExtrinsic, SignedExtra, BalancesCall};
|
||||
use primitives::{sr25519, crypto::Pair};
|
||||
use parity_codec::Encode;
|
||||
use sr_primitives::generic::Era;
|
||||
use sr_primitives::traits::{Block as BlockT, Header as HeaderT};
|
||||
use sr_primitives::{generic::Era, traits::{Block as BlockT, Header as HeaderT, SignedExtension}};
|
||||
use substrate_service::ServiceFactory;
|
||||
use transaction_factory::RuntimeAdapter;
|
||||
use transaction_factory::modes::Mode;
|
||||
@@ -54,6 +51,17 @@ pub struct FactoryState<N> {
|
||||
|
||||
type Number = <<node_primitives::Block as BlockT>::Header as HeaderT>::Number;
|
||||
|
||||
impl<Number> FactoryState<Number> {
|
||||
fn build_extra(index: node_primitives::Index, phase: u64) -> node_runtime::SignedExtra {
|
||||
(
|
||||
system::CheckEra::from(Era::mortal(256, phase)),
|
||||
system::CheckNonce::from(index),
|
||||
system::CheckWeight::from(),
|
||||
balances::TakeFees::from(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RuntimeAdapter for FactoryState<Number> {
|
||||
type AccountId = node_primitives::AccountId;
|
||||
type Balance = node_primitives::Balance;
|
||||
@@ -132,16 +140,14 @@ impl RuntimeAdapter for FactoryState<Number> {
|
||||
let phase = self.extract_phase(*prior_block_hash);
|
||||
|
||||
sign::<service::Factory, Self>(CheckedExtrinsic {
|
||||
signed: Some((sender.clone(), index)),
|
||||
signed: Some((sender.clone(), Self::build_extra(index, phase))),
|
||||
function: Call::Balances(
|
||||
BalancesCall::transfer(
|
||||
indices::address::Address::Id(
|
||||
destination.clone().into()
|
||||
),
|
||||
indices::address::Address::Id(destination.clone().into()),
|
||||
(*amount).into()
|
||||
)
|
||||
)
|
||||
}, key, &prior_block_hash, phase)
|
||||
}, key, (prior_block_hash.clone(), (), (), ()))
|
||||
}
|
||||
|
||||
fn inherent_extrinsics(&self) -> InherentData {
|
||||
@@ -229,13 +235,11 @@ fn gen_seed_bytes(seed: u64) -> [u8; 32] {
|
||||
fn sign<F: ServiceFactory, RA: RuntimeAdapter>(
|
||||
xt: CheckedExtrinsic,
|
||||
key: &sr25519::Pair,
|
||||
prior_block_hash: &Hash,
|
||||
phase: u64,
|
||||
additional_signed: <SignedExtra as SignedExtension>::AdditionalSigned,
|
||||
) -> <RA::Block as BlockT>::Extrinsic {
|
||||
let s = match xt.signed {
|
||||
Some((signed, index)) => {
|
||||
let era = Era::mortal(256, phase);
|
||||
let payload = (index.into(), xt.function, era, prior_block_hash);
|
||||
Some((signed, extra)) => {
|
||||
let payload = (xt.function, extra.clone(), additional_signed);
|
||||
let signature = payload.using_encoded(|b| {
|
||||
if b.len() > 256 {
|
||||
key.sign(&sr_io::blake2_256(b))
|
||||
@@ -244,8 +248,8 @@ fn sign<F: ServiceFactory, RA: RuntimeAdapter>(
|
||||
}
|
||||
}).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 {
|
||||
|
||||
@@ -220,7 +220,7 @@ mod tests {
|
||||
use consensus_common::{Environment, Proposer, BlockImportParams, BlockOrigin, ForkChoiceStrategy};
|
||||
use node_primitives::DigestItem;
|
||||
use node_runtime::{BalancesCall, Call, CENTS, SECS_PER_BLOCK, UncheckedExtrinsic};
|
||||
use parity_codec::{Compact, Encode, Decode};
|
||||
use parity_codec::{Encode, Decode};
|
||||
use primitives::{
|
||||
crypto::Pair as CryptoPair, ed25519::Pair, blake2_256,
|
||||
sr25519::Public as AddressPublic, H256,
|
||||
@@ -358,19 +358,24 @@ mod tests {
|
||||
let signer = charlie.clone();
|
||||
|
||||
let function = Call::Balances(BalancesCall::transfer(to.into(), amount));
|
||||
let era = Era::immortal();
|
||||
let raw_payload = (Compact(index), function, era, genesis_hash);
|
||||
|
||||
let check_era = system::CheckEra::from(Era::Immortal);
|
||||
let check_nonce = system::CheckNonce::from(index);
|
||||
let check_weight = system::CheckWeight::from();
|
||||
let take_fees = balances::TakeFees::from(0);
|
||||
let extra = (check_era, check_nonce, check_weight, take_fees);
|
||||
|
||||
let raw_payload = (function, extra.clone(), genesis_hash);
|
||||
let signature = raw_payload.using_encoded(|payload| if payload.len() > 256 {
|
||||
signer.sign(&blake2_256(payload)[..])
|
||||
} else {
|
||||
signer.sign(payload)
|
||||
});
|
||||
let xt = UncheckedExtrinsic::new_signed(
|
||||
index,
|
||||
raw_payload.1,
|
||||
raw_payload.0,
|
||||
from.into(),
|
||||
signature.into(),
|
||||
era,
|
||||
extra,
|
||||
).encode();
|
||||
let v: Vec<u8> = Decode::decode(&mut xt.as_slice()).unwrap();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
//! Some configurable implementations as associated type for the substrate runtime.
|
||||
|
||||
use node_primitives::Balance;
|
||||
use runtime_primitives::weights::{Weight, WeightMultiplier, MAX_TRANSACTIONS_WEIGHT, IDEAL_TRANSACTIONS_WEIGHT};
|
||||
use runtime_primitives::weights::{Weight, WeightMultiplier};
|
||||
use runtime_primitives::traits::{Convert, Saturating};
|
||||
use runtime_primitives::Fixed64;
|
||||
use crate::Balances;
|
||||
use support::traits::Get;
|
||||
use crate::{Balances, MaximumBlockWeight};
|
||||
|
||||
/// Struct that handles the conversion of Balance -> `u64`. This is used for staking's election
|
||||
/// calculation.
|
||||
@@ -53,14 +54,19 @@ pub struct WeightMultiplierUpdateHandler;
|
||||
impl Convert<(Weight, WeightMultiplier), WeightMultiplier> for WeightMultiplierUpdateHandler {
|
||||
fn convert(previous_state: (Weight, WeightMultiplier)) -> WeightMultiplier {
|
||||
let (block_weight, multiplier) = previous_state;
|
||||
let ideal = IDEAL_TRANSACTIONS_WEIGHT as u128;
|
||||
// CRITICAL NOTE: what the system module interprets as maximum block weight, and a portion
|
||||
// of it (1/4 usually) as ideal weight demonstrate the gap in block weights for operational
|
||||
// transactions. What this weight multiplier interprets as the maximum, is actually the
|
||||
// maximum that is available to normal transactions. Hence,
|
||||
let max_weight = <MaximumBlockWeight as Get<u32>>::get() / 4;
|
||||
let ideal_weight = (max_weight / 4) as u128;
|
||||
let block_weight = block_weight as u128;
|
||||
|
||||
// determines if the first_term is positive
|
||||
let positive = block_weight >= ideal;
|
||||
let diff_abs = block_weight.max(ideal) - block_weight.min(ideal);
|
||||
let positive = block_weight >= ideal_weight;
|
||||
let diff_abs = block_weight.max(ideal_weight) - block_weight.min(ideal_weight);
|
||||
// diff is within u32, safe.
|
||||
let diff = Fixed64::from_rational(diff_abs as i64, MAX_TRANSACTIONS_WEIGHT as u64);
|
||||
let diff = Fixed64::from_rational(diff_abs as i64, max_weight as u64);
|
||||
let diff_squared = diff.saturating_mul(diff);
|
||||
|
||||
// 0.00004 = 4/100_000 = 40_000/10^9
|
||||
@@ -94,9 +100,17 @@ impl Convert<(Weight, WeightMultiplier), WeightMultiplier> for WeightMultiplierU
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use runtime_primitives::weights::{MAX_TRANSACTIONS_WEIGHT, IDEAL_TRANSACTIONS_WEIGHT, Weight};
|
||||
use runtime_primitives::weights::Weight;
|
||||
use runtime_primitives::Perbill;
|
||||
|
||||
fn max() -> Weight {
|
||||
<MaximumBlockWeight as Get<Weight>>::get()
|
||||
}
|
||||
|
||||
fn ideal() -> Weight {
|
||||
max() / 4 / 4
|
||||
}
|
||||
|
||||
// poc reference implementation.
|
||||
#[allow(dead_code)]
|
||||
fn weight_multiplier_update(block_weight: Weight) -> Perbill {
|
||||
@@ -104,9 +118,9 @@ mod tests {
|
||||
let v: f32 = 0.00004;
|
||||
|
||||
// maximum tx weight
|
||||
let m = MAX_TRANSACTIONS_WEIGHT as f32;
|
||||
let m = max() as f32;
|
||||
// Ideal saturation in terms of weight
|
||||
let ss = IDEAL_TRANSACTIONS_WEIGHT as f32;
|
||||
let ss = ideal() as f32;
|
||||
// Current saturation in terms of weight
|
||||
let s = block_weight;
|
||||
|
||||
@@ -124,22 +138,22 @@ mod tests {
|
||||
fn stateless_weight_mul() {
|
||||
// Light block. Fee is reduced a little.
|
||||
assert_eq!(
|
||||
WeightMultiplierUpdateHandler::convert((1024, WeightMultiplier::default())),
|
||||
fm(-9990)
|
||||
WeightMultiplierUpdateHandler::convert((ideal() / 4, WeightMultiplier::default())),
|
||||
fm(-7500)
|
||||
);
|
||||
// a bit more. Fee is decreased less, meaning that the fee increases as the block grows.
|
||||
assert_eq!(
|
||||
WeightMultiplierUpdateHandler::convert((1024 * 4, WeightMultiplier::default())),
|
||||
fm(-9960)
|
||||
WeightMultiplierUpdateHandler::convert((ideal() / 2, WeightMultiplier::default())),
|
||||
fm(-5000)
|
||||
);
|
||||
// ideal. Original fee.
|
||||
// ideal. Original fee. No changes.
|
||||
assert_eq!(
|
||||
WeightMultiplierUpdateHandler::convert((IDEAL_TRANSACTIONS_WEIGHT as u32, WeightMultiplier::default())),
|
||||
WeightMultiplierUpdateHandler::convert((ideal() as u32, WeightMultiplier::default())),
|
||||
fm(0)
|
||||
);
|
||||
// // More than ideal. Fee is increased.
|
||||
assert_eq!(
|
||||
WeightMultiplierUpdateHandler::convert(((IDEAL_TRANSACTIONS_WEIGHT * 2) as u32, WeightMultiplier::default())),
|
||||
WeightMultiplierUpdateHandler::convert(((ideal() * 2) as u32, WeightMultiplier::default())),
|
||||
fm(10000)
|
||||
);
|
||||
}
|
||||
@@ -147,20 +161,20 @@ mod tests {
|
||||
#[test]
|
||||
fn stateful_weight_mul_grow_to_infinity() {
|
||||
assert_eq!(
|
||||
WeightMultiplierUpdateHandler::convert((IDEAL_TRANSACTIONS_WEIGHT * 2, WeightMultiplier::default())),
|
||||
WeightMultiplierUpdateHandler::convert((ideal() * 2, WeightMultiplier::default())),
|
||||
fm(10000)
|
||||
);
|
||||
assert_eq!(
|
||||
WeightMultiplierUpdateHandler::convert((IDEAL_TRANSACTIONS_WEIGHT * 2, fm(10000))),
|
||||
WeightMultiplierUpdateHandler::convert((ideal() * 2, fm(10000))),
|
||||
fm(20000)
|
||||
);
|
||||
assert_eq!(
|
||||
WeightMultiplierUpdateHandler::convert((IDEAL_TRANSACTIONS_WEIGHT * 2, fm(20000))),
|
||||
WeightMultiplierUpdateHandler::convert((ideal() * 2, fm(20000))),
|
||||
fm(30000)
|
||||
);
|
||||
// ...
|
||||
assert_eq!(
|
||||
WeightMultiplierUpdateHandler::convert((IDEAL_TRANSACTIONS_WEIGHT * 2, fm(1_000_000_000))),
|
||||
WeightMultiplierUpdateHandler::convert((ideal() * 2, fm(1_000_000_000))),
|
||||
fm(1_000_000_000 + 10000)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ use client::{
|
||||
};
|
||||
use runtime_primitives::{ApplyResult, impl_opaque_keys, generic, create_runtime_str, key_types};
|
||||
use runtime_primitives::transaction_validity::TransactionValidity;
|
||||
use runtime_primitives::weights::Weight;
|
||||
use runtime_primitives::traits::{
|
||||
BlakeTwo256, Block as BlockT, DigestFor, NumberFor, StaticLookup,
|
||||
};
|
||||
@@ -74,8 +75,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
// and set impl_version to equal spec_version. If only runtime
|
||||
// implementation changes and behavior does not, then leave spec_version as
|
||||
// is and increment impl_version.
|
||||
spec_version: 116,
|
||||
impl_version: 116,
|
||||
spec_version: 117,
|
||||
impl_version: 117,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
};
|
||||
|
||||
@@ -116,6 +117,8 @@ pub const DAYS: Moment = HOURS * 24;
|
||||
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: BlockNumber = 250;
|
||||
pub const MaximumBlockWeight: Weight = 4 * 1024 * 1024;
|
||||
pub const MaximumBlockLength: u32 = 4 * 1024 * 1024;
|
||||
}
|
||||
|
||||
impl system::Trait for Runtime {
|
||||
@@ -130,6 +133,8 @@ impl system::Trait for Runtime {
|
||||
type WeightMultiplierUpdate = WeightMultiplierUpdateHandler;
|
||||
type Event = Event;
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type MaximumBlockWeight = MaximumBlockWeight;
|
||||
type MaximumBlockLength = MaximumBlockLength;
|
||||
}
|
||||
|
||||
impl aura::Trait for Runtime {
|
||||
@@ -432,12 +437,19 @@ pub type Block = generic::Block<Header, UncheckedExtrinsic>;
|
||||
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.
|
||||
pub type SignedExtra = (
|
||||
system::CheckEra<Runtime>,
|
||||
system::CheckNonce<Runtime>,
|
||||
system::CheckWeight<Runtime>,
|
||||
balances::TakeFees<Runtime>
|
||||
);
|
||||
/// Unchecked extrinsic type as expected by this runtime.
|
||||
pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic<Address, Index, Call, Signature>;
|
||||
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
|
||||
/// Extrinsic type that has already been checked.
|
||||
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Index, Call>;
|
||||
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;
|
||||
/// Executive: handles dispatch to the various modules.
|
||||
pub type Executive = executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Balances, Runtime, AllModules>;
|
||||
pub type Executive = executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Runtime, AllModules>;
|
||||
|
||||
impl_runtime_apis! {
|
||||
impl client_api::Core<Block> for Runtime {
|
||||
|
||||
Reference in New Issue
Block a user