From b042a93f67050a8e3cbea565883df62a08996cbf Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 11 Jul 2019 13:24:53 +0200 Subject: [PATCH 01/33] Make extrinsics extensible. Also Remove old extrinsic types. --- .../src/generic/checked_extrinsic.rs | 34 +- core/sr-primitives/src/generic/mod.rs | 4 - .../src/generic/unchecked_extrinsic.rs | 339 +++++++++++++----- .../unchecked_mortal_compact_extrinsic.rs | 306 ---------------- .../src/generic/unchecked_mortal_extrinsic.rs | 307 ---------------- core/sr-primitives/src/traits.rs | 71 ++++ node-template/runtime/src/lib.rs | 2 +- node/runtime/src/lib.rs | 2 +- srml/collective/src/lib.rs | 2 +- srml/elections/src/lib.rs | 2 +- srml/executive/src/lib.rs | 49 ++- srml/support/test/tests/instance.rs | 4 +- srml/support/test/tests/issue2219.rs | 4 +- 13 files changed, 398 insertions(+), 728 deletions(-) delete mode 100644 core/sr-primitives/src/generic/unchecked_mortal_compact_extrinsic.rs delete mode 100644 core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs diff --git a/core/sr-primitives/src/generic/checked_extrinsic.rs b/core/sr-primitives/src/generic/checked_extrinsic.rs index ee43b3af2e951..c1d22d7c09186 100644 --- a/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -17,7 +17,8 @@ //! Generic implementation of an extrinsic that has passed the verification //! stage. -use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay}; +use rstd::result::Result; +use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay, SignedExtension, DispatchError}; use crate::weights::{Weighable, Weight}; /// Definition of something that the external world might want to say; its @@ -25,23 +26,27 @@ use crate::weights::{Weighable, Weight}; /// regards to the signature. #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Debug))] -pub struct CheckedExtrinsic { +pub struct CheckedExtrinsic { /// Who this purports to be from and the number of extrinsics have come before /// from the same signer, if anyone (note this is not a signature). - pub signed: Option<(AccountId, Index)>, + pub signed: Option<(AccountId, Index, Extra)>, + /// The function that should be called. pub function: Call, } -impl traits::Applyable for CheckedExtrinsic +impl traits::Applyable +for + CheckedExtrinsic where AccountId: Member + MaybeDisplay, Index: Member + MaybeDisplay + SimpleArithmetic, Call: Member, + Extra: SignedExtension, { - type Index = Index; type AccountId = AccountId; type Call = Call; + type Index = Index; fn index(&self) -> Option<&Self::Index> { self.signed.as_ref().map(|x| &x.1) @@ -52,11 +57,26 @@ where } fn deconstruct(self) -> (Self::Call, Option) { - (self.function, self.signed.map(|x| x.0)) + if let Some((id, _, extra)) = self.signed { + (self.function, Some(id)) + } else { + (self.function, None) + } + } + + fn pre_dispatch(self, + weight: crate::weights::Weight, + ) -> Result<(Self::Call, Option), DispatchError> { + if let Some((id, index, extra)) = self.signed { + Extra::pre_dispatch(extra, &id, &index, &self.function, weight)?; + Ok((self.function, Some(id))) + } else { + Ok((self.function, None)) + } } } -impl Weighable for CheckedExtrinsic +impl Weighable for CheckedExtrinsic where Call: Weighable, { diff --git a/core/sr-primitives/src/generic/mod.rs b/core/sr-primitives/src/generic/mod.rs index a4e4106780efc..1511753d2c524 100644 --- a/core/sr-primitives/src/generic/mod.rs +++ b/core/sr-primitives/src/generic/mod.rs @@ -19,8 +19,6 @@ // end::description[] mod unchecked_extrinsic; -mod unchecked_mortal_extrinsic; -mod unchecked_mortal_compact_extrinsic; mod era; mod checked_extrinsic; mod header; @@ -30,8 +28,6 @@ mod digest; mod tests; pub use self::unchecked_extrinsic::UncheckedExtrinsic; -pub use self::unchecked_mortal_extrinsic::UncheckedMortalExtrinsic; -pub use self::unchecked_mortal_compact_extrinsic::UncheckedMortalCompactExtrinsic; pub use self::era::{Era, Phase}; pub use self::checked_extrinsic::CheckedExtrinsic; pub use self::header::Header; diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index d6e0d60e2c218..7eb31e28fd608 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -20,48 +20,73 @@ use std::fmt; use rstd::prelude::*; -use crate::codec::{Decode, Encode, Codec, Input, HasCompact}; -use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay, Lookup, Extrinsic}; -use super::CheckedExtrinsic; +use runtime_io::blake2_256; +use crate::codec::{Decode, Encode, Codec, Input, Compact}; +use crate::traits::{ + self, Member, SimpleArithmetic, MaybeDebug, MaybeDisplay, CurrentHeight, SignedExtension, + BlockNumberToHash, Lookup, Checkable, Extrinsic, SaturatedConversion, DispatchError +}; +use super::{CheckedExtrinsic, Era}; -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -pub struct SignatureContent -where - Address: Codec, - Index: HasCompact + Codec, - Signature: Codec, -{ - signed: Address, - signature: Signature, - index: Index, +const TRANSACTION_VERSION: u8 = 1; +/* +/// A type with which the signed payload of a transaction may be extended. +pub trait OSignedExtension: Codec + MaybeDebug {} + +impl SignedExtra for T {} + +/// A type that names a `SignedExtension` and knows how to deal with it. +pub trait OExtension { + /// An extra data field that should go into the signed part of the payload. + type SignedPayload: OSignedExtension; + + /// Anything that should be executed immediately before dispatch. + fn pre_dispatch( + a: &AccountId, + c: &Call, + e: Self::SignedPayload + ) -> Result<(), DispatchError>; } +impl OExtension for () { + type SignedPayload = (); + + fn pre_dispatch( + _: &AccountId, + _: &Call, + _: () + ) -> Result<(), DispatchError> { Ok(()) } +} +*/ /// A extrinsic right from the external world. This is unchecked and so /// can contain a signature. #[derive(PartialEq, Eq, Clone)] -pub struct UncheckedExtrinsic +pub struct UncheckedExtrinsic where - Address: Codec, - Index: HasCompact + Codec, - Signature: Codec, + Extra: SignedExtension { - /// The signature, address and number of extrinsics have come before from - /// the same signer, if this is a signed extrinsic. - pub signature: Option>, + /// The signature, address, number of extrinsics have come before from + /// the same signer and an era describing the longevity of this transaction, + /// if this is a signed extrinsic. + pub signature: Option<(Address, Signature, Compact, Era, Extra)>, /// The function that should be called. pub function: Call, } -impl UncheckedExtrinsic -where - Address: Codec, - Index: HasCompact + Codec, - Signature: Codec, +impl + UncheckedExtrinsic { /// New instance of a signed extrinsic aka "transaction". - pub fn new_signed(index: Index, function: Call, signed: Address, signature: Signature) -> Self { + pub fn new_signed( + index: Index, + function: Call, + signed: Address, + signature: Signature, + era: Era, + extra: Extra + ) -> Self { UncheckedExtrinsic { - signature: Some(SignatureContent{signed, signature, index}), + signature: Some((signed, signature, index.into(), era, extra)), function, } } @@ -75,29 +100,54 @@ where } } -impl traits::Checkable - for UncheckedExtrinsic +impl Extrinsic + for UncheckedExtrinsic +{ + fn is_signed(&self) -> Option { + Some(self.signature.is_some()) + } +} + +impl + Checkable +for + UncheckedExtrinsic where - Address: Member + MaybeDisplay + Codec, - Index: Member + MaybeDisplay + SimpleArithmetic + Codec, + Address: Member + MaybeDisplay, + Index: Member + MaybeDisplay + SimpleArithmetic, + Compact: Encode, Call: Encode + Member, - Signature: Member + traits::Verify + Codec, + Signature: Member + traits::Verify, + Extra: SignedExtension, AccountId: Member + MaybeDisplay, - Context: Lookup, + BlockNumber: SimpleArithmetic, + Hash: Encode, + Context: Lookup + + CurrentHeight + + BlockNumberToHash, { - type Checked = CheckedExtrinsic; + type Checked = CheckedExtrinsic; fn check(self, context: &Context) -> Result { Ok(match self.signature { - Some(SignatureContent{signed, signature, index}) => { - let payload = (index, self.function); + Some((signed, signature, index, era, extra)) => { + let current_u64 = context.current_height().saturated_into::(); + let h = context.block_number_to_hash(era.birth(current_u64).saturated_into()) + .ok_or("transaction birth block ancient")?; let signed = context.lookup(signed)?; - if !crate::verify_encoded_lazy(&signature, &payload, &signed) { + let raw_payload = (index, self.function, era, h, extra); + if !raw_payload.using_encoded(|payload| { + if payload.len() > 256 { + signature.verify(&blake2_256(payload)[..], &signed) + } else { + signature.verify(payload, &signed) + } + }) { return Err(crate::BAD_SIGNATURE) } CheckedExtrinsic { - signed: Some((signed, payload.0)), - function: payload.1, + signed: Some((signed, (raw_payload.0).0, raw_payload.4)), + function: raw_payload.1, } } None => CheckedExtrinsic { @@ -108,19 +158,14 @@ where } } -impl< - Address: Codec, - Index: HasCompact + Codec, - Signature: Codec, - Call, -> Extrinsic for UncheckedExtrinsic { - fn is_signed(&self) -> Option { - Some(self.signature.is_some()) - } -} - -impl Decode - for UncheckedExtrinsic +impl Decode + for UncheckedExtrinsic +where + Address: Decode, + Signature: Decode, + Compact: Decode, + Call: Decode, + Extra: SignedExtension, { fn decode(input: &mut I) -> Option { // This is a little more complicated than usual since the binary format must be compatible @@ -129,70 +174,202 @@ impl // to use this). let _length_do_not_remove_me_see_above: Vec<()> = Decode::decode(input)?; + let version = input.read_byte()?; + + let is_signed = version & 0b1000_0000 != 0; + let version = version & 0b0111_1111; + if version != TRANSACTION_VERSION { + return None + } + Some(UncheckedExtrinsic { - signature: Decode::decode(input)?, + signature: if is_signed { Some(Decode::decode(input)?) } else { None }, function: Decode::decode(input)?, }) } } -impl Encode - for UncheckedExtrinsic +impl Encode + for UncheckedExtrinsic +where + Address: Encode, + Signature: Encode, + Compact: Encode, + Call: Encode, + Extra: SignedExtension, { fn encode(&self) -> Vec { super::encode_with_vec_prefix::(|v| { - self.signature.encode_to(v); + // 1 byte version id. + match self.signature.as_ref() { + Some(s) => { + v.push(TRANSACTION_VERSION | 0b1000_0000); + s.encode_to(v); + } + None => { + v.push(TRANSACTION_VERSION & 0b0111_1111); + } + } self.function.encode_to(v); }) } } #[cfg(feature = "std")] -impl serde::Serialize - for UncheckedExtrinsic +impl serde::Serialize + for UncheckedExtrinsic + where Compact: Encode { fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { - self.using_encoded(|bytes| ::substrate_primitives::bytes::serialize(bytes, seq)) + self.using_encoded(|bytes| seq.serialize_bytes(bytes)) } } #[cfg(feature = "std")] -impl fmt::Debug - for UncheckedExtrinsic +impl fmt::Debug + for UncheckedExtrinsic where - Address: fmt::Debug + Codec, - Index: fmt::Debug + HasCompact + Codec, - Signature: Codec, + Address: fmt::Debug, + Index: fmt::Debug, Call: fmt::Debug, + Extra: SignedExtension, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UncheckedExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.signed, &x.index)), self.function) + write!(f, "UncheckedExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2, &x.4)), self.function) } } #[cfg(test)] -mod test { - use crate::codec::{Decode, Encode}; - use super::UncheckedExtrinsic; +mod tests { + use super::*; + use runtime_io::blake2_256; + use crate::codec::{Encode, Decode}; + use crate::traits::{SignedExtension, DispatchError}; + use serde::{Serialize, Deserialize}; + + struct TestContext; + impl Lookup for TestContext { + type Source = u64; + type Target = u64; + fn lookup(&self, s: u64) -> Result { Ok(s) } + } + impl CurrentHeight for TestContext { + type BlockNumber = u64; + fn current_height(&self) -> u64 { 42 } + } + impl BlockNumberToHash for TestContext { + type BlockNumber = u64; + type Hash = u64; + fn block_number_to_hash(&self, n: u64) -> Option { Some(n) } + } + + #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Encode, Decode)] + struct TestSig(u64, Vec); + impl traits::Verify for TestSig { + type Signer = u64; + fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { + *signer == self.0 && msg.get() == &self.1[..] + } + } + + const DUMMY_ACCOUNTID: u64 = 0; + + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Ord, PartialOrd)] + struct TestExtra; + impl SignedExtension for TestExtra { + type AccountId = u64; + type Index = u64; + type Call = Vec; + fn pre_dispatch( + self, + _a: &Self::AccountId, + _i: &Self::Index, + _c: &Self::Call, + _w: crate::weights::Weight, + ) -> Result<(), DispatchError> { + Ok(()) + } + } + type Ex = UncheckedExtrinsic, TestSig, TestExtra>; + type CEx = CheckedExtrinsic, TestExtra>; #[test] - fn encoding_matches_vec() { - type Extrinsic = UncheckedExtrinsic; - let ex = Extrinsic::new_unsigned(42); - let encoded = ex.encode(); - let decoded = Extrinsic::decode(&mut encoded.as_slice()).unwrap(); - assert_eq!(decoded, ex); - let as_vec: Vec = Decode::decode(&mut encoded.as_slice()).unwrap(); - assert_eq!(as_vec.encode(), encoded); + fn unsigned_codec_should_work() { + let ux = Ex::new_unsigned(vec![0u8;0]); + let encoded = ux.encode(); + assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); + } + + #[test] + fn signed_codec_should_work() { + let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::immortal(), 0u64).encode()), Era::immortal(), TestExtra); + let encoded = ux.encode(); + assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); + } + + #[test] + fn large_signed_codec_should_work() { + let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8; 257], Era::immortal(), 0u64).using_encoded(blake2_256)[..].to_owned()), Era::immortal(), TestExtra); + let encoded = ux.encode(); + assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); + } + + #[test] + fn unsigned_check_should_work() { + let ux = Ex::new_unsigned(vec![0u8;0]); + assert!(!ux.is_signed().unwrap_or(false)); + assert!(>::check(ux, &TestContext).is_ok()); + } + + #[test] + fn badly_signed_check_should_fail() { + let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, vec![0u8]), Era::immortal(), TestExtra); + assert!(ux.is_signed().unwrap_or(false)); + assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); } + #[test] + fn immortal_signed_check_should_work() { + let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (Compact::from(DUMMY_ACCOUNTID), vec![0u8;0], Era::immortal(), 0u64).encode()), Era::immortal(), TestExtra); + assert!(ux.is_signed().unwrap_or(false)); + assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0, TestExtra)), function: vec![0u8;0] })); + } + + #[test] + fn mortal_signed_check_should_work() { + let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (Compact::from(DUMMY_ACCOUNTID), vec![0u8;0], Era::mortal(32, 42), 42u64).encode()), Era::mortal(32, 42), TestExtra); + assert!(ux.is_signed().unwrap_or(false)); + assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0, TestExtra)), function: vec![0u8;0] })); + } + + #[test] + fn later_mortal_signed_check_should_work() { + let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (Compact::from(DUMMY_ACCOUNTID), vec![0u8;0], Era::mortal(32, 11), 11u64).encode()), Era::mortal(32, 11), TestExtra); + assert!(ux.is_signed().unwrap_or(false)); + assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0, TestExtra)), function: vec![0u8;0] })); + } + + #[test] + fn too_late_mortal_signed_check_should_fail() { + let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::mortal(32, 10), 10u64).encode()), Era::mortal(32, 10), TestExtra); + assert!(ux.is_signed().unwrap_or(false)); + assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); + } #[test] - #[cfg(feature = "std")] - fn serialization_of_unchecked_extrinsics() { - type Extrinsic = UncheckedExtrinsic; - let ex = Extrinsic::new_unsigned(42); + fn too_early_mortal_signed_check_should_fail() { + let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::mortal(32, 43), 43u64).encode()), Era::mortal(32, 43), TestExtra); + assert!(ux.is_signed().unwrap_or(false)); + assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); + } - assert_eq!(serde_json::to_string(&ex).unwrap(), "\"0x14002a000000\""); + #[test] + fn encoding_matches_vec() { + let ex = Ex::new_unsigned(vec![0u8;0]); + let encoded = ex.encode(); + let decoded = Ex::decode(&mut encoded.as_slice()).unwrap(); + assert_eq!(decoded, ex); + let as_vec: Vec = Decode::decode(&mut encoded.as_slice()).unwrap(); + assert_eq!(as_vec.encode(), encoded); } } diff --git a/core/sr-primitives/src/generic/unchecked_mortal_compact_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_mortal_compact_extrinsic.rs deleted file mode 100644 index 36e17fc277cde..0000000000000 --- a/core/sr-primitives/src/generic/unchecked_mortal_compact_extrinsic.rs +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! Generic implementation of an unchecked (pre-verification) extrinsic. - -#[cfg(feature = "std")] -use std::fmt; - -use rstd::prelude::*; -use runtime_io::blake2_256; -use crate::codec::{Decode, Encode, Input, Compact}; -use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay, CurrentHeight, BlockNumberToHash, - Lookup, Checkable, Extrinsic, SaturatedConversion}; -use super::{CheckedExtrinsic, Era}; - -const TRANSACTION_VERSION: u8 = 1; - -/// A extrinsic right from the external world. This is unchecked and so -/// can contain a signature. -#[derive(PartialEq, Eq, Clone)] -pub struct UncheckedMortalCompactExtrinsic { - /// The signature, address, number of extrinsics have come before from - /// the same signer and an era describing the longevity of this transaction, - /// if this is a signed extrinsic. - pub signature: Option<(Address, Signature, Compact, Era)>, - /// The function that should be called. - pub function: Call, -} - -impl UncheckedMortalCompactExtrinsic { - /// New instance of a signed extrinsic aka "transaction". - pub fn new_signed(index: Index, function: Call, signed: Address, signature: Signature, era: Era) -> Self { - UncheckedMortalCompactExtrinsic { - signature: Some((signed, signature, index.into(), era)), - function, - } - } - - /// New instance of an unsigned extrinsic aka "inherent". - pub fn new_unsigned(function: Call) -> Self { - UncheckedMortalCompactExtrinsic { - signature: None, - function, - } - } -} - -impl Extrinsic for UncheckedMortalCompactExtrinsic { - fn is_signed(&self) -> Option { - Some(self.signature.is_some()) - } -} - -impl Checkable - for UncheckedMortalCompactExtrinsic -where - Address: Member + MaybeDisplay, - Index: Member + MaybeDisplay + SimpleArithmetic, - Compact: Encode, - Call: Encode + Member, - Signature: Member + traits::Verify, - AccountId: Member + MaybeDisplay, - BlockNumber: SimpleArithmetic, - Hash: Encode, - Context: Lookup - + CurrentHeight - + BlockNumberToHash, -{ - type Checked = CheckedExtrinsic; - - fn check(self, context: &Context) -> Result { - Ok(match self.signature { - Some((signed, signature, index, era)) => { - let current_u64 = context.current_height().saturated_into::(); - let h = context.block_number_to_hash(era.birth(current_u64).saturated_into()) - .ok_or("transaction birth block ancient")?; - let signed = context.lookup(signed)?; - let raw_payload = (index, self.function, era, h); - if !raw_payload.using_encoded(|payload| { - if payload.len() > 256 { - signature.verify(&blake2_256(payload)[..], &signed) - } else { - signature.verify(payload, &signed) - } - }) { - return Err(crate::BAD_SIGNATURE) - } - CheckedExtrinsic { - signed: Some((signed, (raw_payload.0).0)), - function: raw_payload.1, - } - } - None => CheckedExtrinsic { - signed: None, - function: self.function, - }, - }) - } -} - -impl Decode - for UncheckedMortalCompactExtrinsic -where - Address: Decode, - Signature: Decode, - Compact: Decode, - Call: Decode, -{ - fn decode(input: &mut I) -> Option { - // This is a little more complicated than usual since the binary format must be compatible - // with substrate's generic `Vec` type. Basically this just means accepting that there - // will be a prefix of vector length (we don't need - // to use this). - let _length_do_not_remove_me_see_above: Vec<()> = Decode::decode(input)?; - - let version = input.read_byte()?; - - let is_signed = version & 0b1000_0000 != 0; - let version = version & 0b0111_1111; - if version != TRANSACTION_VERSION { - return None - } - - Some(UncheckedMortalCompactExtrinsic { - signature: if is_signed { Some(Decode::decode(input)?) } else { None }, - function: Decode::decode(input)?, - }) - } -} - -impl Encode - for UncheckedMortalCompactExtrinsic -where - Address: Encode, - Signature: Encode, - Compact: Encode, - Call: Encode, -{ - fn encode(&self) -> Vec { - super::encode_with_vec_prefix::(|v| { - // 1 byte version id. - match self.signature.as_ref() { - Some(s) => { - v.push(TRANSACTION_VERSION | 0b1000_0000); - s.encode_to(v); - } - None => { - v.push(TRANSACTION_VERSION & 0b0111_1111); - } - } - self.function.encode_to(v); - }) - } -} - -#[cfg(feature = "std")] -impl serde::Serialize - for UncheckedMortalCompactExtrinsic - where Compact: Encode -{ - fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { - self.using_encoded(|bytes| seq.serialize_bytes(bytes)) - } -} - -#[cfg(feature = "std")] -impl fmt::Debug for UncheckedMortalCompactExtrinsic where - Address: fmt::Debug, - Index: fmt::Debug, - Call: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UncheckedMortalCompactExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2)), self.function) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use runtime_io::blake2_256; - use crate::codec::{Encode, Decode}; - use serde::{Serialize, Deserialize}; - - struct TestContext; - impl Lookup for TestContext { - type Source = u64; - type Target = u64; - fn lookup(&self, s: u64) -> Result { Ok(s) } - } - impl CurrentHeight for TestContext { - type BlockNumber = u64; - fn current_height(&self) -> u64 { 42 } - } - impl BlockNumberToHash for TestContext { - type BlockNumber = u64; - type Hash = u64; - fn block_number_to_hash(&self, n: u64) -> Option { Some(n) } - } - - #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Encode, Decode)] - struct TestSig(u64, Vec); - impl traits::Verify for TestSig { - type Signer = u64; - fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { - *signer == self.0 && msg.get() == &self.1[..] - } - } - - const DUMMY_ACCOUNTID: u64 = 0; - - type Ex = UncheckedMortalCompactExtrinsic, TestSig>; - type CEx = CheckedExtrinsic>; - - #[test] - fn unsigned_codec_should_work() { - let ux = Ex::new_unsigned(vec![0u8;0]); - let encoded = ux.encode(); - assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); - } - - #[test] - fn signed_codec_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::immortal(), 0u64).encode()), Era::immortal()); - let encoded = ux.encode(); - assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); - } - - #[test] - fn large_signed_codec_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8; 257], Era::immortal(), 0u64).using_encoded(blake2_256)[..].to_owned()), Era::immortal()); - let encoded = ux.encode(); - assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); - } - - #[test] - fn unsigned_check_should_work() { - let ux = Ex::new_unsigned(vec![0u8;0]); - assert!(!ux.is_signed().unwrap_or(false)); - assert!(>::check(ux, &TestContext).is_ok()); - } - - #[test] - fn badly_signed_check_should_fail() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, vec![0u8]), Era::immortal()); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); - } - - #[test] - fn immortal_signed_check_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (Compact::from(DUMMY_ACCOUNTID), vec![0u8;0], Era::immortal(), 0u64).encode()), Era::immortal()); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0)), function: vec![0u8;0] })); - } - - #[test] - fn mortal_signed_check_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (Compact::from(DUMMY_ACCOUNTID), vec![0u8;0], Era::mortal(32, 42), 42u64).encode()), Era::mortal(32, 42)); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0)), function: vec![0u8;0] })); - } - - #[test] - fn later_mortal_signed_check_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (Compact::from(DUMMY_ACCOUNTID), vec![0u8;0], Era::mortal(32, 11), 11u64).encode()), Era::mortal(32, 11)); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0)), function: vec![0u8;0] })); - } - - #[test] - fn too_late_mortal_signed_check_should_fail() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::mortal(32, 10), 10u64).encode()), Era::mortal(32, 10)); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); - } - - #[test] - fn too_early_mortal_signed_check_should_fail() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::mortal(32, 43), 43u64).encode()), Era::mortal(32, 43)); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); - } - - #[test] - fn encoding_matches_vec() { - let ex = Ex::new_unsigned(vec![0u8;0]); - let encoded = ex.encode(); - let decoded = Ex::decode(&mut encoded.as_slice()).unwrap(); - assert_eq!(decoded, ex); - let as_vec: Vec = Decode::decode(&mut encoded.as_slice()).unwrap(); - assert_eq!(as_vec.encode(), encoded); - } -} diff --git a/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs deleted file mode 100644 index 7f92b20edd0c3..0000000000000 --- a/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright 2017-2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! Generic implementation of an unchecked (pre-verification) extrinsic. - -#[cfg(feature = "std")] -use std::fmt; - -use rstd::prelude::*; -use runtime_io::blake2_256; -use crate::codec::{Decode, Encode, Input}; -use crate::traits::{ - self, Member, SimpleArithmetic, MaybeDisplay, CurrentHeight, BlockNumberToHash, - Lookup, Checkable, Extrinsic, SaturatedConversion -}; -use super::{CheckedExtrinsic, Era}; - -const TRANSACTION_VERSION: u8 = 1; - -/// A extrinsic right from the external world. This is unchecked and so -/// can contain a signature. -#[derive(PartialEq, Eq, Clone)] -pub struct UncheckedMortalExtrinsic { - /// The signature, address, number of extrinsics have come before from - /// the same signer and an era describing the longevity of this transaction, - /// if this is a signed extrinsic. - pub signature: Option<(Address, Signature, Index, Era)>, - /// The function that should be called. - pub function: Call, -} - -impl UncheckedMortalExtrinsic { - /// New instance of a signed extrinsic aka "transaction". - pub fn new_signed(index: Index, function: Call, signed: Address, signature: Signature, era: Era) -> Self { - UncheckedMortalExtrinsic { - signature: Some((signed, signature, index, era)), - function, - } - } - - /// New instance of an unsigned extrinsic aka "inherent". - pub fn new_unsigned(function: Call) -> Self { - UncheckedMortalExtrinsic { - signature: None, - function, - } - } -} - -impl Extrinsic for UncheckedMortalExtrinsic { - fn is_signed(&self) -> Option { - Some(self.signature.is_some()) - } -} - -impl Checkable - for UncheckedMortalExtrinsic -where - Address: Member + MaybeDisplay, - Index: Encode + Member + MaybeDisplay + SimpleArithmetic, - Call: Encode + Member, - Signature: Member + traits::Verify, - AccountId: Member + MaybeDisplay, - BlockNumber: SimpleArithmetic, - Hash: Encode, - Context: Lookup - + CurrentHeight - + BlockNumberToHash, -{ - type Checked = CheckedExtrinsic; - - fn check(self, context: &Context) -> Result { - Ok(match self.signature { - Some((signed, signature, index, era)) => { - let current_u64 = context.current_height().saturated_into::(); - let h = context.block_number_to_hash(era.birth(current_u64).saturated_into()) - .ok_or("transaction birth block ancient")?; - let signed = context.lookup(signed)?; - let raw_payload = (index, self.function, era, h); - - if !raw_payload.using_encoded(|payload| { - if payload.len() > 256 { - signature.verify(&blake2_256(payload)[..], &signed) - } else { - signature.verify(payload, &signed) - } - }) { - return Err(crate::BAD_SIGNATURE) - } - CheckedExtrinsic { - signed: Some((signed, raw_payload.0)), - function: raw_payload.1, - } - } - None => CheckedExtrinsic { - signed: None, - function: self.function, - }, - }) - } -} - -impl Decode - for UncheckedMortalExtrinsic -where - Address: Decode, - Signature: Decode, - Index: Decode, - Call: Decode, -{ - fn decode(input: &mut I) -> Option { - // This is a little more complicated than usual since the binary format must be compatible - // with substrate's generic `Vec` type. Basically this just means accepting that there - // will be a prefix of vector length (we don't need - // to use this). - let _length_do_not_remove_me_see_above: Vec<()> = Decode::decode(input)?; - - let version = input.read_byte()?; - - let is_signed = version & 0b1000_0000 != 0; - let version = version & 0b0111_1111; - if version != TRANSACTION_VERSION { - return None - } - - Some(UncheckedMortalExtrinsic { - signature: if is_signed { Some(Decode::decode(input)?) } else { None }, - function: Decode::decode(input)?, - }) - } -} - -impl Encode - for UncheckedMortalExtrinsic -where - Address: Encode, - Signature: Encode, - Index: Encode, - Call: Encode, -{ - fn encode(&self) -> Vec { - super::encode_with_vec_prefix::(|v| { - // 1 byte version id. - match self.signature.as_ref() { - Some(s) => { - v.push(TRANSACTION_VERSION | 0b1000_0000); - s.encode_to(v); - } - None => { - v.push(TRANSACTION_VERSION & 0b0111_1111); - } - } - self.function.encode_to(v); - }) - } -} - -#[cfg(feature = "std")] -impl serde::Serialize - for UncheckedMortalExtrinsic -{ - fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { - self.using_encoded(|bytes| seq.serialize_bytes(bytes)) - } -} - -#[cfg(feature = "std")] -impl fmt::Debug for UncheckedMortalExtrinsic where - Address: fmt::Debug, - Index: fmt::Debug, - Call: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UncheckedMortalExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2)), self.function) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use runtime_io::blake2_256; - use crate::codec::{Encode, Decode}; - use serde::{Serialize, Deserialize}; - - struct TestContext; - impl Lookup for TestContext { - type Source = u64; - type Target = u64; - fn lookup(&self, s: u64) -> Result { Ok(s) } - } - impl CurrentHeight for TestContext { - type BlockNumber = u64; - fn current_height(&self) -> u64 { 42 } - } - impl BlockNumberToHash for TestContext { - type BlockNumber = u64; - type Hash = u64; - fn block_number_to_hash(&self, n: u64) -> Option { Some(n) } - } - - #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Encode, Decode)] - struct TestSig(u64, Vec); - impl traits::Verify for TestSig { - type Signer = u64; - fn verify>(&self, mut msg: L, signer: &Self::Signer) -> bool { - *signer == self.0 && msg.get() == &self.1[..] - } - } - - const DUMMY_ACCOUNTID: u64 = 0; - - type Ex = UncheckedMortalExtrinsic, TestSig>; - type CEx = CheckedExtrinsic>; - - #[test] - fn unsigned_codec_should_work() { - let ux = Ex::new_unsigned(vec![0u8;0]); - let encoded = ux.encode(); - assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); - } - - #[test] - fn signed_codec_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::immortal(), 0u64).encode()), Era::immortal()); - let encoded = ux.encode(); - assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); - } - - #[test] - fn large_signed_codec_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8; 257], Era::immortal(), 0u64).using_encoded(blake2_256)[..].to_owned()), Era::immortal()); - let encoded = ux.encode(); - assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); - } - - #[test] - fn unsigned_check_should_work() { - let ux = Ex::new_unsigned(vec![0u8;0]); - assert!(!ux.is_signed().unwrap_or(false)); - assert!(>::check(ux, &TestContext).is_ok()); - } - - #[test] - fn badly_signed_check_should_fail() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, vec![0u8]), Era::immortal()); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); - } - - #[test] - fn immortal_signed_check_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::immortal(), 0u64).encode()), Era::immortal()); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0)), function: vec![0u8;0] })); - } - - #[test] - fn mortal_signed_check_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::mortal(32, 42), 42u64).encode()), Era::mortal(32, 42)); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0)), function: vec![0u8;0] })); - } - - #[test] - fn later_mortal_signed_check_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::mortal(32, 11), 11u64).encode()), Era::mortal(32, 11)); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0)), function: vec![0u8;0] })); - } - - #[test] - fn too_late_mortal_signed_check_should_fail() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::mortal(32, 10), 10u64).encode()), Era::mortal(32, 10)); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); - } - - #[test] - fn too_early_mortal_signed_check_should_fail() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::mortal(32, 43), 43u64).encode()), Era::mortal(32, 43)); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); - } - - #[test] - fn encoding_matches_vec() { - let ex = Ex::new_unsigned(vec![0u8;0]); - let encoded = ex.encode(); - let decoded = Ex::decode(&mut encoded.as_slice()).unwrap(); - assert_eq!(decoded, ex); - let as_vec: Vec = Decode::decode(&mut encoded.as_slice()).unwrap(); - assert_eq!(as_vec.encode(), encoded); - } -} diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index a6d94babbe577..8cf8449c03553 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -749,6 +749,68 @@ impl Checkable for T { } } +/// An abstract error concerning an attempt to verify, check or dispatch the transaction. This +/// cannot be more concrete because it's designed to work reasonably well over a broad range of +/// possible transaction types. +pub enum DispatchError { + /// General error to do with the inability to pay some fees (e.g. account balance too low). + Payment, + + /// General error to do with the permissions of the sender. + NoPermission, + + /// General error to do with the state of the system in general. + BadState, + + /// General error to do with the transaction being outdated (e.g. nonce too low). + Stale, + + /// General error to do with the transaction not yet being valid (e.g. nonce too high). + Future, + + /// General error to do with the transaction's proofs (e.g. signature). + BadProof, +} + +/// Means by which a transaction may be extended. This type embodies both the data and the logic +/// that should be additionally associated with the transaction. It should be plain old data. +pub trait SignedExtension: + Codec + MaybeDebug + Sync + Send + Clone + Eq + PartialEq + Ord + PartialOrd +{ + type AccountId; + type Call; + type Index; + fn pre_dispatch( + self, + account: &Self::AccountId, + index: &Self::Index, + call: &Self::Call, + weight: crate::weights::Weight, + ) -> Result<(), DispatchError>; +} + +impl< + AccountId, + Call, + Index, + A: SignedExtension, + B: SignedExtension +> SignedExtension for (A, B) { + type AccountId = AccountId; + type Call = Call; + type Index = Index; + fn pre_dispatch( + self, + account: &Self::AccountId, + index: &Self::Index, + call: &Self::Call, + weight: crate::weights::Weight, + ) -> Result<(), DispatchError> { + self.0.pre_dispatch(account, index, call, weight)?; + self.1.pre_dispatch(account, index, call, weight) + } +} + /// An "executable" piece of information, used by the standard Substrate Executive in order to /// enact a piece of extrinsic information by marshalling and dispatching to a named function /// call. @@ -767,7 +829,16 @@ pub trait Applyable: Sized + Send + Sync { /// Returns a reference to the sender if any. fn sender(&self) -> Option<&Self::AccountId>; /// Deconstructs into function call and sender. + /// + /// @deprecated - avoid using this and instead refactor into pre_dispatch. fn deconstruct(self) -> (Self::Call, Option); + /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, + /// index and sender. + fn pre_dispatch(self, + weight: crate::weights::Weight + ) -> Result<(Self::Call, Option), DispatchError> { + Ok(self.deconstruct()) + } } /// Auxiliary wrapper that holds an api instance and binds it to the given lifetime. diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 5cf774a5e9015..8879b163ff763 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -228,7 +228,7 @@ pub type Block = generic::Block; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; /// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Extrinsic type that has already been checked. pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 04bc98cecb021..0b66424576181 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -436,7 +436,7 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; /// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Extrinsic type that has already been checked. pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index 153a5df00ae8d..23b156c718e7f 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -422,7 +422,7 @@ mod tests { } pub type Block = primitives::generic::Block; - pub type UncheckedExtrinsic = primitives::generic::UncheckedMortalCompactExtrinsic; + pub type UncheckedExtrinsic = primitives::generic::UncheckedExtrinsic; srml_support::construct_runtime!( pub enum Test where diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 359407d222c18..77597591775d7 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -1211,7 +1211,7 @@ mod tests { } pub type Block = primitives::generic::Block; - pub type UncheckedExtrinsic = primitives::generic::UncheckedMortalCompactExtrinsic; + pub type UncheckedExtrinsic = primitives::generic::UncheckedExtrinsic; srml_support::construct_runtime!( pub enum Test where diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 49d4addb3bc2b..dbfe02e00bc41 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -79,8 +79,7 @@ use rstd::marker::PhantomData; use rstd::result; use primitives::{generic::Digest, traits::{ self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalize, - OnInitialize, NumberFor, Block as BlockT, OffchainWorker, - ValidateUnsigned, + OnInitialize, NumberFor, Block as BlockT, OffchainWorker, ValidateUnsigned }}; use srml_support::{Dispatchable, traits::MakePayment}; use parity_codec::{Codec, Encode}; @@ -90,6 +89,8 @@ use primitives::transaction_validity::{TransactionValidity, TransactionPriority, use primitives::weights::Weighable; mod internal { + use primitives::traits::DispatchError; + pub const MAX_TRANSACTIONS_WEIGHT: u32 = 4 * 1024 * 1024; pub enum ApplyError { @@ -104,6 +105,19 @@ mod internal { Success, Fail(&'static str), } + + impl From for ApplyError { + fn from(d: DispatchError) -> Self { + match d { + DispatchError::Payment => ApplyError::CantPay, + DispatchError::NoPermission => ApplyError::CantPay, + DispatchError::BadState => ApplyError::CantPay, + DispatchError::Stale => ApplyError::Stale, + DispatchError::Future => ApplyError::Future, + DispatchError::BadProof => ApplyError::BadSignature(""), + } + } + } } /// Trait that can be used to execute a block. @@ -264,36 +278,40 @@ where // Verify that the signature is good. let xt = uxt.check(&Default::default()).map_err(internal::ApplyError::BadSignature)?; + // We don't need to make sure to `note_extrinsic` only after we know it's going to be + // executed to prevent it from leaking in storage since at this point, it will either + // execute or panic (and revert storage changes). + if let Some(encoded) = to_note { + >::note_extrinsic(encoded); + } + // Check the weight of the block if that extrinsic is applied. let weight = xt.weight(encoded_len); + + // TODO: Consider placing into a transaction extension. if >::all_extrinsics_weight() + weight > internal::MAX_TRANSACTIONS_WEIGHT { return Err(internal::ApplyError::FullBlock); } if let (Some(sender), Some(index)) = (xt.sender(), xt.index()) { - // check index + // TODO: Place into a transaction extension. + // check nonce and increment let expected_index = >::account_nonce(sender); if index != &expected_index { return Err( if index < &expected_index { internal::ApplyError::Stale } else { internal::ApplyError::Future } ) } + >::inc_account_nonce(sender); + + // TODO: Place into a transaction extension. // pay any fees Payment::make_payment(sender, encoded_len).map_err(|_| internal::ApplyError::CantPay)?; - - // AUDIT: Under no circumstances may this function panic from here onwards. - // FIXME: ensure this at compile-time (such as by not defining a panic function, forcing - // a linker error unless the compiler can prove it cannot be called). - // increment nonce in storage - >::inc_account_nonce(sender); } - // Make sure to `note_extrinsic` only after we know it's going to be executed - // to prevent it from leaking in storage. - if let Some(encoded) = to_note { - >::note_extrinsic(encoded); - } + // AUDIT: Under no circumstances may this function panic from here onwards. // Decode parameters and dispatch - let (f, s) = xt.deconstruct(); + let (f, s) = Applyable::pre_dispatch(xt, weight) + .map_err(internal::ApplyError::from)?; let r = f.dispatch(s.into()); >::note_applied_extrinsic(&r, encoded_len as u32); @@ -348,6 +366,7 @@ where Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR), }; + // TODO: remove this block next block into the transaction extension. match (xt.sender(), xt.index()) { (Some(sender), Some(index)) => { // pay any fees diff --git a/srml/support/test/tests/instance.rs b/srml/support/test/tests/instance.rs index 62e7263b511be..46edcd7df323b 100644 --- a/srml/support/test/tests/instance.rs +++ b/srml/support/test/tests/instance.rs @@ -269,7 +269,7 @@ srml_support::construct_runtime!( pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; fn new_test_ext() -> runtime_io::TestExternalities { GenesisConfig{ @@ -407,4 +407,4 @@ fn storage_with_instance_basic_operation() { DoubleMap::remove(key1, key2); assert_eq!(DoubleMap::get(key1, key2), 0); }); -} \ No newline at end of file +} diff --git a/srml/support/test/tests/issue2219.rs b/srml/support/test/tests/issue2219.rs index 185b5e24807a9..9bae9bcde5549 100644 --- a/srml/support/test/tests/issue2219.rs +++ b/srml/support/test/tests/issue2219.rs @@ -152,7 +152,7 @@ pub type BlockNumber = u64; pub type Index = u64; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl system::Trait for Runtime { type Hash = H256; @@ -183,4 +183,4 @@ fn create_genesis_config() { enable_storage_role: true, }) }; -} \ No newline at end of file +} From 37f6ae00822da7adfef81514d5bf3edaed1831c6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 11 Jul 2019 15:56:40 +0200 Subject: [PATCH 02/33] Rest of mockup. Add tips. --- .../src/generic/checked_extrinsic.rs | 57 ++++---- .../src/generic/unchecked_extrinsic.rs | 104 ++++----------- core/sr-primitives/src/testing.rs | 23 +++- core/sr-primitives/src/traits.rs | 126 +++++++++++++----- .../sr-primitives/src/transaction_validity.rs | 112 +++++++++++----- srml/balances/src/lib.rs | 44 +++++- srml/executive/src/lib.rs | 54 +------- srml/support/src/dispatch.rs | 17 +-- srml/system/src/lib.rs | 73 +++++++++- 9 files changed, 359 insertions(+), 251 deletions(-) diff --git a/core/sr-primitives/src/generic/checked_extrinsic.rs b/core/sr-primitives/src/generic/checked_extrinsic.rs index c1d22d7c09186..5a54bf1afb1b6 100644 --- a/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -18,65 +18,72 @@ //! stage. use rstd::result::Result; -use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay, SignedExtension, DispatchError}; +use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay, SignedExtension, DispatchError, Dispatchable, DispatchResult, ValidateUnsigned}; use crate::weights::{Weighable, Weight}; +use crate::transaction_validity::{ValidTransaction, TransactionValidity}; /// Definition of something that the external world might want to say; its /// existence implies that it has been checked and is good, particularly with /// regards to the signature. #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Debug))] -pub struct CheckedExtrinsic { +pub struct CheckedExtrinsic { /// Who this purports to be from and the number of extrinsics have come before /// from the same signer, if anyone (note this is not a signature). - pub signed: Option<(AccountId, Index, Extra)>, + pub signed: Option<(AccountId, Extra)>, /// The function that should be called. pub function: Call, } -impl traits::Applyable +impl traits::Applyable for - CheckedExtrinsic + CheckedExtrinsic where AccountId: Member + MaybeDisplay, - Index: Member + MaybeDisplay + SimpleArithmetic, - Call: Member, - Extra: SignedExtension, + Call: Member + Dispatchable, + Extra: SignedExtension, + Origin: From>, { type AccountId = AccountId; - type Call = Call; - type Index = Index; - fn index(&self) -> Option<&Self::Index> { - self.signed.as_ref().map(|x| &x.1) - } + type Call = Call; fn sender(&self) -> Option<&Self::AccountId> { self.signed.as_ref().map(|x| &x.0) } - fn deconstruct(self) -> (Self::Call, Option) { - if let Some((id, _, extra)) = self.signed { - (self.function, Some(id)) + fn validate>(&self, + weight: crate::weights::Weight, + ) -> TransactionValidity { + if let Some((ref id, ref extra)) = self.signed { + Extra::validate(extra, id, weight).into() } else { - (self.function, None) + match Extra::validate_unsigned(weight) { + Ok(v) => match UnsignedValidator::validate_unsigned(&self.function) { + TransactionValidity::Valid(v) => Ok(TransactionValidity(v.combine_with(extra))), + x => x, + }, + x => x.into(), + } } } - fn pre_dispatch(self, + fn dispatch(self, weight: crate::weights::Weight, - ) -> Result<(Self::Call, Option), DispatchError> { - if let Some((id, index, extra)) = self.signed { - Extra::pre_dispatch(extra, &id, &index, &self.function, weight)?; - Ok((self.function, Some(id))) + ) -> Result { + let maybe_who = if let Some((id, extra)) = self.signed { + Extra::pre_dispatch(extra, &id, weight)?; + Some(id) } else { - Ok((self.function, None)) - } + Extra::pre_dispatch_unsigned(weight)?; + None + }; + Ok(self.function.dispatch(Origin::from(maybe_who))) } } -impl Weighable for CheckedExtrinsic +impl Weighable for CheckedExtrinsic where Call: Weighable, { diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index 7eb31e28fd608..39c426e3fc39e 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -21,64 +21,35 @@ use std::fmt; use rstd::prelude::*; use runtime_io::blake2_256; -use crate::codec::{Decode, Encode, Codec, Input, Compact}; +use crate::codec::{Decode, Encode, Input, Compact}; use crate::traits::{ - self, Member, SimpleArithmetic, MaybeDebug, MaybeDisplay, CurrentHeight, SignedExtension, - BlockNumberToHash, Lookup, Checkable, Extrinsic, SaturatedConversion, DispatchError + self, Member, SimpleArithmetic, MaybeDisplay, CurrentHeight, SignedExtension, + BlockNumberToHash, Lookup, Checkable, Extrinsic, SaturatedConversion }; use super::{CheckedExtrinsic, Era}; const TRANSACTION_VERSION: u8 = 1; -/* -/// A type with which the signed payload of a transaction may be extended. -pub trait OSignedExtension: Codec + MaybeDebug {} - -impl SignedExtra for T {} - -/// A type that names a `SignedExtension` and knows how to deal with it. -pub trait OExtension { - /// An extra data field that should go into the signed part of the payload. - type SignedPayload: OSignedExtension; - - /// Anything that should be executed immediately before dispatch. - fn pre_dispatch( - a: &AccountId, - c: &Call, - e: Self::SignedPayload - ) -> Result<(), DispatchError>; -} - -impl OExtension for () { - type SignedPayload = (); - fn pre_dispatch( - _: &AccountId, - _: &Call, - _: () - ) -> Result<(), DispatchError> { Ok(()) } -} -*/ /// A extrinsic right from the external world. This is unchecked and so /// can contain a signature. #[derive(PartialEq, Eq, Clone)] -pub struct UncheckedExtrinsic +pub struct UncheckedExtrinsic where Extra: SignedExtension { /// The signature, address, number of extrinsics have come before from /// the same signer and an era describing the longevity of this transaction, /// if this is a signed extrinsic. - pub signature: Option<(Address, Signature, Compact, Era, Extra)>, + pub signature: Option<(Address, Signature, Era, Extra)>, /// The function that should be called. pub function: Call, } -impl - UncheckedExtrinsic +impl + UncheckedExtrinsic { /// New instance of a signed extrinsic aka "transaction". pub fn new_signed( - index: Index, function: Call, signed: Address, signature: Signature, @@ -86,7 +57,7 @@ impl extra: Extra ) -> Self { UncheckedExtrinsic { - signature: Some((signed, signature, index.into(), era, extra)), + signature: Some((signed, signature, era, extra)), function, } } @@ -100,25 +71,23 @@ impl } } -impl Extrinsic - for UncheckedExtrinsic +impl Extrinsic + for UncheckedExtrinsic { fn is_signed(&self) -> Option { Some(self.signature.is_some()) } } -impl +impl Checkable for - UncheckedExtrinsic + UncheckedExtrinsic where Address: Member + MaybeDisplay, - Index: Member + MaybeDisplay + SimpleArithmetic, - Compact: Encode, Call: Encode + Member, Signature: Member + traits::Verify, - Extra: SignedExtension, + Extra: SignedExtension, AccountId: Member + MaybeDisplay, BlockNumber: SimpleArithmetic, Hash: Encode, @@ -126,16 +95,16 @@ where + CurrentHeight + BlockNumberToHash, { - type Checked = CheckedExtrinsic; + type Checked = CheckedExtrinsic; fn check(self, context: &Context) -> Result { Ok(match self.signature { - Some((signed, signature, index, era, extra)) => { + Some((signed, signature, era, extra)) => { let current_u64 = context.current_height().saturated_into::(); let h = context.block_number_to_hash(era.birth(current_u64).saturated_into()) .ok_or("transaction birth block ancient")?; let signed = context.lookup(signed)?; - let raw_payload = (index, self.function, era, h, extra); + let raw_payload = (self.function, era, h, extra); if !raw_payload.using_encoded(|payload| { if payload.len() > 256 { signature.verify(&blake2_256(payload)[..], &signed) @@ -146,8 +115,8 @@ where return Err(crate::BAD_SIGNATURE) } CheckedExtrinsic { - signed: Some((signed, (raw_payload.0).0, raw_payload.4)), - function: raw_payload.1, + signed: Some((signed, raw_payload.3)), + function: raw_payload.0, } } None => CheckedExtrinsic { @@ -158,12 +127,11 @@ where } } -impl Decode - for UncheckedExtrinsic +impl Decode + for UncheckedExtrinsic where Address: Decode, Signature: Decode, - Compact: Decode, Call: Decode, Extra: SignedExtension, { @@ -189,12 +157,11 @@ where } } -impl Encode - for UncheckedExtrinsic +impl Encode + for UncheckedExtrinsic where Address: Encode, Signature: Encode, - Compact: Encode, Call: Encode, Extra: SignedExtension, { @@ -216,9 +183,8 @@ where } #[cfg(feature = "std")] -impl serde::Serialize - for UncheckedExtrinsic - where Compact: Encode +impl serde::Serialize + for UncheckedExtrinsic { fn serialize(&self, seq: S) -> Result where S: ::serde::Serializer { self.using_encoded(|bytes| seq.serialize_bytes(bytes)) @@ -226,16 +192,15 @@ impl fmt::Debug - for UncheckedExtrinsic +impl fmt::Debug + for UncheckedExtrinsic where Address: fmt::Debug, - Index: fmt::Debug, Call: fmt::Debug, Extra: SignedExtension, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UncheckedExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2, &x.4)), self.function) + write!(f, "UncheckedExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2, &x.3)), self.function) } } @@ -278,20 +243,9 @@ mod tests { struct TestExtra; impl SignedExtension for TestExtra { type AccountId = u64; - type Index = u64; - type Call = Vec; - fn pre_dispatch( - self, - _a: &Self::AccountId, - _i: &Self::Index, - _c: &Self::Call, - _w: crate::weights::Weight, - ) -> Result<(), DispatchError> { - Ok(()) - } } - type Ex = UncheckedExtrinsic, TestSig, TestExtra>; - type CEx = CheckedExtrinsic, TestExtra>; + type Ex = UncheckedExtrinsic, TestSig, TestExtra>; + type CEx = CheckedExtrinsic, TestExtra>; #[test] fn unsigned_codec_should_work() { diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index f8df25ec596b0..3a5bf8af9f4bf 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -19,8 +19,8 @@ use serde::{Serialize, Serializer, Deserialize, de::Error as DeError, Deserializer}; use std::{fmt::Debug, ops::Deref, fmt}; use crate::codec::{Codec, Encode, Decode}; -use crate::traits::{self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, TypedKey}; -use crate::{generic, KeyTypeId}; +use crate::traits::{self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, TypedKey, DispatchError, DispatchResult}; +use crate::{generic, KeyTypeId, transaction_validity::ValidTransaction}; use crate::weights::{Weighable, Weight}; pub use substrate_primitives::H256; use substrate_primitives::U256; @@ -227,12 +227,21 @@ impl Applyable for TestXt where Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug, { type AccountId = u64; - type Index = u64; - type Call = Call; fn sender(&self) -> Option<&u64> { self.0.as_ref() } - fn index(&self) -> Option<&u64> { self.0.as_ref().map(|_| &self.1) } - fn deconstruct(self) -> (Self::Call, Option) { - (self.2, self.0) + + /// Checks to see if this is a valid *transaction*. It returns information on it if so. + fn validate(&self, + weight: crate::weights::Weight + ) -> Result { + Ok(Default::default()) + } + + /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, + /// index and sender. + fn dispatch(self, + weight: crate::weights::Weight + ) -> Result { + Ok(Ok(())) } } impl Weighable for TestXt { diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 8cf8449c03553..d3c5afa68de59 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -23,7 +23,7 @@ use runtime_io; #[cfg(feature = "std")] use serde::{Serialize, Deserialize, de::DeserializeOwned}; use substrate_primitives::{self, Hasher, Blake2Hasher}; use crate::codec::{Codec, Encode, Decode, HasCompact}; -use crate::transaction_validity::TransactionValidity; +use crate::transaction_validity::{ValidTransaction, TransactionValidity}; use crate::generic::{Digest, DigestItem}; pub use substrate_primitives::crypto::TypedKey; pub use integer_sqrt::IntegerSquareRoot; @@ -770,44 +770,106 @@ pub enum DispatchError { /// General error to do with the transaction's proofs (e.g. signature). BadProof, + +/* /// General error to do with actually executing the dispatched logic. + User(&'static str),*/ +} + +impl From for i8 { + fn from(e: DispatchError) -> i8 { + match e { + DispatchError::Payment => -64, + DispatchError::NoPermission => -65, + DispatchError::BadState => -66, + DispatchError::Stale => -67, + DispatchError::Future => -68, + DispatchError::BadProof => -69, + } + } +} + +/// Result of a module function call; either nothing (functions are only called for "side effects") +/// or an error message. +pub type DispatchResult = result::Result<(), &'static str>; + +/// A lazy call (module function and argument values) that can be executed via its `dispatch` +/// method. +pub trait Dispatchable { + /// Every function call from your runtime has an origin, which specifies where the extrinsic was + /// generated from. In the case of a signed extrinsic (transaction), the origin contains an + /// identifier for the caller. The origin can be empty in the case of an inherent extrinsic. + type Origin; + /// ... + type Trait; + /// Actually dispatch this call and result the result of it. + fn dispatch(self, origin: Self::Origin) -> DispatchResult; } /// Means by which a transaction may be extended. This type embodies both the data and the logic /// that should be additionally associated with the transaction. It should be plain old data. pub trait SignedExtension: - Codec + MaybeDebug + Sync + Send + Clone + Eq + PartialEq + Ord + PartialOrd + Codec + MaybeDebug + Sync + Send + Clone + Eq + PartialEq { type AccountId; - type Call; - type Index; + + fn validate( + &self, + who: &Self::AccountId, + _weight: crate::weights::Weight, + ) -> Result { Ok(Default::default()) } + fn pre_dispatch( self, - account: &Self::AccountId, - index: &Self::Index, - call: &Self::Call, + who: &Self::AccountId, weight: crate::weights::Weight, - ) -> Result<(), DispatchError>; + ) -> Result<(), DispatchError> { self.validate(who, weight).map(|_| ()) } + + fn validate_unsigned( + _weight: crate::weights::Weight, + ) -> Result { Ok(Default::default()) } + + fn pre_dispatch_unsigned( + weight: crate::weights::Weight, + ) -> Result<(), DispatchError> { Self::validate_unsigned(weight).map(|_| ()) } } impl< AccountId, - Call, - Index, - A: SignedExtension, - B: SignedExtension + A: SignedExtension, + B: SignedExtension, > SignedExtension for (A, B) { type AccountId = AccountId; - type Call = Call; - type Index = Index; + fn validate( + &self, + who: &Self::AccountId, + weight: crate::weights::Weight, + ) -> Result { + let a = self.0.validate(who, weight)?; + let b = self.1.validate(who, weight)?; + Ok(a.combine_with(b)) + } fn pre_dispatch( self, - account: &Self::AccountId, - index: &Self::Index, - call: &Self::Call, + who: &Self::AccountId, weight: crate::weights::Weight, ) -> Result<(), DispatchError> { - self.0.pre_dispatch(account, index, call, weight)?; - self.1.pre_dispatch(account, index, call, weight) + self.0.pre_dispatch(who, weight)?; + self.1.pre_dispatch(who, weight)?; + Ok(()) + } + fn validate_unsigned( + weight: crate::weights::Weight, + ) -> Result { + let a = A::validate_unsigned(weight)?; + let b = B::validate_unsigned(weight)?; + Ok(a.combine_with(b)) + } + fn pre_dispatch_unsigned( + weight: crate::weights::Weight, + ) -> Result<(), DispatchError> { + A::pre_dispatch_unsigned(weight)?; + B::pre_dispatch_unsigned(weight)?; + Ok(()) } } @@ -820,25 +882,23 @@ impl< pub trait Applyable: Sized + Send + Sync { /// Id of the account that is responsible for this piece of information (sender). type AccountId: Member + MaybeDisplay; - /// Index allowing to disambiguate other `Applyable`s from the same `AccountId`. - type Index: Member + MaybeDisplay + SimpleArithmetic; - /// Function call. - type Call: Member; - /// Returns a reference to the index if any. - fn index(&self) -> Option<&Self::Index>; + + /// Type by which we can dispatch. Restricts the UnsignedValidator type. + type Call; + /// Returns a reference to the sender if any. fn sender(&self) -> Option<&Self::AccountId>; - /// Deconstructs into function call and sender. - /// - /// @deprecated - avoid using this and instead refactor into pre_dispatch. - fn deconstruct(self) -> (Self::Call, Option); + + /// Checks to see if this is a valid *transaction*. It returns information on it if so. + fn validate>(&self, + weight: crate::weights::Weight + ) -> TransactionValidity; + /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. - fn pre_dispatch(self, + fn dispatch(self, weight: crate::weights::Weight - ) -> Result<(Self::Call, Option), DispatchError> { - Ok(self.deconstruct()) - } + ) -> Result; } /// Auxiliary wrapper that holds an api instance and binds it to the given lifetime. diff --git a/core/sr-primitives/src/transaction_validity.rs b/core/sr-primitives/src/transaction_validity.rs index f36599b67b42c..d2e3b27bcab11 100644 --- a/core/sr-primitives/src/transaction_validity.rs +++ b/core/sr-primitives/src/transaction_validity.rs @@ -18,6 +18,8 @@ use rstd::prelude::*; use crate::codec::{Encode, Decode}; +use crate::transaction_validity::TransactionValidity::Valid; +use crate::traits::DispatchError; /// Priority for a transaction. Additive. Higher is better. pub type TransactionPriority = u64; @@ -36,40 +38,78 @@ pub enum TransactionValidity { /// Transaction is invalid. Details are described by the error code. Invalid(i8), /// Transaction is valid. - Valid { - /// Priority of the transaction. - /// - /// Priority determines the ordering of two transactions that have all - /// their dependencies (required tags) satisfied. - priority: TransactionPriority, - /// Transaction dependencies - /// - /// A non-empty list signifies that some other transactions which provide - /// given tags are required to be included before that one. - requires: Vec, - /// Provided tags - /// - /// A list of tags this transaction provides. Successfully importing the transaction - /// will enable other transactions that depend on (require) those tags to be included as well. - /// Provided and required tags allow Substrate to build a dependency graph of transactions - /// and import them in the right (linear) order. - provides: Vec, - /// Transaction longevity - /// - /// Longevity describes minimum number of blocks the validity is correct. - /// After this period transaction should be removed from the pool or revalidated. - longevity: TransactionLongevity, - /// A flag indicating if the transaction should be propagated to other peers. - /// - /// By setting `false` here the transaction will still be considered for - /// including in blocks that are authored on the current node, but will - /// never be sent to other peers. - propagate: bool, - }, + Valid(ValidTransaction), /// Transaction validity can't be determined. Unknown(i8), } +impl From> for TransactionValidity { + fn from(r: Result) -> Self { + match r { + Ok(v) => TransactionValidity::Valid(v), + Err(e) => TransactionValidity::Invalid(e.into()), + } + } +} + +/// Information concerning a valid transaction. +#[derive(Clone, PartialEq, Eq, Encode)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct ValidTransaction { + /// Priority of the transaction. + /// + /// Priority determines the ordering of two transactions that have all + /// their dependencies (required tags) satisfied. + pub priority: TransactionPriority, + /// Transaction dependencies + /// + /// A non-empty list signifies that some other transactions which provide + /// given tags are required to be included before that one. + pub requires: Vec, + /// Provided tags + /// + /// A list of tags this transaction provides. Successfully importing the transaction + /// will enable other transactions that depend on (require) those tags to be included as well. + /// Provided and required tags allow Substrate to build a dependency graph of transactions + /// and import them in the right (linear) order. + pub provides: Vec, + /// Transaction longevity + /// + /// Longevity describes minimum number of blocks the validity is correct. + /// After this period transaction should be removed from the pool or revalidated. + pub longevity: TransactionLongevity, + /// A flag indicating if the transaction should be propagated to other peers. + /// + /// By setting `false` here the transaction will still be considered for + /// including in blocks that are authored on the current node, but will + /// never be sent to other peers. + pub propagate: bool, +} + +impl Default for ValidTransaction { + fn default() -> Self { + ValidTransaction { + priority: 0, + requires: vec![], + provides: vec![], + longevity: TransactionLongevity::max_value(), + propagate: true, + } + } +} + +impl ValidTransaction { + pub fn combine_with(mut self, mut other: ValidTransaction) -> Self { + ValidTransaction { + priority: self.priority + other.priority, + requires: { self.requires.append(&mut other.requires); self.requires }, + provides: { self.provides.append(&mut other.provides); self.provides }, + longevity: self.longevity.min(other.longevity), + propagate: self.propagate && other.propagate, + } + } +} + impl Decode for TransactionValidity { fn decode(value: &mut I) -> Option { match value.read_byte()? { @@ -81,9 +121,9 @@ impl Decode for TransactionValidity { let longevity = TransactionLongevity::decode(value)?; let propagate = bool::decode(value).unwrap_or(true); - Some(TransactionValidity::Valid { + Some(TransactionValidity::Valid(ValidTransaction { priority, requires, provides, longevity, propagate, - }) + })) }, 2 => Some(TransactionValidity::Unknown(i8::decode(value)?)), _ => None, @@ -101,24 +141,24 @@ mod tests { 1, 5, 0, 0, 0, 0, 0, 0, 0, 4, 16, 1, 2, 3, 4, 4, 12, 4, 5, 6, 42, 0, 0, 0, 0, 0, 0, 0 ]; - assert_eq!(TransactionValidity::decode(&mut &*old_encoding), Some(TransactionValidity::Valid { + assert_eq!(TransactionValidity::decode(&mut &*old_encoding), Some(TransactionValidity::Valid(ValidTransaction { priority: 5, requires: vec![vec![1, 2, 3, 4]], provides: vec![vec![4, 5, 6]], longevity: 42, propagate: true, - })); + }))); } #[test] fn should_encode_and_decode() { - let v = TransactionValidity::Valid { + let v = TransactionValidity::Valid(ValidTransaction { priority: 5, requires: vec![vec![1, 2, 3, 4]], provides: vec![vec![4, 5, 6]], longevity: 42, propagate: false, - }; + }); let encoded = v.encode(); assert_eq!( diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 84e023ee5b2aa..16b7bcc3a185d 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -1130,18 +1130,50 @@ where } } -impl, I: Instance> MakePayment for Module { - fn make_payment(transactor: &T::AccountId, encoded_len: usize) -> Result { - let encoded_len = T::Balance::from(encoded_len as u32); - let transaction_fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * encoded_len; +/// Require the transactor pay for themselves and maybe include a tip to gain additional priority +/// in the queue. +#[derive(Encode, Decode, Clone, Eq, PartialEq)] +pub struct TakeFees(T::Balance); + +#[cfg(feature = "std")] +impl rstd::fmt::Debug for TakeFees { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + self.0.fmt(f) + } +} + +// TODO: wire this and CheckNonce in to the runtime. + +use primitives::traits::DispatchError; +use primitives::transaction_validity::ValidTransaction; +use primitives::weights::Weight; + +impl SignedExtension for TakeFees { + type AccountId = T::AccountId; + + fn validate( + &self, + who: &Self::AccountId, + weight: Weight, + ) -> rstd::result::Result { + let fee_x = T::Balance::from(weight as u32); + // should be weight_to_fee(weight) + let transaction_fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * fee_x; let imbalance = Self::withdraw( transactor, transaction_fee, WithdrawReason::TransactionPayment, ExistenceRequirement::KeepAlive - )?; + ).map_err(|_| DispatchError::Payment)?; T::TransactionPayment::on_unbalanced(imbalance); - Ok(()) + + Ok(ValidTransaction { + priority: _weight as TransactionPriority + self.0.clone() as TransactionPriority, // TODO: overflow?? + requires: vec![], + provides: vec![], + longevity: TransactionLongevity::max_value(), + propagate: true, + }) } } diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index dbfe02e00bc41..443ba947b3e44 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -293,26 +293,12 @@ where return Err(internal::ApplyError::FullBlock); } - if let (Some(sender), Some(index)) = (xt.sender(), xt.index()) { - // TODO: Place into a transaction extension. - // check nonce and increment - let expected_index = >::account_nonce(sender); - if index != &expected_index { return Err( - if index < &expected_index { internal::ApplyError::Stale } else { internal::ApplyError::Future } - ) } - >::inc_account_nonce(sender); - - // TODO: Place into a transaction extension. - // pay any fees - Payment::make_payment(sender, encoded_len).map_err(|_| internal::ApplyError::CantPay)?; - } - // AUDIT: Under no circumstances may this function panic from here onwards. // Decode parameters and dispatch - let (f, s) = Applyable::pre_dispatch(xt, weight) + let (f, s) = Applyable::dispatch(xt, weight) .map_err(internal::ApplyError::from)?; - let r = f.dispatch(s.into()); + >::note_applied_extrinsic(&r, encoded_len as u32); r.map(|_| internal::ApplyOutcome::Success).or_else(|e| match e { @@ -352,6 +338,7 @@ where const UNKNOWN_ERROR: i8 = -127; const MISSING_SENDER: i8 = -20; const INVALID_INDEX: i8 = -10; + const BAD_DISPATCH: i8 = -15; let encoded_len = uxt.encode().len(); @@ -366,40 +353,7 @@ where Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR), }; - // TODO: remove this block next block into the transaction extension. - match (xt.sender(), xt.index()) { - (Some(sender), Some(index)) => { - // pay any fees - if Payment::make_payment(sender, encoded_len).is_err() { - return TransactionValidity::Invalid(ApplyError::CantPay as i8) - } - - // check index - let expected_index = >::account_nonce(sender); - if index < &expected_index { - return TransactionValidity::Invalid(ApplyError::Stale as i8) - } - - let index = *index; - let provides = vec![(sender, index).encode()]; - let requires = if expected_index < index { - vec![(sender, index - One::one()).encode()] - } else { - vec![] - }; - - TransactionValidity::Valid { - priority: encoded_len as TransactionPriority, - requires, - provides, - longevity: TransactionLongevity::max_value(), - propagate: true, - } - }, - (None, None) => UnsignedValidator::validate_unsigned(&xt.deconstruct().0), - (Some(_), None) => TransactionValidity::Invalid(INVALID_INDEX), - (None, Some(_)) => TransactionValidity::Invalid(MISSING_SENDER), - } + xt.validate::() } /// Start an offchain worker and generate extrinsics. diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index f990cbd8d5a1e..00c21a31ba47f 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -25,25 +25,16 @@ pub use srml_metadata::{ FunctionMetadata, DecodeDifferent, DecodeDifferentArray, FunctionArgumentMetadata, ModuleConstantMetadata, DefaultByte, DefaultByteGetter, }; -pub use sr_primitives::weights::{TransactionWeight, Weighable, Weight}; +pub use sr_primitives::{ + weights::{TransactionWeight, Weighable, Weight}, traits::{Dispatchable, DispatchResult} +}; /// A type that cannot be instantiated. pub enum Never {} /// Result of a module function call; either nothing (functions are only called for "side effects") /// or an error message. -pub type Result = result::Result<(), &'static str>; - -/// A lazy call (module function and argument values) that can be executed via its `dispatch` -/// method. -pub trait Dispatchable { - /// Every function call from your runtime has an origin, which specifies where the extrinsic was - /// generated from. In the case of a signed extrinsic (transaction), the origin contains an - /// identifier for the caller. The origin can be empty in the case of an inherent extrinsic. - type Origin; - type Trait; - fn dispatch(self, origin: Self::Origin) -> Result; -} +pub type Result = DispatchResult; /// Serializable version of Dispatchable. /// This value can be used as a "function" in an extrinsic. diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index a55cb9be86ea4..8961c98a717ad 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -76,15 +76,20 @@ use serde::Serialize; use rstd::prelude::*; #[cfg(any(feature = "std", test))] use rstd::map; -use primitives::{generic, traits::{self, CheckEqual, SimpleArithmetic, - SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, CurrentHeight, BlockNumberToHash, - MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded, Lookup, - Zero, -}}; +use primitives::{ + generic, weights::Weight, traits::{ + self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, + SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, CurrentHeight, BlockNumberToHash, + MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded, + Lookup, DispatchError + }, transaction_validity::{ + ValidTransaction, TransactionPriority, TransactionLongevity + }, +}; use substrate_primitives::storage::well_known_keys; use srml_support::{ storage, decl_module, decl_event, decl_storage, StorageDoubleMap, StorageValue, - StorageMap, Parameter, for_each_tuple, traits::{Contains, Get}, + StorageMap, Parameter, for_each_tuple, traits::{Contains, Get}, Dispatchable }; use safe_mix::TripletMix; use parity_codec::{Encode, Decode}; @@ -748,6 +753,62 @@ impl Module { } } +/// Nonce check and increment to give replay protection for transactions. +#[derive(Encode, Decode, Clone, Eq, PartialEq)] +pub struct CheckNonce(T::Index); + +#[cfg(feature = "std")] +impl rstd::fmt::Debug for CheckNonce { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + self.0.fmt(f) + } +} + +impl SignedExtension for CheckNonce { + type AccountId = T::AccountId; + fn pre_dispatch( + self, + who: &Self::AccountId, + _weight: Weight, + ) -> Result<(), DispatchError> { + let expected = >::get(who); + if self.0 != expected { + return Err( + if self.0 < expected { DispatchError::Stale } else { DispatchError::Future } + ) + } + >::insert(who, expected + T::Index::one()); + Ok(()) + } + + fn validate( + &self, + who: &Self::AccountId, + _weight: Weight, + ) -> Result { + // check index + let expected = >::get(who); + if self.0 < expected { + return Err(DispatchError::Stale) + } + + let provides = vec![Encode::encode(&(who, self.0))]; + let requires = if expected < self.0 { + vec![Encode::encode(&(who, self.0 - One::one()))] + } else { + vec![] + }; + + Ok(ValidTransaction { + priority: _weight as TransactionPriority, + requires, + provides, + longevity: TransactionLongevity::max_value(), + propagate: true, + }) + } +} + pub struct ChainContext(::rstd::marker::PhantomData); impl Default for ChainContext { fn default() -> Self { From 2e5b1f4628a65a6fec87f80789d15cb37ac44d81 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 11 Jul 2019 23:02:52 +0200 Subject: [PATCH 03/33] Fix some build issues --- .../src/generic/checked_extrinsic.rs | 12 ++++--- .../src/generic/unchecked_extrinsic.rs | 2 +- core/sr-primitives/src/testing.rs | 21 ++++++----- core/sr-primitives/src/traits.rs | 9 ++++- .../sr-primitives/src/transaction_validity.rs | 4 ++- srml/balances/src/lib.rs | 35 +++++++++---------- srml/executive/src/lib.rs | 14 ++++---- srml/support/src/traits.rs | 13 ------- srml/system/src/lib.rs | 2 +- 9 files changed, 57 insertions(+), 55 deletions(-) diff --git a/core/sr-primitives/src/generic/checked_extrinsic.rs b/core/sr-primitives/src/generic/checked_extrinsic.rs index 5a54bf1afb1b6..bd9a711fc0e54 100644 --- a/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -18,9 +18,12 @@ //! stage. use rstd::result::Result; -use crate::traits::{self, Member, SimpleArithmetic, MaybeDisplay, SignedExtension, DispatchError, Dispatchable, DispatchResult, ValidateUnsigned}; +use crate::traits::{ + self, Member, MaybeDisplay, SignedExtension, DispatchError, Dispatchable, DispatchResult, + ValidateUnsigned +}; use crate::weights::{Weighable, Weight}; -use crate::transaction_validity::{ValidTransaction, TransactionValidity}; +use crate::transaction_validity::TransactionValidity; /// Definition of something that the external world might want to say; its /// existence implies that it has been checked and is good, particularly with @@ -60,8 +63,9 @@ where Extra::validate(extra, id, weight).into() } else { match Extra::validate_unsigned(weight) { - Ok(v) => match UnsignedValidator::validate_unsigned(&self.function) { - TransactionValidity::Valid(v) => Ok(TransactionValidity(v.combine_with(extra))), + Ok(extra) => match U::validate_unsigned(&self.function) { + TransactionValidity::Valid(v) => + TransactionValidity::Valid(v.combine_with(extra)), x => x, }, x => x.into(), diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index 39c426e3fc39e..a500283b7a947 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -21,7 +21,7 @@ use std::fmt; use rstd::prelude::*; use runtime_io::blake2_256; -use crate::codec::{Decode, Encode, Input, Compact}; +use crate::codec::{Decode, Encode, Input}; use crate::traits::{ self, Member, SimpleArithmetic, MaybeDisplay, CurrentHeight, SignedExtension, BlockNumberToHash, Lookup, Checkable, Extrinsic, SaturatedConversion diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 3a5bf8af9f4bf..76d37a0580a3a 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -19,12 +19,16 @@ use serde::{Serialize, Serializer, Deserialize, de::Error as DeError, Deserializer}; use std::{fmt::Debug, ops::Deref, fmt}; use crate::codec::{Codec, Encode, Decode}; -use crate::traits::{self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, TypedKey, DispatchError, DispatchResult}; -use crate::{generic, KeyTypeId, transaction_validity::ValidTransaction}; +use crate::traits::{ + self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, TypedKey, DispatchError, DispatchResult, + ValidateUnsigned +}; +use crate::{generic, KeyTypeId}; use crate::weights::{Weighable, Weight}; pub use substrate_primitives::H256; use substrate_primitives::U256; use substrate_primitives::ed25519::{Public as AuthorityId}; +use crate::transaction_validity::TransactionValidity; /// Authority Id #[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug)] @@ -199,7 +203,7 @@ impl<'a, Xt> Deserialize<'a> for Block where Block: Decode { /// /// If sender is some then the transaction is signed otherwise it is unsigned. #[derive(PartialEq, Eq, Clone, Encode, Decode)] -pub struct TestXt(pub Option, pub u64, pub Call); +pub struct TestXt(pub Option, u64, pub Call); impl Serialize for TestXt where TestXt: Encode { @@ -227,19 +231,20 @@ impl Applyable for TestXt where Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug, { type AccountId = u64; + type Call = Call; fn sender(&self) -> Option<&u64> { self.0.as_ref() } /// Checks to see if this is a valid *transaction*. It returns information on it if so. - fn validate(&self, - weight: crate::weights::Weight - ) -> Result { - Ok(Default::default()) + fn validate>(&self, + _weight: crate::weights::Weight + ) -> TransactionValidity { + TransactionValidity::Valid(Default::default()) } /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. fn dispatch(self, - weight: crate::weights::Weight + _weight: crate::weights::Weight ) -> Result { Ok(Ok(())) } diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index d3c5afa68de59..ccd9c06ea33ec 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -810,24 +810,31 @@ pub trait Dispatchable { pub trait SignedExtension: Codec + MaybeDebug + Sync + Send + Clone + Eq + PartialEq { + /// The type which encodes the sender identity. type AccountId; + /// Validate a signed transaction for the transaction queue. fn validate( &self, - who: &Self::AccountId, + _who: &Self::AccountId, _weight: crate::weights::Weight, ) -> Result { Ok(Default::default()) } + /// Do any pre-flight stuff for a signed transaction. fn pre_dispatch( self, who: &Self::AccountId, weight: crate::weights::Weight, ) -> Result<(), DispatchError> { self.validate(who, weight).map(|_| ()) } + /// Validate an unsigned transaction for the transaction queue. Normally the default + /// implementation is fine since `ValidateUnsigned` is a better way of recognising and + /// validating unsigned transactions. fn validate_unsigned( _weight: crate::weights::Weight, ) -> Result { Ok(Default::default()) } + /// Do any pre-flight stuff for a unsigned transaction. fn pre_dispatch_unsigned( weight: crate::weights::Weight, ) -> Result<(), DispatchError> { Self::validate_unsigned(weight).map(|_| ()) } diff --git a/core/sr-primitives/src/transaction_validity.rs b/core/sr-primitives/src/transaction_validity.rs index d2e3b27bcab11..66e66c0042db9 100644 --- a/core/sr-primitives/src/transaction_validity.rs +++ b/core/sr-primitives/src/transaction_validity.rs @@ -18,7 +18,6 @@ use rstd::prelude::*; use crate::codec::{Encode, Decode}; -use crate::transaction_validity::TransactionValidity::Valid; use crate::traits::DispatchError; /// Priority for a transaction. Additive. Higher is better. @@ -99,6 +98,9 @@ impl Default for ValidTransaction { } impl ValidTransaction { + /// Combine two instances into one, as a best effort. This will take the superset of each of the + /// `provides` and `requires` tags, it will sum the priorities, take the minimum longevity and + /// the logic *And* of the propagate flags. pub fn combine_with(mut self, mut other: ValidTransaction) -> Self { ValidTransaction { priority: self.priority + other.priority, diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 16b7bcc3a185d..d894b589dc1d1 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -154,15 +154,15 @@ use rstd::{cmp, result, mem}; use parity_codec::{Codec, Encode, Decode}; use srml_support::{StorageValue, StorageMap, Parameter, decl_event, decl_storage, decl_module}; use srml_support::traits::{ - UpdateBalanceOutcome, Currency, OnFreeBalanceZero, MakePayment, OnUnbalanced, + UpdateBalanceOutcome, Currency, OnFreeBalanceZero, OnUnbalanced, WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, Imbalance, SignedImbalance, ReservableCurrency }; use srml_support::{dispatch::Result, traits::Get}; -use primitives::traits::{ +use primitives::{transaction_validity::TransactionPriority, traits::{ Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, - MaybeSerializeDebug, Saturating, Bounded -}; + MaybeSerializeDebug, Saturating, Bounded, SignedExtension +}}; use system::{IsDeadAccount, OnNewAccount, ensure_signed, ensure_root}; mod mock; @@ -1133,10 +1133,10 @@ where /// Require the transactor pay for themselves and maybe include a tip to gain additional priority /// in the queue. #[derive(Encode, Decode, Clone, Eq, PartialEq)] -pub struct TakeFees(T::Balance); +pub struct TakeFees, I: Instance>(T::Balance); #[cfg(feature = "std")] -impl rstd::fmt::Debug for TakeFees { +impl, I: Instance> rstd::fmt::Debug for TakeFees { fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { self.0.fmt(f) } @@ -1144,11 +1144,11 @@ impl rstd::fmt::Debug for TakeFees { // TODO: wire this and CheckNonce in to the runtime. -use primitives::traits::DispatchError; +use primitives::traits::{DispatchError, SaturatedConversion}; use primitives::transaction_validity::ValidTransaction; use primitives::weights::Weight; -impl SignedExtension for TakeFees { +impl, I: Instance + Clone + Eq> SignedExtension for TakeFees { type AccountId = T::AccountId; fn validate( @@ -1158,22 +1158,19 @@ impl SignedExtension for TakeFees { ) -> rstd::result::Result { let fee_x = T::Balance::from(weight as u32); // should be weight_to_fee(weight) - let transaction_fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * fee_x; - let imbalance = Self::withdraw( - transactor, - transaction_fee, + let fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * fee_x; + let fee = fee + self.0.clone(); + let imbalance = >::withdraw( + who, + fee.clone(), WithdrawReason::TransactionPayment, ExistenceRequirement::KeepAlive ).map_err(|_| DispatchError::Payment)?; T::TransactionPayment::on_unbalanced(imbalance); - Ok(ValidTransaction { - priority: _weight as TransactionPriority + self.0.clone() as TransactionPriority, // TODO: overflow?? - requires: vec![], - provides: vec![], - longevity: TransactionLongevity::max_value(), - propagate: true, - }) + let mut r = ValidTransaction::default(); + r.priority = fee.saturated_into::(); + Ok(r) } } diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 443ba947b3e44..41492b2e26ec8 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -85,7 +85,7 @@ use srml_support::{Dispatchable, traits::MakePayment}; use parity_codec::{Codec, Encode}; use system::{extrinsics_root, DigestOf}; use primitives::{ApplyOutcome, ApplyError}; -use primitives::transaction_validity::{TransactionValidity, TransactionPriority, TransactionLongevity}; +use primitives::transaction_validity::TransactionValidity; use primitives::weights::Weighable; mod internal { @@ -144,7 +144,7 @@ impl< > ExecuteBlock for Executive where Block::Extrinsic: Checkable + Codec, - CheckedOf: Applyable + Weighable, + CheckedOf: Applyable + Weighable, CallOf: Dispatchable, OriginOf: From>, UnsignedValidator: ValidateUnsigned>, @@ -164,7 +164,7 @@ impl< > Executive where Block::Extrinsic: Checkable + Codec, - CheckedOf: Applyable + Weighable, + CheckedOf: Applyable + Weighable, CallOf: Dispatchable, OriginOf: From>, UnsignedValidator: ValidateUnsigned>, @@ -296,7 +296,7 @@ where // AUDIT: Under no circumstances may this function panic from here onwards. // Decode parameters and dispatch - let (f, s) = Applyable::dispatch(xt, weight) + let r = Applyable::dispatch(xt, weight) .map_err(internal::ApplyError::from)?; >::note_applied_extrinsic(&r, encoded_len as u32); @@ -336,9 +336,7 @@ where pub fn validate_transaction(uxt: Block::Extrinsic) -> TransactionValidity { // Note errors > 0 are from ApplyError const UNKNOWN_ERROR: i8 = -127; - const MISSING_SENDER: i8 = -20; const INVALID_INDEX: i8 = -10; - const BAD_DISPATCH: i8 = -15; let encoded_len = uxt.encode().len(); @@ -353,7 +351,9 @@ where Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR), }; - xt.validate::() + let weight = xt.weight(encoded_len);† + + xt.validate::(weight) } /// Start an offchain worker and generate extrinsics. diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index 86071a37a2720..f6c09190ebad6 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -91,19 +91,6 @@ pub enum UpdateBalanceOutcome { AccountKilled, } -/// Simple trait designed for hooking into a transaction payment. -/// -/// It operates over a single generic `AccountId` type. -pub trait MakePayment { - /// Make transaction payment from `who` for an extrinsic of encoded length - /// `encoded_len` bytes. Return `Ok` iff the payment was successful. - fn make_payment(who: &AccountId, encoded_len: usize) -> Result<(), &'static str>; -} - -impl MakePayment for () { - fn make_payment(_: &T, _: usize) -> Result<(), &'static str> { Ok(()) } -} - /// A trait for finding the author of a block header based on the `PreRuntime` digests contained /// within it. pub trait FindAuthor { diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 8961c98a717ad..d60524dc42c8b 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -89,7 +89,7 @@ use primitives::{ use substrate_primitives::storage::well_known_keys; use srml_support::{ storage, decl_module, decl_event, decl_storage, StorageDoubleMap, StorageValue, - StorageMap, Parameter, for_each_tuple, traits::{Contains, Get}, Dispatchable + StorageMap, Parameter, for_each_tuple, traits::{Contains, Get} }; use safe_mix::TripletMix; use parity_codec::{Encode, Decode}; From b7646ec9b0a0c3f40ef2d35391b31f0ce57c30e4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 11 Jul 2019 23:16:18 +0200 Subject: [PATCH 04/33] Runtiem builds :) --- node/runtime/src/lib.rs | 8 +++++--- srml/balances/src/lib.rs | 4 +--- srml/executive/src/lib.rs | 16 +++++++--------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 0b66424576181..4daab741406b4 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -435,12 +435,14 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; +/// The SignedExtension to the basic transaction logic. +type SignedExtra = (system::CheckNonce, balances::TakeFees); /// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = generic::CheckedExtrinsic; +pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. -pub type Executive = executive::Executive, Balances, Runtime, AllModules>; +pub type Executive = executive::Executive, Runtime, AllModules>; impl_runtime_apis! { impl client_api::Core for Runtime { diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index d894b589dc1d1..1e5ec3afc7a23 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -1133,7 +1133,7 @@ where /// Require the transactor pay for themselves and maybe include a tip to gain additional priority /// in the queue. #[derive(Encode, Decode, Clone, Eq, PartialEq)] -pub struct TakeFees, I: Instance>(T::Balance); +pub struct TakeFees, I: Instance = DefaultInstance>(T::Balance); #[cfg(feature = "std")] impl, I: Instance> rstd::fmt::Debug for TakeFees { @@ -1142,8 +1142,6 @@ impl, I: Instance> rstd::fmt::Debug for TakeFees { } } -// TODO: wire this and CheckNonce in to the runtime. - use primitives::traits::{DispatchError, SaturatedConversion}; use primitives::transaction_validity::ValidTransaction; use primitives::weights::Weight; diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 41492b2e26ec8..6c83f92850ab6 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -81,7 +81,7 @@ use primitives::{generic::Digest, traits::{ self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalize, OnInitialize, NumberFor, Block as BlockT, OffchainWorker, ValidateUnsigned }}; -use srml_support::{Dispatchable, traits::MakePayment}; +use srml_support::Dispatchable; use parity_codec::{Codec, Encode}; use system::{extrinsics_root, DigestOf}; use primitives::{ApplyOutcome, ApplyError}; @@ -130,18 +130,17 @@ pub type CheckedOf = >::Checked; pub type CallOf = as Applyable>::Call; pub type OriginOf = as Dispatchable>::Origin; -pub struct Executive( - PhantomData<(System, Block, Context, Payment, UnsignedValidator, AllModules)> +pub struct Executive( + PhantomData<(System, Block, Context, UnsignedValidator, AllModules)> ); impl< System: system::Trait, Block: traits::Block, Context: Default, - Payment: MakePayment, UnsignedValidator, AllModules: OnInitialize + OnFinalize + OffchainWorker, -> ExecuteBlock for Executive +> ExecuteBlock for Executive where Block::Extrinsic: Checkable + Codec, CheckedOf: Applyable + Weighable, @@ -150,7 +149,7 @@ where UnsignedValidator: ValidateUnsigned>, { fn execute_block(block: Block) { - Executive::::execute_block(block); + Executive::::execute_block(block); } } @@ -158,10 +157,9 @@ impl< System: system::Trait, Block: traits::Block, Context: Default, - Payment: MakePayment, UnsignedValidator, AllModules: OnInitialize + OnFinalize + OffchainWorker, -> Executive +> Executive where Block::Extrinsic: Checkable + Codec, CheckedOf: Applyable + Weighable, @@ -351,7 +349,7 @@ where Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR), }; - let weight = xt.weight(encoded_len);† + let weight = xt.weight(encoded_len); xt.validate::(weight) } From a871c9f4bc872d9abff4256408003bc5f09fd088 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sat, 13 Jul 2019 01:56:11 +0200 Subject: [PATCH 05/33] Substrate builds. --- Cargo.lock | 4 + .../src/generic/unchecked_extrinsic.rs | 98 +++++++++++++++---- core/sr-primitives/src/testing.rs | 42 +++++--- core/sr-primitives/src/traits.rs | 6 ++ core/test-runtime/src/lib.rs | 10 +- core/test-runtime/src/system.rs | 7 +- core/transaction-pool/graph/src/pool.rs | 28 +++--- core/transaction-pool/src/tests.rs | 6 +- node-template/runtime/src/lib.rs | 8 +- node/cli/Cargo.toml | 2 + node/cli/src/factory_impl.rs | 16 +-- node/cli/src/service.rs | 12 ++- node/executor/src/lib.rs | 76 +++++++------- node/runtime/src/lib.rs | 2 +- srml/balances/src/lib.rs | 12 ++- srml/balances/src/tests.rs | 12 +-- srml/executive/src/lib.rs | 58 +++++------ srml/support/test/tests/instance.rs | 2 +- srml/support/test/tests/issue2219.rs | 2 +- srml/system/src/lib.rs | 8 ++ subkey/Cargo.toml | 2 + subkey/src/main.rs | 20 ++-- 22 files changed, 270 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f389625eae788..d925435e138c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2198,9 +2198,11 @@ dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", + "srml-balances 2.0.0", "srml-contracts 2.0.0", "srml-finality-tracker 2.0.0", "srml-indices 2.0.0", + "srml-system 2.0.0", "srml-timestamp 2.0.0", "structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-basic-authorship 2.0.0", @@ -4055,6 +4057,8 @@ dependencies = [ "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "schnorrkel 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", + "srml-balances 2.0.0", + "srml-system 2.0.0", "substrate-bip39 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-primitives 2.0.0", "tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index a500283b7a947..12e96ba2f1832 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -209,7 +209,7 @@ mod tests { use super::*; use runtime_io::blake2_256; use crate::codec::{Encode, Decode}; - use crate::traits::{SignedExtension, DispatchError}; + use crate::traits::SignedExtension; use serde::{Serialize, Deserialize}; struct TestContext; @@ -237,89 +237,151 @@ mod tests { } } - const DUMMY_ACCOUNTID: u64 = 0; + type TestAccountId = u64; + type TestCall = Vec; + const TEST_ACCOUNT: TestAccountId = 0; + + // NOTE: this is demonstration. One can simply use `()` for testing. #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Ord, PartialOrd)] struct TestExtra; impl SignedExtension for TestExtra { type AccountId = u64; } - type Ex = UncheckedExtrinsic, TestSig, TestExtra>; - type CEx = CheckedExtrinsic, TestExtra>; + + type Ex = UncheckedExtrinsic; + type CEx = CheckedExtrinsic; #[test] fn unsigned_codec_should_work() { - let ux = Ex::new_unsigned(vec![0u8;0]); + let ux = Ex::new_unsigned(vec![0u8; 0]); let encoded = ux.encode(); assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); } #[test] fn signed_codec_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::immortal(), 0u64).encode()), Era::immortal(), TestExtra); + let ux = Ex::new_signed( + vec![0u8; 0], + TEST_ACCOUNT, + TestSig(TEST_ACCOUNT, (TEST_ACCOUNT, vec![0u8; 0], Era::immortal(), 0u64).encode()), + Era::immortal(), + TestExtra + ); let encoded = ux.encode(); assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); } #[test] fn large_signed_codec_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8; 257], Era::immortal(), 0u64).using_encoded(blake2_256)[..].to_owned()), Era::immortal(), TestExtra); + let ux = Ex::new_signed( + vec![0u8; 0], + TEST_ACCOUNT, + TestSig(TEST_ACCOUNT, (TEST_ACCOUNT, vec![0u8; 257], Era::immortal(), 0u64) + .using_encoded(blake2_256)[..].to_owned()), + Era::immortal(), + TestExtra + ); let encoded = ux.encode(); assert_eq!(Ex::decode(&mut &encoded[..]), Some(ux)); } #[test] fn unsigned_check_should_work() { - let ux = Ex::new_unsigned(vec![0u8;0]); + let ux = Ex::new_unsigned(vec![0u8; 0]); assert!(!ux.is_signed().unwrap_or(false)); assert!(>::check(ux, &TestContext).is_ok()); } #[test] fn badly_signed_check_should_fail() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, vec![0u8]), Era::immortal(), TestExtra); + let ux = Ex::new_signed( + vec![0u8; 0], + TEST_ACCOUNT, + TestSig(TEST_ACCOUNT, vec![0u8; 0]), + Era::immortal(), + TestExtra + ); assert!(ux.is_signed().unwrap_or(false)); assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); } #[test] fn immortal_signed_check_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (Compact::from(DUMMY_ACCOUNTID), vec![0u8;0], Era::immortal(), 0u64).encode()), Era::immortal(), TestExtra); + let ux = Ex::new_signed( + vec![0u8; 0], + TEST_ACCOUNT, + TestSig(TEST_ACCOUNT, (vec![0u8; 0], Era::immortal(), 0u64, TestExtra).encode()), + Era::immortal(), + TestExtra + ); assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0, TestExtra)), function: vec![0u8;0] })); + assert_eq!( + >::check(ux, &TestContext), + Ok(CEx { signed: Some((TEST_ACCOUNT, TestExtra)), function: vec![0u8; 0] }) + ); } #[test] fn mortal_signed_check_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (Compact::from(DUMMY_ACCOUNTID), vec![0u8;0], Era::mortal(32, 42), 42u64).encode()), Era::mortal(32, 42), TestExtra); + let ux = Ex::new_signed( + vec![0u8; 0], + TEST_ACCOUNT, + TestSig(TEST_ACCOUNT, (vec![0u8; 0], Era::mortal(32, 42), 42u64, TestExtra).encode()), + Era::mortal(32, 42), + TestExtra + ); assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0, TestExtra)), function: vec![0u8;0] })); + assert_eq!( + >::check(ux, &TestContext), + Ok(CEx { signed: Some((TEST_ACCOUNT, TestExtra)), function: vec![0u8; 0] }) + ); } #[test] fn later_mortal_signed_check_should_work() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (Compact::from(DUMMY_ACCOUNTID), vec![0u8;0], Era::mortal(32, 11), 11u64).encode()), Era::mortal(32, 11), TestExtra); + let ux = Ex::new_signed( + vec![0u8; 0], + TEST_ACCOUNT, + TestSig(TEST_ACCOUNT, (vec![0u8; 0], Era::mortal(32, 11), 11u64, TestExtra).encode()), + Era::mortal(32, 11), + TestExtra + ); assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Ok(CEx { signed: Some((DUMMY_ACCOUNTID, 0, TestExtra)), function: vec![0u8;0] })); + assert_eq!( + >::check(ux, &TestContext), + Ok(CEx { signed: Some((TEST_ACCOUNT, TestExtra)), function: vec![0u8; 0] })); } #[test] fn too_late_mortal_signed_check_should_fail() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::mortal(32, 10), 10u64).encode()), Era::mortal(32, 10), TestExtra); + let ux = Ex::new_signed( + vec![0u8; 0], + TEST_ACCOUNT, + TestSig(TEST_ACCOUNT, (TEST_ACCOUNT, vec![0u8; 0], Era::mortal(32, 10), 10u64).encode()), + Era::mortal(32, 10), + TestExtra + ); assert!(ux.is_signed().unwrap_or(false)); assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); } #[test] fn too_early_mortal_signed_check_should_fail() { - let ux = Ex::new_signed(0, vec![0u8;0], DUMMY_ACCOUNTID, TestSig(DUMMY_ACCOUNTID, (DUMMY_ACCOUNTID, vec![0u8;0], Era::mortal(32, 43), 43u64).encode()), Era::mortal(32, 43), TestExtra); + let ux = Ex::new_signed( + vec![0u8; 0], + TEST_ACCOUNT, + TestSig(TEST_ACCOUNT, (TEST_ACCOUNT, vec![0u8; 0], Era::mortal(32, 43), 43u64).encode()), + Era::mortal(32, 43), + TestExtra + ); assert!(ux.is_signed().unwrap_or(false)); assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); } #[test] fn encoding_matches_vec() { - let ex = Ex::new_unsigned(vec![0u8;0]); + let ex = Ex::new_unsigned(vec![0u8; 0]); let encoded = ex.encode(); let decoded = Ex::decode(&mut encoded.as_slice()).unwrap(); assert_eq!(decoded, ex); diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 76d37a0580a3a..a101c3db94212 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -21,7 +21,7 @@ use std::{fmt::Debug, ops::Deref, fmt}; use crate::codec::{Codec, Encode, Decode}; use crate::traits::{ self, Checkable, Applyable, BlakeTwo256, OpaqueKeys, TypedKey, DispatchError, DispatchResult, - ValidateUnsigned + ValidateUnsigned, SignedExtension, Dispatchable, }; use crate::{generic, KeyTypeId}; use crate::weights::{Weighable, Weight}; @@ -198,45 +198,49 @@ impl<'a, Xt> Deserialize<'a> for Block where Block: Decode { } } -/// Test transaction, tuple of (sender, index, call) +/// Test transaction, tuple of (sender, call, signed_extra) /// with index only used if sender is some. /// /// If sender is some then the transaction is signed otherwise it is unsigned. #[derive(PartialEq, Eq, Clone, Encode, Decode)] -pub struct TestXt(pub Option, u64, pub Call); +pub struct TestXt(pub Option, pub Call, pub Extra); -impl Serialize for TestXt where TestXt: Encode -{ +impl Serialize for TestXt where TestXt: Encode { fn serialize(&self, seq: S) -> Result where S: Serializer { self.using_encoded(|bytes| seq.serialize_bytes(bytes)) } } -impl Debug for TestXt { +impl Debug for TestXt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TestXt({:?}, {:?})", self.0, self.1) + write!(f, "TestXt({:?}, ...)", self.0) } } -impl Checkable for TestXt { +impl Checkable for TestXt { type Checked = Self; fn check(self, _: &Context) -> Result { Ok(self) } } -impl traits::Extrinsic for TestXt { + +impl traits::Extrinsic for TestXt { fn is_signed(&self) -> Option { Some(self.0.is_some()) } } -impl Applyable for TestXt where - Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug, + +impl Applyable for TestXt where + Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Dispatchable, + Extra: SignedExtension, + Origin: From> { type AccountId = u64; type Call = Call; + fn sender(&self) -> Option<&u64> { self.0.as_ref() } /// Checks to see if this is a valid *transaction*. It returns information on it if so. fn validate>(&self, - _weight: crate::weights::Weight + _weight: Weight ) -> TransactionValidity { TransactionValidity::Valid(Default::default()) } @@ -244,12 +248,20 @@ impl Applyable for TestXt where /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. fn dispatch(self, - _weight: crate::weights::Weight + weight: Weight ) -> Result { - Ok(Ok(())) + let maybe_who = if let Some(who) = self.0 { + Extra::pre_dispatch(self.2, &who, weight)?; + Some(who) + } else { + Extra::pre_dispatch_unsigned(weight)?; + None + }; + Ok(self.1.dispatch(maybe_who.into())) } } -impl Weighable for TestXt { + +impl Weighable for TestXt { fn weight(&self, len: usize) -> Weight { // for testing: weight == size. len as Weight diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index ccd9c06ea33ec..91667ecce4ae7 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -880,6 +880,12 @@ impl< } } +/// To be used only for testing. +#[cfg(feature = "std")] +impl SignedExtension for () { + type AccountId = u64; +} + /// An "executable" piece of information, used by the standard Substrate Executive in order to /// enact a piece of extrinsic information by marshalling and dispatching to a named function /// call. diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index b72d2af62a9ac..196336a2e91e8 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -36,7 +36,7 @@ use substrate_client::{ use runtime_primitives::{ ApplyResult, create_runtime_str, - transaction_validity::TransactionValidity, + transaction_validity::{TransactionValidity, ValidTransaction}, traits::{ BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, GetNodeBlockType, GetRuntimeBlockType, Verify @@ -371,13 +371,13 @@ cfg_if! { impl client_api::TaggedTransactionQueue for Runtime { fn validate_transaction(utx: ::Extrinsic) -> TransactionValidity { if let Extrinsic::IncludeData(data) = utx { - return TransactionValidity::Valid { + return TransactionValidity::Valid(ValidTransaction { priority: data.len() as u64, requires: vec![], provides: vec![data], longevity: 1, propagate: false, - }; + }); } system::validate_transaction(utx) @@ -512,13 +512,13 @@ cfg_if! { impl client_api::TaggedTransactionQueue for Runtime { fn validate_transaction(utx: ::Extrinsic) -> TransactionValidity { if let Extrinsic::IncludeData(data) = utx { - return TransactionValidity::Valid { + return TransactionValidity::Valid(ValidTransaction{ priority: data.len() as u64, requires: vec![], provides: vec![data], longevity: 1, propagate: false, - }; + }); } system::validate_transaction(utx) diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index f4433e391c7df..01b032f59925a 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -23,7 +23,8 @@ use runtime_support::storage::{self, StorageValue, StorageMap}; use runtime_support::storage_items; use runtime_primitives::traits::{Hash as HashT, BlakeTwo256, Header as _}; use runtime_primitives::generic; -use runtime_primitives::{ApplyError, ApplyOutcome, ApplyResult, transaction_validity::TransactionValidity}; +use runtime_primitives::{ApplyError, ApplyOutcome, ApplyResult}; +use runtime_primitives::transaction_validity::{TransactionValidity, ValidTransaction}; use parity_codec::{KeyedVec, Encode}; use super::{ AccountId, BlockNumber, Extrinsic, Transfer, H256 as Hash, Block, Header, Digest, AuthorityId @@ -175,13 +176,13 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity { p }; - TransactionValidity::Valid { + TransactionValidity::Valid(ValidTransaction { priority: tx.amount, requires, provides, longevity: 64, propagate: true, - } + }) } /// Execute a transaction outside of the block execution function. diff --git a/core/transaction-pool/graph/src/pool.rs b/core/transaction-pool/graph/src/pool.rs index 4498598aee9ca..8f76a17ed9809 100644 --- a/core/transaction-pool/graph/src/pool.rs +++ b/core/transaction-pool/graph/src/pool.rs @@ -129,18 +129,19 @@ impl Pool { } match self.api.validate_transaction(at, xt.clone())? { - TransactionValidity::Valid { priority, requires, provides, longevity, propagate } => { + TransactionValidity::Valid(validity) => { Ok(base::Transaction { data: xt, - bytes, + bytes + , hash, - priority, - requires, - provides, - propagate, + priority: validity.priority, + requires: validity.requires, + provides: validity.provides, + propagate: validity.propagate, valid_till: block_number .saturated_into::() - .saturating_add(longevity), + .saturating_add(validity.longevity), }) }, TransactionValidity::Invalid(e) => { @@ -233,7 +234,7 @@ impl Pool { for (extrinsic, existing_in_pool) in all { match *existing_in_pool { - // reuse the tags for extrinsis that were found in the pool + // reuse the tags for extrinsics that were found in the pool Some(ref transaction) => { tags.extend(transaction.provides.iter().cloned()); }, @@ -242,8 +243,8 @@ impl Pool { None => { let validity = self.api.validate_transaction(parent, extrinsic.clone()); match validity { - Ok(TransactionValidity::Valid { mut provides, .. }) => { - tags.append(&mut provides); + Ok(TransactionValidity::Valid(mut validity)) => { + tags.append(&mut validity.provides); }, // silently ignore invalid extrinsics, // cause they might just be inherent @@ -306,7 +307,7 @@ impl Pool { let hashes = status.pruned.iter().map(|tx| tx.hash.clone()).collect::>(); let results = self.submit_at(at, status.pruned.into_iter().map(|tx| tx.data.clone()))?; - // Collect the hashes of transactions that now became invalid (meaning that they are succesfully pruned). + // Collect the hashes of transactions that now became invalid (meaning that they are successfully pruned). let hashes = results.into_iter().enumerate().filter_map(|(idx, r)| match r.map_err(error::IntoPoolError::into_pool_error) { Err(Ok(error::Error::InvalidTransaction(_))) => Some(hashes[idx].clone()), _ => None, @@ -451,6 +452,7 @@ fn fire_events( #[cfg(test)] mod tests { use super::*; + use sr_primitives::transaction_validity::ValidTransaction; use futures::Stream; use parity_codec::Encode; use test_runtime::{Block, Extrinsic, Transfer, H256, AccountId}; @@ -486,13 +488,13 @@ mod tests { if nonce < block_number { Ok(TransactionValidity::Invalid(0)) } else { - Ok(TransactionValidity::Valid { + Ok(TransactionValidity::Valid(ValidTransaction { priority: 4, requires: if nonce > block_number { vec![vec![nonce as u8 - 1]] } else { vec![] }, provides: vec![vec![nonce as u8]], longevity: 3, propagate: true, - }) + })) } } diff --git a/core/transaction-pool/src/tests.rs b/core/transaction-pool/src/tests.rs index a1ee4a50df332..7fb94936d2b62 100644 --- a/core/transaction-pool/src/tests.rs +++ b/core/transaction-pool/src/tests.rs @@ -23,7 +23,7 @@ use test_client::{runtime::{AccountId, Block, Hash, Index, Extrinsic, Transfer}, use sr_primitives::{ generic::{self, BlockId}, traits::{Hash as HashT, BlakeTwo256}, - transaction_validity::TransactionValidity, + transaction_validity::{TransactionValidity, ValidTransaction}, }; struct TestApi; @@ -48,13 +48,13 @@ impl txpool::ChainApi for TestApi { }; let provides = vec![vec![uxt.transfer().nonce as u8]]; - Ok(TransactionValidity::Valid { + Ok(TransactionValidity::Valid(ValidTransaction { priority: 1, requires, provides, longevity: 64, propagate: true, - }) + })) } fn block_id_to_number(&self, at: &BlockId) -> error::Result>> { diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 8879b163ff763..1dcc65d00b5e4 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -227,12 +227,14 @@ pub type Header = generic::Header; pub type Block = generic::Block; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; +/// The SignedExtension to the basic transaction logic. +pub type SignedExtra = (system::CheckNonce, balances::TakeFees); /// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = generic::CheckedExtrinsic; +pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. -pub type Executive = executive::Executive; +pub type Executive = executive::Executive; // Implement our runtime API endpoints. This is just a bunch of proxying. impl_runtime_apis! { diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index ad49cbe36cd90..17efcc400f35b 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -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" } diff --git a/node/cli/src/factory_impl.rs b/node/cli/src/factory_impl.rs index 0d94610362fdc..40f4f602ce712 100644 --- a/node/cli/src/factory_impl.rs +++ b/node/cli/src/factory_impl.rs @@ -130,14 +130,14 @@ impl RuntimeAdapter for FactoryState { ) -> ::Extrinsic { let index = self.extract_index(&sender, prior_block_hash); let phase = self.extract_phase(*prior_block_hash); + let check_nonce = system::CheckNonce::from(index); + let take_fees = balances::TakeFees::from(0); sign::(CheckedExtrinsic { - signed: Some((sender.clone(), index)), + signed: Some((sender.clone(), (check_nonce, take_fees))), function: Call::Balances( BalancesCall::transfer( - indices::address::Address::Id( - destination.clone().into() - ), + indices::address::Address::Id(destination.clone().into()), (*amount).into() ) ) @@ -233,9 +233,9 @@ fn sign( phase: u64, ) -> ::Extrinsic { let s = match xt.signed { - Some((signed, index)) => { + Some((signed, extra)) => { let era = Era::mortal(256, phase); - let payload = (index.into(), xt.function, era, prior_block_hash); + let payload = (xt.function, era, prior_block_hash, extra.clone()); let signature = payload.using_encoded(|b| { if b.len() > 256 { key.sign(&sr_io::blake2_256(b)) @@ -244,8 +244,8 @@ fn sign( } }).into(); UncheckedExtrinsic { - signature: Some((indices::address::Address::Id(signed), signature, payload.0, era)), - function: payload.1, + signature: Some((indices::address::Address::Id(signed), signature, era, extra)), + function: payload.0, } } None => UncheckedExtrinsic { diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 3dcaf85d6a80b..ce054f9f798a2 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -219,7 +219,7 @@ mod tests { use consensus_common::{Environment, Proposer, ImportBlock, BlockOrigin, ForkChoiceStrategy}; use node_primitives::DigestItem; use node_runtime::{BalancesCall, Call, CENTS, 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,18 +358,22 @@ mod tests { let function = Call::Balances(BalancesCall::transfer(to.into(), amount)); let era = Era::immortal(); - let raw_payload = (Compact(index), function, era, genesis_hash); + let check_nonce = system::CheckNonce::from(index); + let take_fees = balances::TakeFees::from(0); + let extra = (check_nonce, take_fees); + + let raw_payload = (function, era, genesis_hash, extra.clone()); 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 = Decode::decode(&mut xt.as_slice()).unwrap(); diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index ae306d33e5bd3..87c4d4a88e4bc 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -40,13 +40,13 @@ 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 {balances, contracts, indices, staking, system, timestamp}; @@ -55,8 +55,8 @@ mod tests { 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, }; use wabt; use primitives::map; @@ -78,10 +78,16 @@ mod tests { const GENESIS_HASH: [u8; 32] = [69u8; 32]; - const TX_FEE: u128 = 3 * CENTS + 460 * MILLICENTS; - type TestExternalities = CoreTestExternalities; + fn transfer_fee(bytes: Balance) -> Balance { + >::get() + >::get() * bytes + } + + fn creation_fee() -> Balance { + >::get() + } + fn alice() -> AccountId { AccountKeyring::Alice.into() } @@ -108,9 +114,9 @@ mod tests { fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { match xt.signed { - Some((signed, index)) => { + Some((signed, extra)) => { let era = Era::mortal(256, 0); - let payload = (index.into(), xt.function, era, GENESIS_HASH); + let payload = (xt.function, era, GENESIS_HASH, extra.clone()); let key = AccountKeyring::from_public(&signed).unwrap(); let signature = payload.using_encoded(|b| { if b.len() > 256 { @@ -120,8 +126,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, era, extra)), + function: payload.0, } } None => UncheckedExtrinsic { @@ -131,9 +137,13 @@ mod tests { } } + fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra { + (system::CheckNonce::from(nonce), 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::(bob().into(), 69 * DOLLARS)), }) } @@ -249,7 +259,7 @@ mod tests { assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(169) - creation_fee()); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -285,7 +295,7 @@ mod tests { assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(169) - creation_fee()); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -430,7 +440,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)), }, ] @@ -452,7 +462,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)), }, ] @@ -467,11 +477,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)), } ] @@ -496,7 +506,7 @@ mod tests { function: Call::Timestamp(timestamp::Call::set(42)), }, CheckedExtrinsic { - signed: Some((alice(), 0)), + signed: Some((alice(), signed_extra(0, 0))), function: Call::System(system::Call::remark(vec![0; 120000])), } ] @@ -518,9 +528,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 - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(169) - creation_fee()); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); let events = vec![ EventRecord { @@ -556,11 +564,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); - // 100 + 69 + 10 = 179 - assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * TX_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(169) - 2 * creation_fee()); + assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - transfer_fee(169) - creation_fee()); let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), @@ -615,19 +621,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 - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(169) - 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); - // 100 + 69 + 10 = 179 - assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&alice()), 32 * DOLLARS - 2 * transfer_fee(169) - 2 * creation_fee()); + assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * transfer_fee(169) - creation_fee()); }); } @@ -745,19 +747,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::(10_000, transfer_code) ), }, CheckedExtrinsic { - signed: Some((charlie(), 1)), + signed: Some((charlie(), signed_extra(1, 0))), function: Call::Contracts( contracts::Call::create::(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::( indices::address::Address::Id(addr.clone()), @@ -873,7 +875,7 @@ mod tests { assert_eq!(r, Ok(ApplyOutcome::Success)); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * TX_FEE); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(169) - creation_fee()); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 4daab741406b4..71784959e5ef8 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -436,7 +436,7 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. -type SignedExtra = (system::CheckNonce, balances::TakeFees); +pub type SignedExtra = (system::CheckNonce, balances::TakeFees); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Extrinsic type that has already been checked. diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 1e5ec3afc7a23..8c04e6f7d29d5 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -1135,6 +1135,14 @@ where #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct TakeFees, I: Instance = DefaultInstance>(T::Balance); +#[cfg(feature = "std")] +impl, I: Instance> TakeFees { + /// utility constructor. Used only in client/factory code. + pub fn from(fee: T::Balance) -> Self { + Self(fee) + } +} + #[cfg(feature = "std")] impl, I: Instance> rstd::fmt::Debug for TakeFees { fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { @@ -1154,8 +1162,8 @@ impl, I: Instance + Clone + Eq> SignedExtension for TakeFees { who: &Self::AccountId, weight: Weight, ) -> rstd::result::Result { - let fee_x = T::Balance::from(weight as u32); - // should be weight_to_fee(weight) + let fee_x = T::Balance::from(weight); + // TODO TODO: should be weight_to_fee(weight) let fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * fee_x; let fee = fee + self.0.clone(); let imbalance = >::withdraw( diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 0a5a4b5bb70a6..10e6f94693682 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -24,7 +24,7 @@ use runtime_io::with_externalities; use srml_support::{ assert_noop, assert_ok, assert_err, traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons, - Currency, MakePayment, ReservableCurrency} + Currency, ReservableCurrency} }; const ID_1: LockIdentifier = *b"1 "; @@ -118,7 +118,8 @@ fn lock_reasons_should_work() { "account liquidity restrictions prevent withdrawal" ); assert_ok!(>::reserve(&1, 1)); - assert_ok!(>::make_payment(&1, 1)); + // NOTE: this causes a fee payment. + assert!( as SignedExtension>::validate(&TakeFees::from(1), &1, 1).is_ok()); Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Reserve.into()); assert_ok!(>::transfer(&1, &2, 1)); @@ -126,15 +127,12 @@ fn lock_reasons_should_work() { >::reserve(&1, 1), "account liquidity restrictions prevent withdrawal" ); - assert_ok!(>::make_payment(&1, 1)); + assert!( as SignedExtension>::validate(&TakeFees::from(1), &1, 1).is_ok()); Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::TransactionPayment.into()); assert_ok!(>::transfer(&1, &2, 1)); assert_ok!(>::reserve(&1, 1)); - assert_noop!( - >::make_payment(&1, 1), - "account liquidity restrictions prevent withdrawal" - ); + assert!( as SignedExtension>::validate(&TakeFees::from(1), &1, 1).is_err()); }); } diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 6c83f92850ab6..a389da6ac093c 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -429,27 +429,19 @@ mod tests { fn validate_unsigned(call: &Self::Call) -> TransactionValidity { match call { - Call::set_balance(_, _, _) => TransactionValidity::Valid { - priority: 0, - requires: vec![], - provides: vec![], - longevity: std::u64::MAX, - propagate: false, - }, + Call::set_balance(_, _, _) => TransactionValidity::Valid(Default::default()), _ => TransactionValidity::Invalid(0), } } } - type TestXt = primitives::testing::TestXt>; - type Executive = super::Executive< - Runtime, - Block, - system::ChainContext, - balances::Module, - Runtime, - () - >; + type SignedExtra = (system::CheckNonce, balances::TakeFees); + type TestXt = primitives::testing::TestXt, SignedExtra>; + type Executive = super::Executive, system::ChainContext, Runtime, ()>; + + fn extra(nonce: u64, fee: u64) -> SignedExtra { + (system::CheckNonce::from(nonce), balances::TakeFees::from(fee)) + } #[test] fn balance_transfer_dispatch_works() { @@ -458,7 +450,7 @@ mod tests { balances: vec![(1, 111)], vesting: vec![], }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); - let xt = primitives::testing::TestXt(Some(1), 0, Call::transfer(2, 69)); + let xt = primitives::testing::TestXt(Some(1), Call::transfer(2, 69), extra(0, 0)); let mut t = runtime_io::TestExternalities::::new_with_children(t); with_externalities(&mut t, || { Executive::initialize_block(&Header::new( @@ -468,7 +460,8 @@ mod tests { [69u8; 32].into(), Digest::default(), )); - Executive::apply_extrinsic(xt).unwrap(); + let r = Executive::apply_extrinsic(xt); + assert_eq!(r, Ok(ApplyOutcome::Success)); assert_eq!(>::total_balance(&1), 42 - 10); assert_eq!(>::total_balance(&2), 69); }); @@ -536,7 +529,8 @@ mod tests { #[test] fn bad_extrinsic_not_inserted() { let mut t = new_test_ext(); - let xt = primitives::testing::TestXt(Some(1), 42, Call::transfer(33, 69)); + // bad nonce check! + let xt = primitives::testing::TestXt(Some(1), Call::transfer(33, 69), extra(30, 0)); with_externalities(&mut t, || { Executive::initialize_block(&Header::new( 1, @@ -554,10 +548,11 @@ mod tests { fn block_weight_limit_enforced() { let run_test = |should_fail: bool| { let mut t = new_test_ext(); - let xt = primitives::testing::TestXt(Some(1), 0, Call::transfer(33, 69)); - let xt2 = primitives::testing::TestXt(Some(1), 1, Call::transfer(33, 69)); + let xt = primitives::testing::TestXt(Some(1), Call::transfer(33, 69), extra(0, 0)); + let xt2 = primitives::testing::TestXt(Some(1), Call::transfer(33, 69), extra(1, 0)); let encoded = xt2.encode(); let len = if should_fail { (internal::MAX_TRANSACTIONS_WEIGHT - 1) as usize } else { encoded.len() }; + let encoded_len = encoded.len() as u32; with_externalities(&mut t, || { Executive::initialize_block(&Header::new( 1, @@ -573,11 +568,11 @@ mod tests { if should_fail { assert!(res.is_err()); - assert_eq!(>::all_extrinsics_weight(), 28); + assert_eq!(>::all_extrinsics_weight(), encoded_len); assert_eq!(>::extrinsic_index(), Some(1)); } else { assert!(res.is_ok()); - assert_eq!(>::all_extrinsics_weight(), 56); + assert_eq!(>::all_extrinsics_weight(), encoded_len * 2); assert_eq!(>::extrinsic_index(), Some(2)); } }); @@ -589,7 +584,8 @@ mod tests { #[test] fn default_block_weight() { - let xt = primitives::testing::TestXt(None, 0, Call::set_balance(33, 69, 69)); + let xt = primitives::testing::TestXt(None, Call::set_balance(33, 69, 69), extra(0, 0)); + let len = xt.clone().encode().len() as u32; let mut t = new_test_ext(); with_externalities(&mut t, || { Executive::apply_extrinsic(xt.clone()).unwrap(); @@ -597,21 +593,15 @@ mod tests { Executive::apply_extrinsic(xt.clone()).unwrap(); assert_eq!( >::all_extrinsics_weight(), - 3 * (0 /*base*/ + 22 /*len*/ * 1 /*byte*/) + 3 * (0 /*base*/ + len /*len*/ * 1 /*byte*/) ); }); } #[test] fn validate_unsigned() { - let xt = primitives::testing::TestXt(None, 0, Call::set_balance(33, 69, 69)); - let valid = TransactionValidity::Valid { - priority: 0, - requires: vec![], - provides: vec![], - longevity: 18446744073709551615, - propagate: false, - }; + let xt = primitives::testing::TestXt(None, Call::set_balance(33, 69, 69), extra(0, 0)); + let valid = TransactionValidity::Valid(Default::default()); let mut t = new_test_ext(); with_externalities(&mut t, || { @@ -633,7 +623,7 @@ mod tests { 10, lock, ); - let xt = primitives::testing::TestXt(Some(1), 0, Call::transfer(2, 10)); + let xt = primitives::testing::TestXt(Some(1), Call::transfer(2, 10), extra(0, 0)); Executive::initialize_block(&Header::new( 1, H256::default(), diff --git a/srml/support/test/tests/instance.rs b/srml/support/test/tests/instance.rs index 46edcd7df323b..a5f40878e057b 100644 --- a/srml/support/test/tests/instance.rs +++ b/srml/support/test/tests/instance.rs @@ -269,7 +269,7 @@ srml_support::construct_runtime!( pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; fn new_test_ext() -> runtime_io::TestExternalities { GenesisConfig{ diff --git a/srml/support/test/tests/issue2219.rs b/srml/support/test/tests/issue2219.rs index 9bae9bcde5549..54ad62cc937ab 100644 --- a/srml/support/test/tests/issue2219.rs +++ b/srml/support/test/tests/issue2219.rs @@ -152,7 +152,7 @@ pub type BlockNumber = u64; pub type Index = u64; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl system::Trait for Runtime { type Hash = H256; diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index d60524dc42c8b..9e98aaffa017f 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -757,6 +757,14 @@ impl Module { #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct CheckNonce(T::Index); +#[cfg(feature = "std")] +impl CheckNonce { + /// utility constructor. Used only in client/factory code. + pub fn from(nonce: T::Index) -> Self { + Self(nonce) + } +} + #[cfg(feature = "std")] impl rstd::fmt::Debug for CheckNonce { fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { diff --git a/subkey/Cargo.toml b/subkey/Cargo.toml index 699448e17407c..6ecede88edaec 100644 --- a/subkey/Cargo.toml +++ b/subkey/Cargo.toml @@ -18,6 +18,8 @@ schnorrkel = "0.1.1" hex = "0.3" hex-literal = "0.2" parity-codec = "4.1.1" +system = { package = "srml-system", path = "../srml/system" } +balances = { package = "srml-balances", path = "../srml/balances" } [features] bench = [] diff --git a/subkey/src/main.rs b/subkey/src/main.rs index 7cff0d6414f26..dfd923e993149 100644 --- a/subkey/src/main.rs +++ b/subkey/src/main.rs @@ -23,10 +23,10 @@ use hex_literal::hex; use clap::load_yaml; use bip39::{Mnemonic, Language, MnemonicType}; use substrate_primitives::{ed25519, sr25519, hexdisplay::HexDisplay, Pair, Public, crypto::Ss58Codec, blake2_256}; -use parity_codec::{Encode, Decode, Compact}; +use parity_codec::{Encode, Decode}; use sr_primitives::generic::Era; use node_primitives::{Balance, Index, Hash}; -use node_runtime::{Call, UncheckedExtrinsic, BalancesCall}; +use node_runtime::{Call, UncheckedExtrinsic, BalancesCall, Runtime}; mod vanity; @@ -86,6 +86,9 @@ fn execute(matches: clap::ArgMatches) where <::Pair as Pair>::Signature: AsRef<[u8]> + AsMut<[u8]> + Default, <::Pair as Pair>::Public: Sized + AsRef<[u8]> + Ss58Codec + AsRef<<::Pair as Pair>::Public>, { + let extra = |i: Index, f: Balance| { + (system::CheckNonce::::from(i), balances::TakeFees::::from(f)) + }; let password = matches.value_of("password"); match matches.subcommand() { ("generate", Some(matches)) => { @@ -153,7 +156,8 @@ fn execute(matches: clap::ArgMatches) where println!("Using a genesis hash of {}", HexDisplay::from(&genesis_hash.as_ref())); let era = Era::immortal(); - let raw_payload = (Compact(index), function, era, genesis_hash); + + let raw_payload = (function, era, genesis_hash, extra(index, 0)); let signature = raw_payload.using_encoded(|payload| if payload.len() > 256 { signer.sign(&blake2_256(payload)[..]) } else { @@ -161,11 +165,11 @@ fn execute(matches: clap::ArgMatches) where signer.sign(payload) }); let extrinsic = UncheckedExtrinsic::new_signed( - index, - raw_payload.1, + raw_payload.0, signer.public().into(), signature.into(), era, + extra(index, 0), ); println!("0x{}", hex::encode(&extrinsic.encode())); } @@ -192,7 +196,7 @@ fn execute(matches: clap::ArgMatches) where let era = Era::immortal(); - let raw_payload = (Compact(index), function, era, prior_block_hash); + let raw_payload = (function, era, prior_block_hash, extra(index, 0)); let signature = raw_payload.using_encoded(|payload| if payload.len() > 256 { signer.sign(&blake2_256(payload)[..]) @@ -202,11 +206,11 @@ fn execute(matches: clap::ArgMatches) where ); let extrinsic = UncheckedExtrinsic::new_signed( - index, - raw_payload.1, + raw_payload.0, signer.public().into(), signature.into(), era, + extra(index, 0), ); println!("0x{}", hex::encode(&extrinsic.encode())); From 8e7c803c0ffdedf0c9775c01fe124ac5c30e0a30 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 13 Jul 2019 13:30:52 +0200 Subject: [PATCH 06/33] Fix a doc test --- srml/executive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index a389da6ac093c..512b9086c9cbb 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -69,7 +69,7 @@ //! # } //! # } //! /// Executive: handles dispatch to the various modules. -//! pub type Executive = executive::Executive; +//! pub type Executive = executive::Executive; //! ``` #![cfg_attr(not(feature = "std"), no_std)] From a824b561e371faf8eefadc23ed527ddc93d286f8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 13 Jul 2019 14:03:10 +0200 Subject: [PATCH 07/33] Compact encoding --- srml/balances/src/lib.rs | 2 +- srml/system/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 8c04e6f7d29d5..493090ed0b3c2 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -1133,7 +1133,7 @@ where /// Require the transactor pay for themselves and maybe include a tip to gain additional priority /// in the queue. #[derive(Encode, Decode, Clone, Eq, PartialEq)] -pub struct TakeFees, I: Instance = DefaultInstance>(T::Balance); +pub struct TakeFees, I: Instance = DefaultInstance>(#[codec(compact)] T::Balance); #[cfg(feature = "std")] impl, I: Instance> TakeFees { diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 9e98aaffa017f..bc2b217a49eeb 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -755,7 +755,7 @@ impl Module { /// Nonce check and increment to give replay protection for transactions. #[derive(Encode, Decode, Clone, Eq, PartialEq)] -pub struct CheckNonce(T::Index); +pub struct CheckNonce(#[codec(compact)] T::Index); #[cfg(feature = "std")] impl CheckNonce { From 5de080f671e0290729d9ae0f54b73b9a97e318f9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 15 Jul 2019 15:42:53 +0900 Subject: [PATCH 08/33] Extract out the era logic into an extension --- .../src/generic/unchecked_extrinsic.rs | 38 +++++++------------ core/sr-primitives/src/traits.rs | 18 ++++++++- node/cli/src/factory_impl.rs | 22 +++++------ node/executor/src/lib.rs | 1 + node/runtime/src/lib.rs | 2 +- srml/balances/src/lib.rs | 5 ++- srml/system/src/lib.rs | 38 ++++++++++++++++++- 7 files changed, 82 insertions(+), 42 deletions(-) diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index 12e96ba2f1832..190fff168c770 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -22,11 +22,8 @@ use std::fmt; use rstd::prelude::*; use runtime_io::blake2_256; use crate::codec::{Decode, Encode, Input}; -use crate::traits::{ - self, Member, SimpleArithmetic, MaybeDisplay, CurrentHeight, SignedExtension, - BlockNumberToHash, Lookup, Checkable, Extrinsic, SaturatedConversion -}; -use super::{CheckedExtrinsic, Era}; +use crate::traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic}; +use super::CheckedExtrinsic; const TRANSACTION_VERSION: u8 = 1; @@ -40,7 +37,7 @@ where /// The signature, address, number of extrinsics have come before from /// the same signer and an era describing the longevity of this transaction, /// if this is a signed extrinsic. - pub signature: Option<(Address, Signature, Era, Extra)>, + pub signature: Option<(Address, Signature, Extra)>, /// The function that should be called. pub function: Call, } @@ -53,11 +50,10 @@ impl function: Call, signed: Address, signature: Signature, - era: Era, extra: Extra ) -> Self { UncheckedExtrinsic { - signature: Some((signed, signature, era, extra)), + signature: Some((signed, signature, extra)), function, } } @@ -79,8 +75,8 @@ impl Extrinsic } } -impl - Checkable +impl + Checkable for UncheckedExtrinsic where @@ -89,22 +85,16 @@ where Signature: Member + traits::Verify, Extra: SignedExtension, AccountId: Member + MaybeDisplay, - BlockNumber: SimpleArithmetic, - Hash: Encode, - Context: Lookup - + CurrentHeight - + BlockNumberToHash, + Lookup: traits::Lookup { type Checked = CheckedExtrinsic; - fn check(self, context: &Context) -> Result { + fn check(self, lookup: &Lookup) -> Result { Ok(match self.signature { - Some((signed, signature, era, extra)) => { - let current_u64 = context.current_height().saturated_into::(); - let h = context.block_number_to_hash(era.birth(current_u64).saturated_into()) - .ok_or("transaction birth block ancient")?; - let signed = context.lookup(signed)?; - let raw_payload = (self.function, era, h, extra); + Some((signed, signature, extra)) => { + let additional_signed = extra.additional_signed()?; + let raw_payload = (self.function, extra, additional_signed); + let signed = lookup.lookup(signed)?; if !raw_payload.using_encoded(|payload| { if payload.len() > 256 { signature.verify(&blake2_256(payload)[..], &signed) @@ -115,7 +105,7 @@ where return Err(crate::BAD_SIGNATURE) } CheckedExtrinsic { - signed: Some((signed, raw_payload.3)), + signed: Some((signed, raw_payload.1)), function: raw_payload.0, } } @@ -200,7 +190,7 @@ where Extra: SignedExtension, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UncheckedExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2, &x.3)), self.function) + write!(f, "UncheckedExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2)), self.function) } } diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 91667ecce4ae7..98b3ceb0ef15d 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -813,7 +813,15 @@ pub trait SignedExtension: /// The type which encodes the sender identity. type AccountId; - /// Validate a signed transaction for the transaction queue. + /// Any additional data that will go into the signed payload. This may be created dynamically + /// from the transaction using the `additional_signed` function. + type AdditionalSigned: Encode; + + /// Construct any additional data that should be in the signed payload of the transaction. Can + /// also perform any pre-signature-verification checks and return an error if needed. + fn additional_signed(&self) -> Result; + + /// Validate a signed transaction for the transaction queue. fn validate( &self, _who: &Self::AccountId, @@ -846,6 +854,12 @@ impl< B: SignedExtension, > SignedExtension for (A, B) { type AccountId = AccountId; + type AdditionalSigned = (A::AdditionalSigned, B::AdditionalSigned); + + fn additional_signed(&self) -> Result { + Ok((self.0.additional_signed()?, self.1.additional_signed()?)) + } + fn validate( &self, who: &Self::AccountId, @@ -884,6 +898,8 @@ impl< #[cfg(feature = "std")] impl SignedExtension for () { type AccountId = u64; + type AdditionalSigned = (); + fn additional_signed(&self) -> result::Result<(), &'static str> { Ok(()) } } /// An "executable" piece of information, used by the standard Substrate Executive in order to diff --git a/node/cli/src/factory_impl.rs b/node/cli/src/factory_impl.rs index 40f4f602ce712..ed45d4cf9545a 100644 --- a/node/cli/src/factory_impl.rs +++ b/node/cli/src/factory_impl.rs @@ -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; @@ -130,18 +127,19 @@ impl RuntimeAdapter for FactoryState { ) -> ::Extrinsic { let index = self.extract_index(&sender, prior_block_hash); let phase = self.extract_phase(*prior_block_hash); + let era = system::CheckEra::from(Era::mortal(256, phase)); let check_nonce = system::CheckNonce::from(index); let take_fees = balances::TakeFees::from(0); sign::(CheckedExtrinsic { - signed: Some((sender.clone(), (check_nonce, take_fees))), + signed: Some((sender.clone(), (era, (check_nonce, take_fees)))), function: Call::Balances( BalancesCall::transfer( 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 +227,11 @@ fn gen_seed_bytes(seed: u64) -> [u8; 32] { fn sign( xt: CheckedExtrinsic, key: &sr25519::Pair, - prior_block_hash: &Hash, - phase: u64, + additional_signed: ::AdditionalSigned, ) -> ::Extrinsic { let s = match xt.signed { Some((signed, extra)) => { - let era = Era::mortal(256, phase); - let payload = (xt.function, era, prior_block_hash, extra.clone()); + 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,7 +240,7 @@ fn sign( } }).into(); UncheckedExtrinsic { - signature: Some((indices::address::Address::Id(signed), signature, era, extra)), + signature: Some((indices::address::Address::Id(signed), signature, extra)), function: payload.0, } } diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 87c4d4a88e4bc..f09853ca10e1e 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -80,6 +80,7 @@ mod tests { type TestExternalities = CoreTestExternalities; + // TODO: fix for being charged based on weight now. fn transfer_fee(bytes: Balance) -> Balance { >::get() + >::get() * bytes } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 71784959e5ef8..f6c6707e03cfd 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -436,7 +436,7 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. -pub type SignedExtra = (system::CheckNonce, balances::TakeFees); +pub type SignedExtra = (system::CheckEra, (system::CheckNonce, balances::TakeFees)); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Extrinsic type that has already been checked. diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 493090ed0b3c2..9266b44a4ee42 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -1157,13 +1157,16 @@ use primitives::weights::Weight; impl, I: Instance + Clone + Eq> SignedExtension for TakeFees { type AccountId = T::AccountId; + type AdditionalSigned = (); + fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } + fn validate( &self, who: &Self::AccountId, weight: Weight, ) -> rstd::result::Result { let fee_x = T::Balance::from(weight); - // TODO TODO: should be weight_to_fee(weight) + // TODO: should be weight_to_fee(weight) let fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * fee_x; let fee = fee + self.0.clone(); let imbalance = >::withdraw( diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index bc2b217a49eeb..684dc24ae7339 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -77,11 +77,11 @@ use rstd::prelude::*; #[cfg(any(feature = "std", test))] use rstd::map; use primitives::{ - generic, weights::Weight, traits::{ + generic::{self, Era}, weights::Weight, traits::{ self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, CurrentHeight, BlockNumberToHash, MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded, - Lookup, DispatchError + Lookup, DispatchError, SaturatedConversion }, transaction_validity::{ ValidTransaction, TransactionPriority, TransactionLongevity }, @@ -774,6 +774,8 @@ impl rstd::fmt::Debug for CheckNonce { impl SignedExtension for CheckNonce { type AccountId = T::AccountId; + type AdditionalSigned = (); + fn additional_signed(&self) -> Result<(), &'static str> { Ok(()) } fn pre_dispatch( self, who: &Self::AccountId, @@ -817,6 +819,38 @@ impl SignedExtension for CheckNonce { } } + +/// Nonce check and increment to give replay protection for transactions. +#[derive(Encode, Decode, Clone, Eq, PartialEq)] +pub struct CheckEra((Era, rstd::marker::PhantomData)); + +#[cfg(feature = "std")] +impl CheckEra { + /// utility constructor. Used only in client/factory code. + pub fn from(era: Era) -> Self { + Self((era, rstd::marker::PhantomData)) + } +} + +#[cfg(feature = "std")] +impl rstd::fmt::Debug for CheckEra { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + self.0.fmt(f) + } +} + +impl SignedExtension for CheckEra { + type AccountId = T::AccountId; + type AdditionalSigned = T::Hash; + fn additional_signed(&self) -> Result { + let current_u64 = >::block_number().saturated_into::(); + let n = (self.0).0.birth(current_u64).saturated_into::(); + if !>::exists(n) { Err("transaction birth block ancient")? } + Ok(>::block_hash(n)) + } +} + + pub struct ChainContext(::rstd::marker::PhantomData); impl Default for ChainContext { fn default() -> Self { From a8789b92382cd78d1dfec0f7f386f80727a37e6f Mon Sep 17 00:00:00 2001 From: Kian Peymani Date: Tue, 16 Jul 2019 12:42:42 +0200 Subject: [PATCH 09/33] 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 --- Cargo.lock | 1 + .../src/generic/unchecked_extrinsic.rs | 73 ++--------- core/sr-primitives/src/traits.rs | 106 +++++++++------- .../sr-primitives/src/transaction_validity.rs | 2 +- node-template/runtime/src/lib.rs | 7 +- node-template/runtime/src/template.rs | 3 + node/cli/src/factory_impl.rs | 18 ++- node/cli/src/service.rs | 9 +- node/executor/src/lib.rs | 37 +++--- node/runtime/src/lib.rs | 10 +- srml/assets/src/lib.rs | 2 + srml/aura/src/mock.rs | 2 + srml/authorship/src/lib.rs | 2 + srml/balances/src/lib.rs | 2 +- srml/balances/src/mock.rs | 2 + srml/balances/src/tests.rs | 17 +++ srml/collective/src/lib.rs | 2 + srml/contracts/src/tests.rs | 2 + srml/council/src/lib.rs | 2 + srml/democracy/src/lib.rs | 2 + srml/elections/src/lib.rs | 2 + srml/example/src/lib.rs | 2 + srml/executive/src/lib.rs | 42 ++++--- srml/finality-tracker/src/lib.rs | 2 + srml/grandpa/src/mock.rs | 2 + srml/indices/src/mock.rs | 2 + srml/session/src/mock.rs | 2 + srml/staking/src/mock.rs | 2 + srml/system/src/lib.rs | 119 +++++++++++++++++- srml/timestamp/src/lib.rs | 2 + srml/treasury/src/lib.rs | 2 + subkey/src/main.rs | 13 +- 32 files changed, 322 insertions(+), 171 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d925435e138c4..33d34db349ec1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3738,6 +3738,7 @@ name = "srml-executive" version = "2.0.0" dependencies = [ "hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "node-runtime 2.0.0", "parity-codec 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index 190fff168c770..65c0f20182e5e 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -199,7 +199,7 @@ mod tests { use super::*; use runtime_io::blake2_256; use crate::codec::{Encode, Decode}; - use crate::traits::SignedExtension; + use crate::traits::{SignedExtension, BlockNumberToHash, Lookup, CurrentHeight}; use serde::{Serialize, Deserialize}; struct TestContext; @@ -237,6 +237,8 @@ mod tests { struct TestExtra; impl SignedExtension for TestExtra { type AccountId = u64; + type AdditionalSigned = (); + fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } } type Ex = UncheckedExtrinsic; @@ -254,8 +256,7 @@ mod tests { let ux = Ex::new_signed( vec![0u8; 0], TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (TEST_ACCOUNT, vec![0u8; 0], Era::immortal(), 0u64).encode()), - Era::immortal(), + TestSig(TEST_ACCOUNT, (vec![0u8; 0], TestExtra).encode()), TestExtra ); let encoded = ux.encode(); @@ -267,9 +268,8 @@ mod tests { let ux = Ex::new_signed( vec![0u8; 0], TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (TEST_ACCOUNT, vec![0u8; 257], Era::immortal(), 0u64) + TestSig(TEST_ACCOUNT, (vec![0u8; 257], TestExtra) .using_encoded(blake2_256)[..].to_owned()), - Era::immortal(), TestExtra ); let encoded = ux.encode(); @@ -289,7 +289,6 @@ mod tests { vec![0u8; 0], TEST_ACCOUNT, TestSig(TEST_ACCOUNT, vec![0u8; 0]), - Era::immortal(), TestExtra ); assert!(ux.is_signed().unwrap_or(false)); @@ -297,12 +296,11 @@ mod tests { } #[test] - fn immortal_signed_check_should_work() { + fn signed_check_should_work() { let ux = Ex::new_signed( vec![0u8; 0], TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (vec![0u8; 0], Era::immortal(), 0u64, TestExtra).encode()), - Era::immortal(), + TestSig(TEST_ACCOUNT, (vec![0u8; 0], TestExtra).encode()), TestExtra ); assert!(ux.is_signed().unwrap_or(false)); @@ -312,63 +310,6 @@ mod tests { ); } - #[test] - fn mortal_signed_check_should_work() { - let ux = Ex::new_signed( - vec![0u8; 0], - TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (vec![0u8; 0], Era::mortal(32, 42), 42u64, TestExtra).encode()), - Era::mortal(32, 42), - TestExtra - ); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!( - >::check(ux, &TestContext), - Ok(CEx { signed: Some((TEST_ACCOUNT, TestExtra)), function: vec![0u8; 0] }) - ); - } - - #[test] - fn later_mortal_signed_check_should_work() { - let ux = Ex::new_signed( - vec![0u8; 0], - TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (vec![0u8; 0], Era::mortal(32, 11), 11u64, TestExtra).encode()), - Era::mortal(32, 11), - TestExtra - ); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!( - >::check(ux, &TestContext), - Ok(CEx { signed: Some((TEST_ACCOUNT, TestExtra)), function: vec![0u8; 0] })); - } - - #[test] - fn too_late_mortal_signed_check_should_fail() { - let ux = Ex::new_signed( - vec![0u8; 0], - TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (TEST_ACCOUNT, vec![0u8; 0], Era::mortal(32, 10), 10u64).encode()), - Era::mortal(32, 10), - TestExtra - ); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); - } - - #[test] - fn too_early_mortal_signed_check_should_fail() { - let ux = Ex::new_signed( - vec![0u8; 0], - TEST_ACCOUNT, - TestSig(TEST_ACCOUNT, (TEST_ACCOUNT, vec![0u8; 0], Era::mortal(32, 43), 43u64).encode()), - Era::mortal(32, 43), - TestExtra - ); - assert!(ux.is_signed().unwrap_or(false)); - assert_eq!(>::check(ux, &TestContext), Err(crate::BAD_SIGNATURE)); - } - #[test] fn encoding_matches_vec() { let ex = Ex::new_unsigned(vec![0u8; 0]); diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 98b3ceb0ef15d..1afe65fa274b2 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -848,58 +848,74 @@ pub trait SignedExtension: ) -> Result<(), DispatchError> { Self::validate_unsigned(weight).map(|_| ()) } } -impl< - AccountId, - A: SignedExtension, - B: SignedExtension, -> SignedExtension for (A, B) { - type AccountId = AccountId; - type AdditionalSigned = (A::AdditionalSigned, B::AdditionalSigned); - - fn additional_signed(&self) -> Result { - Ok((self.0.additional_signed()?, self.1.additional_signed()?)) - } +macro_rules! tuple_impl_indexed { + ($first:ident, $($rest:ident,)+ ; $first_index:tt, $($rest_index:tt,)+) => { + tuple_impl_indexed!([$first] [$($rest)+] ; [$first_index,] [$($rest_index,)+]); + }; + ([$($direct:ident)+] ; [$($index:tt,)+]) => { + impl< + AccountId, + $($direct: SignedExtension),+ + > SignedExtension for ($($direct),+,) { + type AccountId = AccountId; + type AdditionalSigned = ($($direct::AdditionalSigned,)+); + fn additional_signed(&self) -> Result { + Ok(( $(self.$index.additional_signed()?,)+ )) + } + fn validate( + &self, + who: &Self::AccountId, + weight: crate::weights::Weight, + ) -> Result { + let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, weight)?),+]; + Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a))) + } + fn pre_dispatch( + self, + who: &Self::AccountId, + weight: crate::weights::Weight, + ) -> Result<(), DispatchError> { + $(self.$index.pre_dispatch(who, weight)?;)+ + Ok(()) + } + fn validate_unsigned( + weight: crate::weights::Weight, + ) -> Result { + let aggregator = vec![$($direct::validate_unsigned(weight)?),+]; + Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a))) + } + fn pre_dispatch_unsigned( + weight: crate::weights::Weight, + ) -> Result<(), DispatchError> { + $($direct::pre_dispatch_unsigned(weight)?;)+ + Ok(()) + } + } - fn validate( - &self, - who: &Self::AccountId, - weight: crate::weights::Weight, - ) -> Result { - let a = self.0.validate(who, weight)?; - let b = self.1.validate(who, weight)?; - Ok(a.combine_with(b)) - } - fn pre_dispatch( - self, - who: &Self::AccountId, - weight: crate::weights::Weight, - ) -> Result<(), DispatchError> { - self.0.pre_dispatch(who, weight)?; - self.1.pre_dispatch(who, weight)?; - Ok(()) - } - fn validate_unsigned( - weight: crate::weights::Weight, - ) -> Result { - let a = A::validate_unsigned(weight)?; - let b = B::validate_unsigned(weight)?; - Ok(a.combine_with(b)) - } - fn pre_dispatch_unsigned( - weight: crate::weights::Weight, - ) -> Result<(), DispatchError> { - A::pre_dispatch_unsigned(weight)?; - B::pre_dispatch_unsigned(weight)?; - Ok(()) - } + }; + ([$($direct:ident)+] [] ; [$($index:tt,)+] []) => { + tuple_impl_indexed!([$($direct)+] ; [$($index,)+]); + }; + ( + [$($direct:ident)+] [$first:ident $($rest:ident)*] + ; + [$($index:tt,)+] [$first_index:tt, $($rest_index:tt,)*] + ) => { + tuple_impl_indexed!([$($direct)+] ; [$($index,)+]); + tuple_impl_indexed!([$($direct)+ $first] [$($rest)*] ; [$($index,)+ $first_index,] [$($rest_index,)*]); + }; } -/// To be used only for testing. +// TODO: merge this into `tuple_impl` once codec supports `trait Codec` for longer tuple lengths. +#[allow(non_snake_case)] +tuple_impl_indexed!(A, B, C, D, E, F, G, H, I, J, ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,); + +/// Only for base bone testing when you don't care about signed extensions at all.\ #[cfg(feature = "std")] impl SignedExtension for () { type AccountId = u64; type AdditionalSigned = (); - fn additional_signed(&self) -> result::Result<(), &'static str> { Ok(()) } + fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } } /// An "executable" piece of information, used by the standard Substrate Executive in order to diff --git a/core/sr-primitives/src/transaction_validity.rs b/core/sr-primitives/src/transaction_validity.rs index 66e66c0042db9..a6cc43c5a365d 100644 --- a/core/sr-primitives/src/transaction_validity.rs +++ b/core/sr-primitives/src/transaction_validity.rs @@ -103,7 +103,7 @@ impl ValidTransaction { /// the logic *And* of the propagate flags. pub fn combine_with(mut self, mut other: ValidTransaction) -> Self { ValidTransaction { - priority: self.priority + other.priority, + priority: self.priority.saturating_add(other.priority), requires: { self.requires.append(&mut other.requires); self.requires }, provides: { self.provides.append(&mut other.provides); self.provides }, longevity: self.longevity.min(other.longevity), diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 1dcc65d00b5e4..3a6eb1886fc34 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -17,7 +17,7 @@ use primitives::bytes; use primitives::{ed25519, sr25519, OpaqueMetadata}; use runtime_primitives::{ ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str, - traits::{self, NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify} + traits::{self, NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify}, weights::Weight, }; use client::{ block_builder::api::{CheckInherentsResult, InherentData, self as block_builder_api}, @@ -113,6 +113,7 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const BlockHashCount: BlockNumber = 250; + pub const MaximumBlockWeight: Weight = 4 * 1024 * 1024; } impl system::Trait for Runtime { @@ -136,6 +137,8 @@ impl system::Trait for Runtime { type Origin = Origin; /// Maximum number of block number to block hash mappings to keep (oldest pruned first). type BlockHashCount = BlockHashCount; + /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. + type MaximumBlockWeight = MaximumBlockWeight; } impl aura::Trait for Runtime { @@ -228,7 +231,7 @@ pub type Block = generic::Block; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. -pub type SignedExtra = (system::CheckNonce, balances::TakeFees); +pub type SignedExtra = (system::CheckNonce, system::CheckWeight, balances::TakeFees); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Extrinsic type that has already been checked. diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index 05257d2a53341..97466d2b6dce5 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -73,6 +73,7 @@ mod tests { use primitives::{H256, Blake2Hasher}; use support::{impl_outer_origin, assert_ok, parameter_types}; use runtime_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; + use runtime_primitives::weights::Weight; impl_outer_origin! { pub enum Origin for Test {} @@ -85,6 +86,7 @@ mod tests { pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -97,6 +99,7 @@ mod tests { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl Trait for Test { type Event = (); diff --git a/node/cli/src/factory_impl.rs b/node/cli/src/factory_impl.rs index ed45d4cf9545a..6f2ef00ad74a6 100644 --- a/node/cli/src/factory_impl.rs +++ b/node/cli/src/factory_impl.rs @@ -51,6 +51,17 @@ pub struct FactoryState { type Number = <::Header as HeaderT>::Number; +impl FactoryState { + 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 { type AccountId = node_primitives::AccountId; type Balance = node_primitives::Balance; @@ -127,19 +138,16 @@ impl RuntimeAdapter for FactoryState { ) -> ::Extrinsic { let index = self.extract_index(&sender, prior_block_hash); let phase = self.extract_phase(*prior_block_hash); - let era = system::CheckEra::from(Era::mortal(256, phase)); - let check_nonce = system::CheckNonce::from(index); - let take_fees = balances::TakeFees::from(0); sign::(CheckedExtrinsic { - signed: Some((sender.clone(), (era, (check_nonce, take_fees)))), + signed: Some((sender.clone(), Self::build_extra(index, phase))), function: Call::Balances( BalancesCall::transfer( indices::address::Address::Id(destination.clone().into()), (*amount).into() ) ) - }, key, (prior_block_hash.clone(), ((), ()))) + }, key, (prior_block_hash.clone(), (), (), ())) } fn inherent_extrinsics(&self) -> InherentData { diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index ce054f9f798a2..6302a6a4815e5 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -357,12 +357,14 @@ mod tests { let signer = charlie.clone(); let function = Call::Balances(BalancesCall::transfer(to.into(), amount)); - let era = Era::immortal(); + + 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_nonce, take_fees); + let extra = (check_era, check_nonce, check_weight, take_fees); - let raw_payload = (function, era, genesis_hash, extra.clone()); + 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 { @@ -372,7 +374,6 @@ mod tests { raw_payload.0, from.into(), signature.into(), - era, extra, ).encode(); let v: Vec = Decode::decode(&mut xt.as_slice()).unwrap(); diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index f09853ca10e1e..e0617ff9d1324 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -81,8 +81,10 @@ mod tests { type TestExternalities = CoreTestExternalities; // TODO: fix for being charged based on weight now. - fn transfer_fee(bytes: Balance) -> Balance { - >::get() + >::get() * bytes + fn transfer_fee(extrinsic: &E) -> Balance { + >::get() + + >::get() * + (extrinsic.encode().len() as Balance) } fn creation_fee() -> Balance { @@ -116,8 +118,7 @@ mod tests { fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { match xt.signed { Some((signed, extra)) => { - let era = Era::mortal(256, 0); - let payload = (xt.function, era, GENESIS_HASH, extra.clone()); + 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 { @@ -127,7 +128,7 @@ mod tests { } }).into(); UncheckedExtrinsic { - signature: Some((indices::address::Address::Id(signed), signature, era, extra)), + signature: Some((indices::address::Address::Id(signed), signature, extra)), function: payload.0, } } @@ -139,7 +140,12 @@ mod tests { } fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra { - (system::CheckNonce::from(nonce), balances::TakeFees::from(extra_fee)) + ( + system::CheckEra::from(Era::mortal(256, 0)), + system::CheckNonce::from(nonce), + system::CheckWeight::from(), + balances::TakeFees::from(extra_fee) + ) } fn xt() -> UncheckedExtrinsic { @@ -260,7 +266,7 @@ mod tests { assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(169) - creation_fee()); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt()) - creation_fee()); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -296,7 +302,7 @@ mod tests { assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(169) - creation_fee()); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt()) - creation_fee()); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -491,7 +497,6 @@ mod tests { // session change => consensus authorities change => authorities change digest item appears let digest = Header::decode(&mut &block2.0[..]).unwrap().digest; assert_eq!(digest.logs().len(), 0); -// assert!(digest.logs()[0].as_consensus().is_some()); (block1, block2) } @@ -529,7 +534,7 @@ mod tests { ).0.unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(169) - creation_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 { @@ -566,8 +571,8 @@ mod tests { runtime_io::with_externalities(&mut t, || { // 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(169) - 2 * creation_fee()); - assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - transfer_fee(169) - creation_fee()); + 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), @@ -622,15 +627,15 @@ mod tests { WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0).unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(169) - creation_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, || { - assert_eq!(Balances::total_balance(&alice()), 32 * DOLLARS - 2 * transfer_fee(169) - 2 * creation_fee()); - assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * transfer_fee(169) - creation_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()); }); } @@ -876,7 +881,7 @@ mod tests { assert_eq!(r, Ok(ApplyOutcome::Success)); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(169) - creation_fee()); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(&xt()) - creation_fee()); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index f6c6707e03cfd..a8130dee0ea17 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -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, Convert, }; @@ -111,6 +112,7 @@ pub const DAYS: Moment = HOURS * 24; parameter_types! { pub const BlockHashCount: BlockNumber = 250; + pub const MaximumBlockWeight: Weight = 4 * 1024 * 1024; } impl system::Trait for Runtime { @@ -124,6 +126,7 @@ impl system::Trait for Runtime { type Header = generic::Header; type Event = Event; type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl aura::Trait for Runtime { @@ -436,7 +439,12 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; /// The SignedExtension to the basic transaction logic. -pub type SignedExtra = (system::CheckEra, (system::CheckNonce, balances::TakeFees)); +pub type SignedExtra = ( + system::CheckEra, + system::CheckNonce, + system::CheckWeight, + balances::TakeFees +); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Extrinsic type that has already been checked. diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index 19159bf60fba3..1e4c06700abe1 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -257,6 +257,7 @@ mod tests { pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -269,6 +270,7 @@ mod tests { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl Trait for Test { type Event = (); diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index fad511baba331..ba6a66cdace68 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -37,6 +37,7 @@ pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { @@ -50,6 +51,7 @@ impl system::Trait for Test { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl timestamp::Trait for Test { diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index 08a0279284871..42fa0630a4855 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -337,6 +337,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { @@ -350,6 +351,7 @@ mod tests { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl Trait for Test { diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 9266b44a4ee42..004ea41a035e9 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -747,6 +747,7 @@ impl, I: Instance> system::Trait for ElevatedTrait { type Header = T::Header; type Event = (); type BlockHashCount = T::BlockHashCount; + type MaximumBlockWeight = T::MaximumBlockWeight; } impl, I: Instance> Trait for ElevatedTrait { type Balance = T::Balance; @@ -1156,7 +1157,6 @@ use primitives::weights::Weight; impl, I: Instance + Clone + Eq> SignedExtension for TakeFees { type AccountId = T::AccountId; - type AdditionalSigned = (); fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index 26f4439f4608d..274f093386823 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -67,6 +67,7 @@ impl Get for TransactionByteFee { pub struct Runtime; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Runtime { type Origin = Origin; @@ -79,6 +80,7 @@ impl system::Trait for Runtime { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl Trait for Runtime { type Balance = u64; diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 10e6f94693682..c5e36ed6571f2 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -658,3 +658,20 @@ fn extra_balance_should_transfer() { } ); } + +#[test] +fn signed_extension_take_fees_work() { + with_externalities( + &mut ExtBuilder::default() + .existential_deposit(10) + .transaction_fees(10, 1) + .monied(true) + .build(), + || { + assert!(TakeFees::::from(0).validate(&1, 10).is_ok()); + assert_eq!(Balances::free_balance(&1), 100 - 20); + assert!(TakeFees::::from(5 /* tipped */).validate(&1, 10).is_ok()); + assert_eq!(Balances::free_balance(&1), 100 - 20 - 25); + } + ); +} diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index 23b156c718e7f..a8303501d46ea 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -402,6 +402,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -414,6 +415,7 @@ mod tests { type Header = Header; type Event = Event; type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl Trait for Test { type Origin = Origin; diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index b195a74bf429b..c3c6a595a3442 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -96,6 +96,7 @@ impl Get for BlockGasLimit { pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -108,6 +109,7 @@ impl system::Trait for Test { type Header = Header; type Event = MetaEvent; type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } parameter_types! { pub const BalancesTransactionBaseFee: u64 = 0; diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index 8a52f9ec004a9..1baeb6fdfd34b 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -98,6 +98,7 @@ mod tests { pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -110,6 +111,7 @@ mod tests { type Header = Header; type Event = Event; type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } parameter_types! { pub const ExistentialDeposit: u64 = 0; diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index d13feb4db531d..5c49f9519013d 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -998,6 +998,7 @@ mod tests { pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -1010,6 +1011,7 @@ mod tests { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } parameter_types! { pub const ExistentialDeposit: u64 = 0; diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 77597591775d7..324c1a78fbf1e 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -1108,6 +1108,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -1120,6 +1121,7 @@ mod tests { type Header = Header; type Event = Event; type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } parameter_types! { pub const ExistentialDeposit: u64 = 0; diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index 20ee1c6ba114f..b2bb0a0af47e4 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -525,6 +525,7 @@ mod tests { pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -537,6 +538,7 @@ mod tests { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } parameter_types! { pub const ExistentialDeposit: u64 = 0; diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 512b9086c9cbb..fa08a1017b94f 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -91,8 +91,6 @@ use primitives::weights::Weighable; mod internal { use primitives::traits::DispatchError; - pub const MAX_TRANSACTIONS_WEIGHT: u32 = 4 * 1024 * 1024; - pub enum ApplyError { BadSignature(&'static str), Stale, @@ -283,17 +281,10 @@ where >::note_extrinsic(encoded); } - // Check the weight of the block if that extrinsic is applied. - let weight = xt.weight(encoded_len); - - // TODO: Consider placing into a transaction extension. - if >::all_extrinsics_weight() + weight > internal::MAX_TRANSACTIONS_WEIGHT { - return Err(internal::ApplyError::FullBlock); - } - // AUDIT: Under no circumstances may this function panic from here onwards. // Decode parameters and dispatch + let weight = xt.weight(encoded_len); let r = Applyable::dispatch(xt, weight) .map_err(internal::ApplyError::from)?; @@ -366,10 +357,11 @@ mod tests { use balances::Call; use runtime_io::with_externalities; use substrate_primitives::{H256, Blake2Hasher}; + use primitives::generic::Era; use primitives::traits::{Header as HeaderT, BlakeTwo256, IdentityLookup}; use primitives::testing::{Digest, Header, Block}; use srml_support::{impl_outer_event, impl_outer_origin, parameter_types}; - use srml_support::traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason}; + use srml_support::traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason, Get}; use system; use hex_literal::hex; @@ -389,6 +381,7 @@ mod tests { pub struct Runtime; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Runtime { type Origin = Origin; @@ -401,6 +394,7 @@ mod tests { type Header = Header; type Event = MetaEvent; type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } parameter_types! { pub const ExistentialDeposit: u64 = 0; @@ -435,12 +429,22 @@ mod tests { } } - type SignedExtra = (system::CheckNonce, balances::TakeFees); + type SignedExtra = ( + system::CheckEra, + system::CheckNonce, + system::CheckWeight, + balances::TakeFees + ); type TestXt = primitives::testing::TestXt, SignedExtra>; type Executive = super::Executive, system::ChainContext, Runtime, ()>; fn extra(nonce: u64, fee: u64) -> SignedExtra { - (system::CheckNonce::from(nonce), balances::TakeFees::from(fee)) + ( + system::CheckEra::from(Era::Immortal), + system::CheckNonce::from(nonce), + system::CheckWeight::from(), + balances::TakeFees::from(fee) + ) } #[test] @@ -551,7 +555,7 @@ mod tests { let xt = primitives::testing::TestXt(Some(1), Call::transfer(33, 69), extra(0, 0)); let xt2 = primitives::testing::TestXt(Some(1), Call::transfer(33, 69), extra(1, 0)); let encoded = xt2.encode(); - let len = if should_fail { (internal::MAX_TRANSACTIONS_WEIGHT - 1) as usize } else { encoded.len() }; + let len = if should_fail { ( ::MaximumBlockWeight::get() - 1) as usize } else { encoded.len() }; let encoded_len = encoded.len() as u32; with_externalities(&mut t, || { Executive::initialize_block(&Header::new( @@ -583,14 +587,16 @@ mod tests { } #[test] - fn default_block_weight() { - let xt = primitives::testing::TestXt(None, Call::set_balance(33, 69, 69), extra(0, 0)); + fn default_block_weight_is_stored() { + let xt = primitives::testing::TestXt(Some(1), Call::transfer(33, 0), extra(0, 0)); + let x1 = primitives::testing::TestXt(Some(1), Call::transfer(33, 0), extra(1, 0)); + let x2 = primitives::testing::TestXt(Some(1), Call::transfer(33, 0), extra(2, 0)); let len = xt.clone().encode().len() as u32; let mut t = new_test_ext(); with_externalities(&mut t, || { Executive::apply_extrinsic(xt.clone()).unwrap(); - Executive::apply_extrinsic(xt.clone()).unwrap(); - Executive::apply_extrinsic(xt.clone()).unwrap(); + Executive::apply_extrinsic(x1.clone()).unwrap(); + Executive::apply_extrinsic(x2.clone()).unwrap(); assert_eq!( >::all_extrinsics_weight(), 3 * (0 /*base*/ + len /*len*/ * 1 /*byte*/) diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs index f9ccc36346222..2e17d9688f1c9 100644 --- a/srml/finality-tracker/src/lib.rs +++ b/srml/finality-tracker/src/lib.rs @@ -299,6 +299,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -311,6 +312,7 @@ mod tests { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } parameter_types! { pub const WindowSize: u64 = 11; diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index 733b2deaf1493..1420d65eb5576 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -43,6 +43,7 @@ impl Trait for Test { } parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -55,6 +56,7 @@ impl system::Trait for Test { type Header = Header; type Event = TestEvent; type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } mod grandpa { diff --git a/srml/indices/src/mock.rs b/srml/indices/src/mock.rs index 53e8f314c94bb..938aec2bc3311 100644 --- a/srml/indices/src/mock.rs +++ b/srml/indices/src/mock.rs @@ -66,6 +66,7 @@ impl ResolveHint for TestResolveHint { pub struct Runtime; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Runtime { type Origin = Origin; @@ -78,6 +79,7 @@ impl system::Trait for Runtime { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl Trait for Runtime { type AccountIndex = u64; diff --git a/srml/session/src/mock.rs b/srml/session/src/mock.rs index adb37720519a8..e6228e21042ed 100644 --- a/srml/session/src/mock.rs +++ b/srml/session/src/mock.rs @@ -109,6 +109,7 @@ pub fn set_next_validators(next: Vec) { pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -121,6 +122,7 @@ impl system::Trait for Test { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl timestamp::Trait for Test { type Moment = u64; diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index abad1752a6ec6..b767f446df1e8 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -87,6 +87,7 @@ impl_outer_origin!{ pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -99,6 +100,7 @@ impl system::Trait for Test { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } parameter_types! { pub const TransferFee: u64 = 0; diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 684dc24ae7339..be7a3ec492252 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -76,6 +76,7 @@ use serde::Serialize; use rstd::prelude::*; #[cfg(any(feature = "std", test))] use rstd::map; +use rstd::marker::PhantomData; use primitives::{ generic::{self, Era}, weights::Weight, traits::{ self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, @@ -190,6 +191,9 @@ pub trait Trait: 'static + Eq + Clone { /// Maximum number of block number to block hash mappings to keep (oldest pruned first). type BlockHashCount: Get; + + /// The maximum weight of a block. + type MaximumBlockWeight: Get; } pub type DigestOf = generic::Digest<::Hash>; @@ -725,17 +729,15 @@ impl Module { } /// To be called immediately after an extrinsic has been applied. - pub fn note_applied_extrinsic(r: &Result<(), &'static str>, encoded_len: u32) { + pub fn note_applied_extrinsic(r: &Result<(), &'static str>, _encoded_len: u32) { Self::deposit_event(match r { Ok(_) => Event::ExtrinsicSuccess, Err(_) => Event::ExtrinsicFailed, }.into()); let next_extrinsic_index = Self::extrinsic_index().unwrap_or_default() + 1u32; - let total_length = encoded_len.saturating_add(Self::all_extrinsics_weight()); storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &next_extrinsic_index); - AllExtrinsicsWeight::put(&total_length); } /// To be called immediately after `note_applied_extrinsic` of the last extrinsic of the block @@ -753,6 +755,61 @@ impl Module { } } +/// Weight limit check and increment. +#[derive(Encode, Decode, Clone, Eq, PartialEq)] +pub struct CheckWeight(PhantomData); + +impl CheckWeight { + fn internal_check_weight(weight: Weight) -> Result<(), DispatchError> { + let current_weight = Module::::all_extrinsics_weight(); + let next_weight = current_weight.saturating_add(weight); + if next_weight > T::MaximumBlockWeight::get() { + return Err(DispatchError::Payment) + } + AllExtrinsicsWeight::put(next_weight); + Ok(()) + } +} + +impl SignedExtension for CheckWeight { + type AccountId = T::AccountId; + type AdditionalSigned = (); + + fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + weight: Weight, + ) -> Result<(), DispatchError> { + Self::internal_check_weight(weight) + } + + fn validate( + &self, + _who: &Self::AccountId, + _weight: Weight, + ) -> Result { + // TODO: check for a maximum size and weight here as well. + // write priority based on tx weight type + tip. + Ok(ValidTransaction::default()) + } +} + +#[cfg(feature = "std")] +impl CheckWeight { + pub fn from() -> Self { + Self(PhantomData) + } +} + +#[cfg(feature = "std")] +impl rstd::fmt::Debug for CheckWeight { + fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { + write!(f, "CheckWeight") + } +} + /// Nonce check and increment to give replay protection for transactions. #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct CheckNonce(#[codec(compact)] T::Index); @@ -775,7 +832,9 @@ impl rstd::fmt::Debug for CheckNonce { impl SignedExtension for CheckNonce { type AccountId = T::AccountId; type AdditionalSigned = (); - fn additional_signed(&self) -> Result<(), &'static str> { Ok(()) } + + fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) } + fn pre_dispatch( self, who: &Self::AccountId, @@ -819,7 +878,6 @@ impl SignedExtension for CheckNonce { } } - /// Nonce check and increment to give replay protection for transactions. #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct CheckEra((Era, rstd::marker::PhantomData)); @@ -850,7 +908,6 @@ impl SignedExtension for CheckEra { } } - pub struct ChainContext(::rstd::marker::PhantomData); impl Default for ChainContext { fn default() -> Self { @@ -898,6 +955,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 10; + pub const MaximumBlockWeight: Weight = 1024; } impl Trait for Test { @@ -911,6 +969,7 @@ mod tests { type Header = Header; type Event = u16; type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl From for u16 { @@ -1061,4 +1120,52 @@ mod tests { } }) } + + #[test] + fn signed_ext_check_nonce_works() { + with_externalities(&mut new_test_ext(), || { + >::insert(1, 1); + // stale + assert!(CheckNonce::(0).validate(&1, 0).is_err()); + assert!(CheckNonce::(0).pre_dispatch(&1, 0).is_err()); + // correct + assert!(CheckNonce::(1).validate(&1, 0).is_ok()); + assert!(CheckNonce::(1).pre_dispatch(&1, 0).is_ok()); + // future + assert!(CheckNonce::(5).validate(&1, 0).is_ok()); + assert!(CheckNonce::(5).pre_dispatch(&1, 0).is_err()); + }) + } + + #[test] + fn signed_ext_check_weight_works() { + with_externalities(&mut new_test_ext(), || { + // small + AllExtrinsicsWeight::put(512); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, 100).is_ok()); + // almost + AllExtrinsicsWeight::put(512); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, 512).is_ok()); + // big + AllExtrinsicsWeight::put(512); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, 513).is_err()); + + }) + } + + #[test] + fn signed_ext_check_era_should_work() { + with_externalities(&mut new_test_ext(), || { + // future + assert_eq!( + CheckEra::::from(Era::mortal(4, 2)).additional_signed().err().unwrap(), + "transaction birth block ancient" + ); + + // correct + System::set_block_number(13); + >::insert(12, H256::repeat_byte(1)); + assert!(CheckEra::::from(Era::mortal(4, 12)).additional_signed().is_ok()); + }) + } } diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index 7bffac0db9007..a1c0b2f69fcaa 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -343,6 +343,7 @@ mod tests { pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -355,6 +356,7 @@ mod tests { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } impl Trait for Test { type Moment = u64; diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 7c4d7b10f21cf..aa49190d5abb2 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -370,6 +370,7 @@ mod tests { pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; } impl system::Trait for Test { type Origin = Origin; @@ -382,6 +383,7 @@ mod tests { type Header = Header; type Event = (); type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; } parameter_types! { pub const ExistentialDeposit: u64 = 0; diff --git a/subkey/src/main.rs b/subkey/src/main.rs index dfd923e993149..6a74391b00815 100644 --- a/subkey/src/main.rs +++ b/subkey/src/main.rs @@ -87,7 +87,12 @@ fn execute(matches: clap::ArgMatches) where <::Pair as Pair>::Public: Sized + AsRef<[u8]> + Ss58Codec + AsRef<<::Pair as Pair>::Public>, { let extra = |i: Index, f: Balance| { - (system::CheckNonce::::from(i), balances::TakeFees::::from(f)) + ( + system::CheckEra::::from(Era::Immortal), + system::CheckNonce::::from(i), + system::CheckWeight::::from(), + balances::TakeFees::::from(f), + ) }; let password = matches.value_of("password"); match matches.subcommand() { @@ -155,9 +160,7 @@ fn execute(matches: clap::ArgMatches) where println!("Using a genesis hash of {}", HexDisplay::from(&genesis_hash.as_ref())); - let era = Era::immortal(); - - let raw_payload = (function, era, genesis_hash, extra(index, 0)); + let raw_payload = (function, extra(index, 0), genesis_hash); let signature = raw_payload.using_encoded(|payload| if payload.len() > 256 { signer.sign(&blake2_256(payload)[..]) } else { @@ -168,7 +171,6 @@ fn execute(matches: clap::ArgMatches) where raw_payload.0, signer.public().into(), signature.into(), - era, extra(index, 0), ); println!("0x{}", hex::encode(&extrinsic.encode())); @@ -209,7 +211,6 @@ fn execute(matches: clap::ArgMatches) where raw_payload.0, signer.public().into(), signature.into(), - era, extra(index, 0), ); From 30b4ba7c200eeefc445b762942d74a23f6557b55 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 16 Jul 2019 21:47:23 +0900 Subject: [PATCH 10/33] Don't use len for weight - use data. --- .../src/generic/checked_extrinsic.rs | 20 +++++++------ core/sr-primitives/src/testing.rs | 18 +++++++----- core/sr-primitives/src/traits.rs | 26 ++++++++++++----- core/sr-primitives/src/weights.rs | 29 +++++++++++-------- srml/balances/src/lib.rs | 3 +- srml/example/src/lib.rs | 2 +- srml/executive/src/lib.rs | 18 +++++------- srml/support/src/dispatch.rs | 15 +++++----- srml/system/src/lib.rs | 4 +++ 9 files changed, 79 insertions(+), 56 deletions(-) diff --git a/core/sr-primitives/src/generic/checked_extrinsic.rs b/core/sr-primitives/src/generic/checked_extrinsic.rs index bd9a711fc0e54..3f73bca07a5f8 100644 --- a/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -22,7 +22,7 @@ use crate::traits::{ self, Member, MaybeDisplay, SignedExtension, DispatchError, Dispatchable, DispatchResult, ValidateUnsigned }; -use crate::weights::{Weighable, Weight}; +use crate::weights::{Weigh, Weight}; use crate::transaction_validity::TransactionValidity; /// Definition of something that the external world might want to say; its @@ -58,11 +58,12 @@ where fn validate>(&self, weight: crate::weights::Weight, + len: usize, ) -> TransactionValidity { if let Some((ref id, ref extra)) = self.signed { - Extra::validate(extra, id, weight).into() + Extra::validate(extra, id, weight, len).into() } else { - match Extra::validate_unsigned(weight) { + match Extra::validate_unsigned(weight, len) { Ok(extra) => match U::validate_unsigned(&self.function) { TransactionValidity::Valid(v) => TransactionValidity::Valid(v.combine_with(extra)), @@ -75,23 +76,24 @@ where fn dispatch(self, weight: crate::weights::Weight, + len: usize, ) -> Result { let maybe_who = if let Some((id, extra)) = self.signed { - Extra::pre_dispatch(extra, &id, weight)?; + Extra::pre_dispatch(extra, &id, weight, len)?; Some(id) } else { - Extra::pre_dispatch_unsigned(weight)?; + Extra::pre_dispatch_unsigned(weight, len)?; None }; Ok(self.function.dispatch(Origin::from(maybe_who))) } } -impl Weighable for CheckedExtrinsic +impl Weigh for CheckedExtrinsic where - Call: Weighable, + Call: Weigh, { - fn weight(&self, len: usize) -> Weight { - self.function.weight(len) + fn weigh(&self) -> Weight { + self.function.weigh() } } diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index a101c3db94212..61e65a21d5b61 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -24,7 +24,7 @@ use crate::traits::{ ValidateUnsigned, SignedExtension, Dispatchable, }; use crate::{generic, KeyTypeId}; -use crate::weights::{Weighable, Weight}; +use crate::weights::{Weigh, Weight}; pub use substrate_primitives::H256; use substrate_primitives::U256; use substrate_primitives::ed25519::{Public as AuthorityId}; @@ -240,7 +240,8 @@ impl Applyable for TestXt where /// Checks to see if this is a valid *transaction*. It returns information on it if so. fn validate>(&self, - _weight: Weight + _weight: Weight, + _len: usize, ) -> TransactionValidity { TransactionValidity::Valid(Default::default()) } @@ -248,22 +249,23 @@ impl Applyable for TestXt where /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. fn dispatch(self, - weight: Weight + weight: Weight, + len: usize, ) -> Result { let maybe_who = if let Some(who) = self.0 { - Extra::pre_dispatch(self.2, &who, weight)?; + Extra::pre_dispatch(self.2, &who, weight, len)?; Some(who) } else { - Extra::pre_dispatch_unsigned(weight)?; + Extra::pre_dispatch_unsigned(weight, len)?; None }; Ok(self.1.dispatch(maybe_who.into())) } } -impl Weighable for TestXt { - fn weight(&self, len: usize) -> Weight { +impl Weigh for TestXt { + fn weigh(&self) -> Weight { // for testing: weight == size. - len as Weight + self.0.using_encoded(|d| d.len() as Weight) } } diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 1afe65fa274b2..0708e561f6c2a 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -826,6 +826,7 @@ pub trait SignedExtension: &self, _who: &Self::AccountId, _weight: crate::weights::Weight, + _len: usize, ) -> Result { Ok(Default::default()) } /// Do any pre-flight stuff for a signed transaction. @@ -833,19 +834,22 @@ pub trait SignedExtension: self, who: &Self::AccountId, weight: crate::weights::Weight, - ) -> Result<(), DispatchError> { self.validate(who, weight).map(|_| ()) } + len: usize, + ) -> Result<(), DispatchError> { self.validate(who, weight, len).map(|_| ()) } /// Validate an unsigned transaction for the transaction queue. Normally the default /// implementation is fine since `ValidateUnsigned` is a better way of recognising and /// validating unsigned transactions. fn validate_unsigned( _weight: crate::weights::Weight, + _len: usize, ) -> Result { Ok(Default::default()) } /// Do any pre-flight stuff for a unsigned transaction. fn pre_dispatch_unsigned( weight: crate::weights::Weight, - ) -> Result<(), DispatchError> { Self::validate_unsigned(weight).map(|_| ()) } + len: usize, + ) -> Result<(), DispatchError> { Self::validate_unsigned(weight, len).map(|_| ()) } } macro_rules! tuple_impl_indexed { @@ -866,28 +870,32 @@ macro_rules! tuple_impl_indexed { &self, who: &Self::AccountId, weight: crate::weights::Weight, + len: usize, ) -> Result { - let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, weight)?),+]; + let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, weight, len)?),+]; Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a))) } fn pre_dispatch( self, who: &Self::AccountId, weight: crate::weights::Weight, + len: usize, ) -> Result<(), DispatchError> { - $(self.$index.pre_dispatch(who, weight)?;)+ + $(self.$index.pre_dispatch(who, weight, len)?;)+ Ok(()) } fn validate_unsigned( weight: crate::weights::Weight, + len: usize, ) -> Result { - let aggregator = vec![$($direct::validate_unsigned(weight)?),+]; + let aggregator = vec![$($direct::validate_unsigned(weight, len)?),+]; Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a))) } fn pre_dispatch_unsigned( weight: crate::weights::Weight, + len: usize, ) -> Result<(), DispatchError> { - $($direct::pre_dispatch_unsigned(weight)?;)+ + $($direct::pre_dispatch_unsigned(weight, len)?;)+ Ok(()) } } @@ -936,13 +944,15 @@ pub trait Applyable: Sized + Send + Sync { /// Checks to see if this is a valid *transaction*. It returns information on it if so. fn validate>(&self, - weight: crate::weights::Weight + weight: crate::weights::Weight, + len: usize, ) -> TransactionValidity; /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. fn dispatch(self, - weight: crate::weights::Weight + weight: crate::weights::Weight, + len: usize, ) -> Result; } diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index 3443992c7396b..fa60737bb89e9 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -18,7 +18,7 @@ //! //! Each dispatch function within `decl_module!` can now have an optional //! `#[weight = $x]` attribute. $x can be any object that implements the -//! `Weighable` trait. By default, All transactions are annotated by +//! `Weigh` trait. By default, All transactions are annotated by //! `#[weight = TransactionWeight::default()]`. //! //! Note that the decl_module macro _cannot_ enforce this and will simply fail @@ -33,20 +33,25 @@ pub type Weight = u32; /// /// Both the outer Call enum and the per-module individual ones will implement this. /// The outer enum simply calls the inner ones based on call type. -pub trait Weighable { - /// Return the weight of this call. - /// The `len` argument is the encoded length of the transaction/call. - fn weight(&self, len: usize) -> Weight; +pub trait Weigh { + /// Return the weight of this call. This is done independently of its encoded size. + fn weigh(&self) -> Weight; +} + +/// Means of weighing some particular kind of data (`T`). +pub trait WeighData { + /// Weigh the data `T` given by `target`. + fn weigh_data(&self, target: T) -> Weight; } /// Default type used as the weight representative in a `#[weight = x]` attribute. /// -/// A user may pass in any other type that implements [`Weighable`]. If not, the `Default` +/// A user may pass in any other type that implements [`Weigh`]. If not, the `Default` /// implementation of [`TransactionWeight`] is used. pub enum TransactionWeight { /// Basic weight (base, byte). /// The values contained are the base weight and byte weight respectively. - Basic(Weight, Weight), + Fixed(Weight), /// Maximum fee. This implies that this transaction _might_ get included but /// no more transaction can be added. This can be done by setting the /// implementation to _maximum block weight_. @@ -56,10 +61,10 @@ pub enum TransactionWeight { Free, } -impl Weighable for TransactionWeight { - fn weight(&self, len: usize) -> Weight { +impl WeighData for TransactionWeight { + fn weigh_data(&self, _: T) -> Weight { match self { - TransactionWeight::Basic(base, byte) => base + byte * len as Weight, + TransactionWeight::Fixed(w) => *w, TransactionWeight::Max => 3 * 1024 * 1024, TransactionWeight::Free => 0, } @@ -68,9 +73,9 @@ impl Weighable for TransactionWeight { impl Default for TransactionWeight { fn default() -> Self { - // This implies that the weight is currently equal to tx-size, nothing more + // This implies that the weight is currently equal to 100, nothing more // for all substrate transactions that do NOT explicitly annotate weight. // TODO #2431 needs to be updated with proper max values. - TransactionWeight::Basic(0, 1) + TransactionWeight::Fixed(1) } } diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index bba3162ab9b5e..24b414ee0a9eb 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -1178,9 +1178,10 @@ impl, I: Instance + Clone + Eq> SignedExtension for TakeFees { &self, who: &Self::AccountId, weight: Weight, + _len: usize, ) -> rstd::result::Result { let fee_x = T::Balance::from(weight); - // TODO: should be weight_to_fee(weight) + // TODO: should be weight_and_size_to_fee(weight, _len) let fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * fee_x; let fee = fee + self.0.clone(); let imbalance = >::withdraw( diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index b2bb0a0af47e4..37d091279e479 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -397,7 +397,7 @@ decl_module! { // If you don't respect these rules, it is likely that your chain will be attackable. // // Each transaction can optionally indicate a weight. The weight is passed in as a - // custom attribute and the value can be anything that implements the `Weighable` + // custom attribute and the value can be anything that implements the `Weigh` // trait. Most often using substrate's default `TransactionWeight` is enough for you. // // A basic weight is a tuple of `(base_weight, byte_weight)`. Upon including each transaction diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index fa08a1017b94f..47422d50f182f 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -86,7 +86,7 @@ use parity_codec::{Codec, Encode}; use system::{extrinsics_root, DigestOf}; use primitives::{ApplyOutcome, ApplyError}; use primitives::transaction_validity::TransactionValidity; -use primitives::weights::Weighable; +use primitives::weights::Weigh; mod internal { use primitives::traits::DispatchError; @@ -141,7 +141,7 @@ impl< > ExecuteBlock for Executive where Block::Extrinsic: Checkable + Codec, - CheckedOf: Applyable + Weighable, + CheckedOf: Applyable + Weigh, CallOf: Dispatchable, OriginOf: From>, UnsignedValidator: ValidateUnsigned>, @@ -160,7 +160,7 @@ impl< > Executive where Block::Extrinsic: Checkable + Codec, - CheckedOf: Applyable + Weighable, + CheckedOf: Applyable + Weigh, CallOf: Dispatchable, OriginOf: From>, UnsignedValidator: ValidateUnsigned>, @@ -284,8 +284,8 @@ where // AUDIT: Under no circumstances may this function panic from here onwards. // Decode parameters and dispatch - let weight = xt.weight(encoded_len); - let r = Applyable::dispatch(xt, weight) + let weight = xt.weigh(); + let r = Applyable::dispatch(xt, weight, encoded_len) .map_err(internal::ApplyError::from)?; >::note_applied_extrinsic(&r, encoded_len as u32); @@ -327,8 +327,7 @@ where const UNKNOWN_ERROR: i8 = -127; const INVALID_INDEX: i8 = -10; - let encoded_len = uxt.encode().len(); - + let encoded_len = uxt.using_encoded(|d| d.len()); let xt = match uxt.check(&Default::default()) { // Checks out. Carry on. Ok(xt) => xt, @@ -340,9 +339,8 @@ where Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR), }; - let weight = xt.weight(encoded_len); - - xt.validate::(weight) + let weight = xt.weigh(); + xt.validate::(weight, encoded_len) } /// Start an offchain worker and generate extrinsics. diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index 00c21a31ba47f..ac5e0604446e4 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -26,7 +26,7 @@ pub use srml_metadata::{ ModuleConstantMetadata, DefaultByte, DefaultByteGetter, }; pub use sr_primitives::{ - weights::{TransactionWeight, Weighable, Weight}, traits::{Dispatchable, DispatchResult} + weights::{TransactionWeight, Weigh, Weight, WeighData}, traits::{Dispatchable, DispatchResult} }; /// A type that cannot be instantiated. @@ -1108,12 +1108,13 @@ macro_rules! decl_module { } // Implement weight calculation function for Call - impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Weighable + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Weigh for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { - fn weight(&self, _len: usize) -> $crate::dispatch::Weight { + fn weigh(&self) -> $crate::dispatch::Weight { match self { - $( $call_type::$fn_name(..) => $crate::dispatch::Weighable::weight(&$weight, _len), )* + $( $call_type::$fn_name($( ref $param_name ),*) => + <$crate::dispatch::WeighData<( $( & $param, )* )>>::weigh_data(&$weight, ($( $param_name, )*)), )* $call_type::__PhantomItem(_, _) => { unreachable!("__PhantomItem should never be used.") }, } } @@ -1260,10 +1261,10 @@ macro_rules! impl_outer_dispatch { $camelcase ( $crate::dispatch::CallableCallFor<$camelcase, $runtime> ) ,)* } - impl $crate::dispatch::Weighable for $call_type { - fn weight(&self, len: usize) -> $crate::dispatch::Weight { + impl $crate::dispatch::Weigh for $call_type { + fn weigh(&self) -> $crate::dispatch::Weight { match self { - $( $call_type::$camelcase(call) => call.weight(len), )* + $( $call_type::$camelcase(call) => call.weigh(), )* } } } diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index be7a3ec492252..897d7c727635f 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -781,6 +781,7 @@ impl SignedExtension for CheckWeight { self, _who: &Self::AccountId, weight: Weight, + _len: usize, ) -> Result<(), DispatchError> { Self::internal_check_weight(weight) } @@ -789,6 +790,7 @@ impl SignedExtension for CheckWeight { &self, _who: &Self::AccountId, _weight: Weight, + _len: usize, ) -> Result { // TODO: check for a maximum size and weight here as well. // write priority based on tx weight type + tip. @@ -839,6 +841,7 @@ impl SignedExtension for CheckNonce { self, who: &Self::AccountId, _weight: Weight, + _len: usize, ) -> Result<(), DispatchError> { let expected = >::get(who); if self.0 != expected { @@ -854,6 +857,7 @@ impl SignedExtension for CheckNonce { &self, who: &Self::AccountId, _weight: Weight, + _len: usize, ) -> Result { // check index let expected = >::get(who); From 342efb514a00a9c877a70564d064e4c72c84db0c Mon Sep 17 00:00:00 2001 From: Kian Peymani Date: Fri, 19 Jul 2019 14:22:14 +0200 Subject: [PATCH 11/33] 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. --- .../src/generic/checked_extrinsic.rs | 22 +- core/sr-primitives/src/testing.rs | 19 +- core/sr-primitives/src/traits.rs | 34 +-- core/sr-primitives/src/weights.rs | 155 +++++++++--- node-template/runtime/src/lib.rs | 3 + node-template/runtime/src/template.rs | 2 + node/executor/src/lib.rs | 1 - node/runtime/src/lib.rs | 4 +- srml/assets/src/lib.rs | 2 + srml/aura/src/mock.rs | 2 + srml/authorship/src/lib.rs | 2 + srml/balances/src/lib.rs | 63 +++-- srml/balances/src/mock.rs | 14 +- srml/balances/src/tests.rs | 28 ++- srml/collective/src/lib.rs | 2 + srml/contracts/src/tests.rs | 2 + srml/council/src/lib.rs | 2 + srml/democracy/src/lib.rs | 2 + srml/elections/src/lib.rs | 2 + srml/example/src/lib.rs | 27 +- srml/executive/src/lib.rs | 99 ++++---- srml/finality-tracker/src/lib.rs | 2 + srml/generic-asset/src/lib.rs | 2 + srml/generic-asset/src/mock.rs | 4 + srml/grandpa/src/mock.rs | 2 + srml/indices/src/mock.rs | 2 + srml/session/src/mock.rs | 2 + srml/staking/src/mock.rs | 2 + srml/support/Cargo.toml | 2 +- srml/support/src/dispatch.rs | 75 ++++-- srml/system/src/lib.rs | 238 ++++++++++++++---- srml/timestamp/src/lib.rs | 2 + srml/treasury/src/lib.rs | 2 + 33 files changed, 599 insertions(+), 223 deletions(-) diff --git a/core/sr-primitives/src/generic/checked_extrinsic.rs b/core/sr-primitives/src/generic/checked_extrinsic.rs index 3f73bca07a5f8..04ccd1162c6c6 100644 --- a/core/sr-primitives/src/generic/checked_extrinsic.rs +++ b/core/sr-primitives/src/generic/checked_extrinsic.rs @@ -22,7 +22,7 @@ use crate::traits::{ self, Member, MaybeDisplay, SignedExtension, DispatchError, Dispatchable, DispatchResult, ValidateUnsigned }; -use crate::weights::{Weigh, Weight}; +use crate::weights::{GetDispatchInfo, DispatchInfo}; use crate::transaction_validity::TransactionValidity; /// Definition of something that the external world might want to say; its @@ -57,13 +57,13 @@ where } fn validate>(&self, - weight: crate::weights::Weight, + info: DispatchInfo, len: usize, ) -> TransactionValidity { if let Some((ref id, ref extra)) = self.signed { - Extra::validate(extra, id, weight, len).into() + Extra::validate(extra, id, info, len).into() } else { - match Extra::validate_unsigned(weight, len) { + match Extra::validate_unsigned(info, len) { Ok(extra) => match U::validate_unsigned(&self.function) { TransactionValidity::Valid(v) => TransactionValidity::Valid(v.combine_with(extra)), @@ -75,25 +75,25 @@ where } fn dispatch(self, - weight: crate::weights::Weight, + info: DispatchInfo, len: usize, ) -> Result { let maybe_who = if let Some((id, extra)) = self.signed { - Extra::pre_dispatch(extra, &id, weight, len)?; + Extra::pre_dispatch(extra, &id, info, len)?; Some(id) } else { - Extra::pre_dispatch_unsigned(weight, len)?; + Extra::pre_dispatch_unsigned(info, len)?; None }; Ok(self.function.dispatch(Origin::from(maybe_who))) } } -impl Weigh for CheckedExtrinsic +impl GetDispatchInfo for CheckedExtrinsic where - Call: Weigh, + Call: GetDispatchInfo, { - fn weigh(&self) -> Weight { - self.function.weigh() + fn get_dispatch_info(&self) -> DispatchInfo { + self.function.get_dispatch_info() } } diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 61e65a21d5b61..75f940eb313ad 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -24,7 +24,7 @@ use crate::traits::{ ValidateUnsigned, SignedExtension, Dispatchable, }; use crate::{generic, KeyTypeId}; -use crate::weights::{Weigh, Weight}; +use crate::weights::{GetDispatchInfo, DispatchInfo}; pub use substrate_primitives::H256; use substrate_primitives::U256; use substrate_primitives::ed25519::{Public as AuthorityId}; @@ -240,7 +240,7 @@ impl Applyable for TestXt where /// Checks to see if this is a valid *transaction*. It returns information on it if so. fn validate>(&self, - _weight: Weight, + _info: DispatchInfo, _len: usize, ) -> TransactionValidity { TransactionValidity::Valid(Default::default()) @@ -249,23 +249,26 @@ impl Applyable for TestXt where /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. fn dispatch(self, - weight: Weight, + info: DispatchInfo, len: usize, ) -> Result { let maybe_who = if let Some(who) = self.0 { - Extra::pre_dispatch(self.2, &who, weight, len)?; + Extra::pre_dispatch(self.2, &who, info, len)?; Some(who) } else { - Extra::pre_dispatch_unsigned(weight, len)?; + Extra::pre_dispatch_unsigned(info, len)?; None }; Ok(self.1.dispatch(maybe_who.into())) } } -impl Weigh for TestXt { - fn weigh(&self) -> Weight { +impl GetDispatchInfo for TestXt { + fn get_dispatch_info(&self) -> DispatchInfo { // for testing: weight == size. - self.0.using_encoded(|d| d.len() as Weight) + DispatchInfo { + weight: self.encode().len() as u32, + ..Default::default() + } } } diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 0708e561f6c2a..3539e2fcfd814 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -25,6 +25,7 @@ use substrate_primitives::{self, Hasher, Blake2Hasher}; use crate::codec::{Codec, Encode, Decode, HasCompact}; use crate::transaction_validity::{ValidTransaction, TransactionValidity}; use crate::generic::{Digest, DigestItem}; +use crate::weights::DispatchInfo; pub use substrate_primitives::crypto::TypedKey; pub use integer_sqrt::IntegerSquareRoot; pub use num_traits::{ @@ -752,6 +753,7 @@ impl Checkable for T { /// An abstract error concerning an attempt to verify, check or dispatch the transaction. This /// cannot be more concrete because it's designed to work reasonably well over a broad range of /// possible transaction types. +#[cfg_attr(feature = "std", derive(Debug))] pub enum DispatchError { /// General error to do with the inability to pay some fees (e.g. account balance too low). Payment, @@ -825,7 +827,7 @@ pub trait SignedExtension: fn validate( &self, _who: &Self::AccountId, - _weight: crate::weights::Weight, + _info: DispatchInfo, _len: usize, ) -> Result { Ok(Default::default()) } @@ -833,23 +835,23 @@ pub trait SignedExtension: fn pre_dispatch( self, who: &Self::AccountId, - weight: crate::weights::Weight, + info: DispatchInfo, len: usize, - ) -> Result<(), DispatchError> { self.validate(who, weight, len).map(|_| ()) } + ) -> Result<(), DispatchError> { self.validate(who, info, len).map(|_| ()) } /// Validate an unsigned transaction for the transaction queue. Normally the default /// implementation is fine since `ValidateUnsigned` is a better way of recognising and /// validating unsigned transactions. fn validate_unsigned( - _weight: crate::weights::Weight, + _info: DispatchInfo, _len: usize, ) -> Result { Ok(Default::default()) } /// Do any pre-flight stuff for a unsigned transaction. fn pre_dispatch_unsigned( - weight: crate::weights::Weight, + info: DispatchInfo, len: usize, - ) -> Result<(), DispatchError> { Self::validate_unsigned(weight, len).map(|_| ()) } + ) -> Result<(), DispatchError> { Self::validate_unsigned(info, len).map(|_| ()) } } macro_rules! tuple_impl_indexed { @@ -869,33 +871,33 @@ macro_rules! tuple_impl_indexed { fn validate( &self, who: &Self::AccountId, - weight: crate::weights::Weight, + info: DispatchInfo, len: usize, ) -> Result { - let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, weight, len)?),+]; + let aggregator = vec![$(<$direct as SignedExtension>::validate(&self.$index, who, info, len)?),+]; Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a))) } fn pre_dispatch( self, who: &Self::AccountId, - weight: crate::weights::Weight, + info: DispatchInfo, len: usize, ) -> Result<(), DispatchError> { - $(self.$index.pre_dispatch(who, weight, len)?;)+ + $(self.$index.pre_dispatch(who, info, len)?;)+ Ok(()) } fn validate_unsigned( - weight: crate::weights::Weight, + info: DispatchInfo, len: usize, ) -> Result { - let aggregator = vec![$($direct::validate_unsigned(weight, len)?),+]; + let aggregator = vec![$($direct::validate_unsigned(info, len)?),+]; Ok(aggregator.into_iter().fold(ValidTransaction::default(), |acc, a| acc.combine_with(a))) } fn pre_dispatch_unsigned( - weight: crate::weights::Weight, + info: DispatchInfo, len: usize, ) -> Result<(), DispatchError> { - $($direct::pre_dispatch_unsigned(weight, len)?;)+ + $($direct::pre_dispatch_unsigned(info, len)?;)+ Ok(()) } } @@ -944,14 +946,14 @@ pub trait Applyable: Sized + Send + Sync { /// Checks to see if this is a valid *transaction*. It returns information on it if so. fn validate>(&self, - weight: crate::weights::Weight, + info: DispatchInfo, len: usize, ) -> TransactionValidity; /// Executes all necessary logic needed prior to dispatch and deconstructs into function call, /// index and sender. fn dispatch(self, - weight: crate::weights::Weight, + info: DispatchInfo, len: usize, ) -> Result; } diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index fa60737bb89e9..872a091a84523 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -16,26 +16,78 @@ //! Primitives for transaction weighting. //! -//! Each dispatch function within `decl_module!` can now have an optional -//! `#[weight = $x]` attribute. $x can be any object that implements the -//! `Weigh` trait. By default, All transactions are annotated by -//! `#[weight = TransactionWeight::default()]`. +//! Each dispatch function within `decl_module!` can have an optional `#[weight = $x]` attribute. +//! `$x` can be any type that implements the `ClassifyDispatch` and `WeighData` traits. By +//! default, All transactions are annotated with `#[weight = SimpleDispatchInfo::default()]`. //! //! Note that the decl_module macro _cannot_ enforce this and will simply fail //! if an invalid struct is passed in. -/// The final type that each `#[weight = $x:expr]`'s -/// expression must evaluate to. +pub use crate::transaction_validity::TransactionPriority; +use crate::traits::Bounded; + +/// Numeric range of a transaction weight. pub type Weight = u32; -/// A `Call` enum (aka transaction) that can be weighted using the custom weight attribute of -/// its dispatchable functions. Is implemented by default in the `decl_module!`. -/// -/// Both the outer Call enum and the per-module individual ones will implement this. -/// The outer enum simply calls the inner ones based on call type. -pub trait Weigh { - /// Return the weight of this call. This is done independently of its encoded size. - fn weigh(&self) -> Weight; +/// A broad range of dispatch types. This is only distinguishing normal, user-triggered transactions +/// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`). +#[cfg_attr(feature = "std", derive(Debug))] +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum DispatchClass { + /// A normal dispatch. + Normal, + /// An operational dispatch. + Operational, +} + +impl Default for DispatchClass { + fn default() -> Self { + DispatchClass::Normal + } +} + +impl From for DispatchClass { + fn from(tx: SimpleDispatchInfo) -> Self { + match tx { + SimpleDispatchInfo::FixedOperational(_) => DispatchClass::Operational, + SimpleDispatchInfo::MaxOperational => DispatchClass::Operational, + SimpleDispatchInfo::FreeOperational => DispatchClass::Operational, + + SimpleDispatchInfo::FixedNormal(_) => DispatchClass::Normal, + SimpleDispatchInfo::MaxNormal => DispatchClass::Normal, + SimpleDispatchInfo::FreeNormal => DispatchClass::Normal, + } + } +} + +/// A bundle of static information collected from the `#[weight = $x]` attributes. +#[cfg_attr(feature = "std", derive(PartialEq, Eq, Debug))] +#[derive(Clone, Copy, Default)] +pub struct DispatchInfo { + /// Weight of this transaction. + pub weight: Weight, + /// Class of this transaction. + pub class: DispatchClass, +} + +impl DispatchInfo { + /// Determine if this dispatch should pay the base length-related fee or not. + pub fn pay_length_fee(&self) -> bool { + match self.class { + DispatchClass::Normal => true, + // For now we assume all operational transactions don't pay the length fee. + DispatchClass::Operational => false, + } + } +} + +/// A `Dispatchable` function (aka transaction) that can carry some static information along with it, using the +/// `#[weight]` attribute. +pub trait GetDispatchInfo { + /// Return a `DispatchInfo`, containing relevant information of this dispatch. + /// + /// This is done independently of its encoded size. + fn get_dispatch_info(&self) -> DispatchInfo; } /// Means of weighing some particular kind of data (`T`). @@ -44,38 +96,73 @@ pub trait WeighData { fn weigh_data(&self, target: T) -> Weight; } -/// Default type used as the weight representative in a `#[weight = x]` attribute. +/// Means of classifying a dispatchable function. +pub trait ClassifyDispatch { + /// Classify the dispatch function based on input data `target` of type `T`. + fn classify_dispatch(&self, target: T) -> DispatchClass; +} + +/// Default type used with the `#[weight = x]` attribute in a substrate chain. /// -/// A user may pass in any other type that implements [`Weigh`]. If not, the `Default` -/// implementation of [`TransactionWeight`] is used. -pub enum TransactionWeight { - /// Basic weight (base, byte). - /// The values contained are the base weight and byte weight respectively. - Fixed(Weight), - /// Maximum fee. This implies that this transaction _might_ get included but - /// no more transaction can be added. This can be done by setting the - /// implementation to _maximum block weight_. - Max, - /// Free. The transaction does not increase the total weight - /// (i.e. is not included in weight calculation). - Free, +/// A user may pass in any other type that implements the correct traits. If not, the `Default` +/// implementation of [`SimpleDispatchInfo`] is used. +/// +/// For each broad group (`Normal` and `Operation`): +/// - A `Fixed` variant means weight fee is charged normally and the weight is the number +/// specified in the inner value of the variant. +/// - A `Free` variant is equal to `::Fixed(0)`. Note that this does not guarantee inclusion. +/// - A `Max` variant is equal to `::Fixed(Weight::max_value())`. +/// +/// Based on the final weight value, based on the above variants: +/// - A _weight-fee_ is deducted. +/// - The block weight is consumed proportionally. +/// +/// As for the broad groups themselves: +/// - `Normal` variants will be assigned a priority proportional to their weight. They can only +/// consume a portion (1/4) of the maximum block resource limits. +/// - `Operational` variants will be assigned the maximum priority. They can potentially consume +/// the entire block resource limit. +#[derive(Clone, Copy)] +pub enum SimpleDispatchInfo { + /// A normal dispatch with fixed weight. + FixedNormal(Weight), + /// A normal dispatch with the maximum weight. + MaxNormal, + /// A normal dispatch with no weight. + FreeNormal, + /// An operational dispatch with fixed weight. + FixedOperational(Weight), + /// An operational dispatch with the maximum weight. + MaxOperational, + /// An operational dispatch with no weight. + FreeOperational, } -impl WeighData for TransactionWeight { +impl WeighData for SimpleDispatchInfo { fn weigh_data(&self, _: T) -> Weight { match self { - TransactionWeight::Fixed(w) => *w, - TransactionWeight::Max => 3 * 1024 * 1024, - TransactionWeight::Free => 0, + SimpleDispatchInfo::FixedNormal(w) => *w, + SimpleDispatchInfo::MaxNormal => Bounded::max_value(), + SimpleDispatchInfo::FreeNormal => Bounded::min_value(), + + SimpleDispatchInfo::FixedOperational(w) => *w, + SimpleDispatchInfo::MaxOperational => Bounded::max_value(), + SimpleDispatchInfo::FreeOperational => Bounded::min_value(), } } } -impl Default for TransactionWeight { +impl ClassifyDispatch for SimpleDispatchInfo { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::from(*self) + } +} + +impl Default for SimpleDispatchInfo { fn default() -> Self { // This implies that the weight is currently equal to 100, nothing more // for all substrate transactions that do NOT explicitly annotate weight. // TODO #2431 needs to be updated with proper max values. - TransactionWeight::Fixed(1) + SimpleDispatchInfo::FixedNormal(1) } } diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 92e64e2ea9ca9..b86af75ea8c8b 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -113,6 +113,7 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const BlockHashCount: BlockNumber = 250; pub const MaximumBlockWeight: Weight = 4 * 1024 * 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Runtime { @@ -138,6 +139,8 @@ impl system::Trait for Runtime { type BlockHashCount = BlockHashCount; /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. type MaximumBlockWeight = MaximumBlockWeight; + /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. + type MaximumBlockLength = MaximumBlockLength; } impl aura::Trait for Runtime { diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index 97466d2b6dce5..961ffaea4ffa6 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -87,6 +87,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -100,6 +101,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } impl Trait for Test { type Event = (); diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 0f61a4ceade53..5e142a64b681f 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -80,7 +80,6 @@ mod tests { type TestExternalities = CoreTestExternalities; - // TODO: fix for being charged based on weight now. fn transfer_fee(extrinsic: &E) -> Balance { >::get() + >::get() * diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 97a265c1f9b0a..2c652a027785e 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -112,7 +112,8 @@ pub const DAYS: Moment = HOURS * 24; parameter_types! { pub const BlockHashCount: BlockNumber = 250; - pub const MaximumBlockWeight: Weight = 4 * 1024 * 1024; + pub const MaximumBlockWeight: Weight = 4 * 1024; + pub const MaximumBlockLength: u32 = 4 * 1024 * 1024; } impl system::Trait for Runtime { @@ -127,6 +128,7 @@ impl system::Trait for Runtime { type Event = Event; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } impl aura::Trait for Runtime { diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index 1e4c06700abe1..962f4cfb4f0e0 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -258,6 +258,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -271,6 +272,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } impl Trait for Test { type Event = (); diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index 7664405eb37e3..ffa0385761c68 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -38,6 +38,7 @@ pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; pub const MinimumPeriod: u64 = 1; } @@ -53,6 +54,7 @@ impl system::Trait for Test { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } impl timestamp::Trait for Test { diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index 5ba82f5daf2c2..8561a8428303b 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -338,6 +338,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { @@ -352,6 +353,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } impl Trait for Test { diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 24b414ee0a9eb..b8a0ffe6c51cc 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -156,13 +156,15 @@ use srml_support::{StorageValue, StorageMap, Parameter, decl_event, decl_storage use srml_support::traits::{ UpdateBalanceOutcome, Currency, OnFreeBalanceZero, OnUnbalanced, WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, - Imbalance, SignedImbalance, ReservableCurrency + Imbalance, SignedImbalance, ReservableCurrency, Get, }; -use srml_support::{dispatch::Result, traits::Get}; -use primitives::{transaction_validity::TransactionPriority, traits::{ - Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, - MaybeSerializeDebug, Saturating, Bounded, SignedExtension -}}; +use srml_support::dispatch::Result; +use primitives::traits::{ + Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDebug, + Saturating, Bounded, SignedExtension, SaturatedConversion, DispatchError +}; +use primitives::transaction_validity::{TransactionPriority, ValidTransaction}; +use primitives::weights::DispatchInfo; use system::{IsDeadAccount, OnNewAccount, ensure_signed, ensure_root}; mod mock; @@ -762,6 +764,7 @@ impl, I: Instance> system::Trait for ElevatedTrait { type Event = (); type BlockHashCount = T::BlockHashCount; type MaximumBlockWeight = T::MaximumBlockWeight; + type MaximumBlockLength = T::MaximumBlockLength; } impl, I: Instance> Trait for ElevatedTrait { type Balance = T::Balance; @@ -1150,12 +1153,38 @@ where #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct TakeFees, I: Instance = DefaultInstance>(#[codec(compact)] T::Balance); -#[cfg(feature = "std")] impl, I: Instance> TakeFees { /// utility constructor. Used only in client/factory code. + #[cfg(feature = "std")] pub fn from(fee: T::Balance) -> Self { Self(fee) } + + /// Compute the final fee value for a particular transaction. + /// + /// The final fee is composed of: + /// - _length-fee_: This is the amount paid merely to pay for size of the transaction. + /// - _weight-fee_: This amount is computed based on the weight of the transaction. Unlike + /// size-fee, this is not input dependent and reflects the _complexity_ of the execution + /// and the time it consumes. + /// - (optional) _tip_: if included in the transaction, it will be added on top. Only signed + /// transactions can have a tip. + fn compute_fee(len: usize, info: DispatchInfo, tip: T::Balance) -> T::Balance { + // length fee + let len_fee = if info.pay_length_fee() { + let len = T::Balance::from(len as u32); + let base = T::TransactionBaseFee::get(); + let byte = T::TransactionByteFee::get(); + base.saturating_add(byte.saturating_mul(len)) + } else { + Zero::zero() + }; + + // weight fee + let _weight_fee = T::Balance::from(0); // TODO: should be weight_and_size_to_fee(weight, _len) #2854 + + len_fee.saturating_add(_weight_fee).saturating_add(tip) + } } #[cfg(feature = "std")] @@ -1165,10 +1194,6 @@ impl, I: Instance> rstd::fmt::Debug for TakeFees { } } -use primitives::traits::{DispatchError, SaturatedConversion}; -use primitives::transaction_validity::ValidTransaction; -use primitives::weights::Weight; - impl, I: Instance + Clone + Eq> SignedExtension for TakeFees { type AccountId = T::AccountId; type AdditionalSigned = (); @@ -1177,22 +1202,22 @@ impl, I: Instance + Clone + Eq> SignedExtension for TakeFees { fn validate( &self, who: &Self::AccountId, - weight: Weight, - _len: usize, + info: DispatchInfo, + len: usize, ) -> rstd::result::Result { - let fee_x = T::Balance::from(weight); - // TODO: should be weight_and_size_to_fee(weight, _len) - let fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * fee_x; - let fee = fee + self.0.clone(); + // pay any fees. + let fee = Self::compute_fee(len, info, self.0); let imbalance = >::withdraw( who, - fee.clone(), + fee, WithdrawReason::TransactionPayment, - ExistenceRequirement::KeepAlive + ExistenceRequirement::KeepAlive, ).map_err(|_| DispatchError::Payment)?; T::TransactionPayment::on_unbalanced(imbalance); let mut r = ValidTransaction::default(); + // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which + // will be a bit more than setting the priority to tip. For now, this is enough. r.priority = fee.saturated_into::(); Ok(r) } diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index 3fb29058439d5..12eae9724172e 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -18,10 +18,11 @@ #![cfg(test)] -use primitives::{traits::{IdentityLookup}, testing::Header}; +use primitives::{traits::{IdentityLookup}, testing::Header, weights::{DispatchInfo, Weight}}; use substrate_primitives::{H256, Blake2Hasher}; use runtime_io; -use srml_support::{impl_outer_origin, parameter_types, traits::Get}; +use srml_support::{impl_outer_origin, parameter_types}; +use srml_support::traits::Get; use std::cell::RefCell; use crate::{GenesisConfig, Module, Trait}; @@ -34,7 +35,7 @@ thread_local! { static TRANSFER_FEE: RefCell = RefCell::new(0); static CREATION_FEE: RefCell = RefCell::new(0); static TRANSACTION_BASE_FEE: RefCell = RefCell::new(0); - static TRANSACTION_BYTE_FEE: RefCell = RefCell::new(0); + static TRANSACTION_BYTE_FEE: RefCell = RefCell::new(1); } pub struct ExistentialDeposit; @@ -68,6 +69,7 @@ pub struct Runtime; parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Runtime { type Origin = Origin; @@ -81,6 +83,7 @@ impl system::Trait for Runtime { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } impl Trait for Runtime { type Balance = u64; @@ -187,3 +190,8 @@ impl ExtBuilder { pub type System = system::Module; pub type Balances = Module; + +/// create a transaction info struct from weight. Handy to avoid building the whole struct. +pub fn info_from_weight(w: Weight) -> DispatchInfo { + DispatchInfo { weight: w, ..Default::default() } +} diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 2174176b7af5c..2828d40e63ff8 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -19,7 +19,7 @@ #![cfg(test)] use super::*; -use mock::{Balances, ExtBuilder, Runtime, System}; +use mock::{Balances, ExtBuilder, Runtime, System, info_from_weight}; use runtime_io::with_externalities; use srml_support::{ assert_noop, assert_ok, assert_err, @@ -124,7 +124,12 @@ fn lock_reasons_should_work() { ); assert_ok!(>::reserve(&1, 1)); // NOTE: this causes a fee payment. - assert!( as SignedExtension>::validate(&TakeFees::from(1), &1, 1).is_ok()); + assert!( as SignedExtension>::pre_dispatch( + TakeFees::from(1), + &1, + info_from_weight(1), + 0, + ).is_ok()); Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Reserve.into()); assert_ok!(>::transfer(&1, &2, 1)); @@ -132,12 +137,22 @@ fn lock_reasons_should_work() { >::reserve(&1, 1), "account liquidity restrictions prevent withdrawal" ); - assert!( as SignedExtension>::validate(&TakeFees::from(1), &1, 1).is_ok()); + assert!( as SignedExtension>::pre_dispatch( + TakeFees::from(1), + &1, + info_from_weight(1), + 0, + ).is_ok()); Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::TransactionPayment.into()); assert_ok!(>::transfer(&1, &2, 1)); assert_ok!(>::reserve(&1, 1)); - assert!( as SignedExtension>::validate(&TakeFees::from(1), &1, 1).is_err()); + assert!( as SignedExtension>::pre_dispatch( + TakeFees::from(1), + &1, + info_from_weight(1), + 0, + ).is_err()); } ); } @@ -741,9 +756,10 @@ fn signed_extension_take_fees_work() { .monied(true) .build(), || { - assert!(TakeFees::::from(0).validate(&1, 10).is_ok()); + let len = 10; + assert!(TakeFees::::from(0).pre_dispatch(&1, info_from_weight(0), len).is_ok()); assert_eq!(Balances::free_balance(&1), 100 - 20); - assert!(TakeFees::::from(5 /* tipped */).validate(&1, 10).is_ok()); + assert!(TakeFees::::from(5 /* tipped */).pre_dispatch(&1, info_from_weight(0), len).is_ok()); assert_eq!(Balances::free_balance(&1), 100 - 20 - 25); } ); diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index b7f57cd1234b2..c2d146e0b6484 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -400,6 +400,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -413,6 +414,7 @@ mod tests { type Event = Event; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } impl Trait for Test { type Origin = Origin; diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index 785840e9352c6..ffc7b9998d191 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -97,6 +97,7 @@ pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -110,6 +111,7 @@ impl system::Trait for Test { type Event = MetaEvent; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } parameter_types! { pub const BalancesTransactionBaseFee: u64 = 0; diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index 1baeb6fdfd34b..72feead5e1e33 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -99,6 +99,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -112,6 +113,7 @@ mod tests { type Event = Event; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } parameter_types! { pub const ExistentialDeposit: u64 = 0; diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index 5c49f9519013d..ab5d068928258 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -999,6 +999,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -1012,6 +1013,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } parameter_types! { pub const ExistentialDeposit: u64 = 0; diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index a1c139349ccee..1060c7b9a7bf0 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -1109,6 +1109,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -1122,6 +1123,7 @@ mod tests { type Event = Event; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } parameter_types! { pub const ExistentialDeposit: u64 = 0; diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index 37d091279e479..cd93d3a6b0735 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -255,7 +255,7 @@ use srml_support::{StorageValue, dispatch::Result, decl_module, decl_storage, decl_event}; use system::{ensure_signed, ensure_root}; -use sr_primitives::weights::TransactionWeight; +use sr_primitives::weights::SimpleDispatchInfo; /// Our module's configuration trait. All our types and consts go in here. If the /// module is dependent on specific other modules, then their configuration traits @@ -396,19 +396,18 @@ decl_module! { // // If you don't respect these rules, it is likely that your chain will be attackable. // - // Each transaction can optionally indicate a weight. The weight is passed in as a - // custom attribute and the value can be anything that implements the `Weigh` - // trait. Most often using substrate's default `TransactionWeight` is enough for you. + // Each transaction can define an optional `#[weight]` attribute to convey a set of static + // information about its dispatch. The `system` and `executive` module then use this + // information to properly execute the transaction, whilst keeping the total load of the + // chain in a moderate rate. // - // A basic weight is a tuple of `(base_weight, byte_weight)`. Upon including each transaction - // in a block, the final weight is calculated as `base_weight + byte_weight * tx_size`. - // If this value, added to the weight of all included transactions, exceeds `MAX_TRANSACTION_WEIGHT`, - // the transaction is not included. If no weight attribute is provided, the `::default()` - // implementation of `TransactionWeight` is used. - // - // The example below showcases a transaction which is relatively costly, but less dependent on - // the input, hence `byte_weight` is configured smaller. - #[weight = TransactionWeight::Basic(100_000, 10)] + // The _right-hand-side_ value of the `#[weight]` attribute can be any type that implements + // a set of traits, namely [`WeighData`] and [`ClassifyDispatch`]. The former conveys the + // weight (a numeric representation of pure execution time and difficulty) of the + // transaction and the latter demonstrates the `DispatchClass` of the call. A higher weight + // means a larger transaction (less of which can be placed in a single block). See the + // `CheckWeight` signed extension struct in the `system` module for more information. + #[weight = SimpleDispatchInfo::FixedNormal(10_000)] fn accumulate_dummy(origin, increase_by: T::Balance) -> Result { // This is a public call, so we ensure that the origin is some signed account. let _sender = ensure_signed(origin)?; @@ -526,6 +525,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -539,6 +539,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } parameter_types! { pub const ExistentialDeposit: u64 = 0; diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 47422d50f182f..0b2d9142a7d11 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -86,7 +86,7 @@ use parity_codec::{Codec, Encode}; use system::{extrinsics_root, DigestOf}; use primitives::{ApplyOutcome, ApplyError}; use primitives::transaction_validity::TransactionValidity; -use primitives::weights::Weigh; +use primitives::weights::GetDispatchInfo; mod internal { use primitives::traits::DispatchError; @@ -141,7 +141,7 @@ impl< > ExecuteBlock for Executive where Block::Extrinsic: Checkable + Codec, - CheckedOf: Applyable + Weigh, + CheckedOf: Applyable + GetDispatchInfo, CallOf: Dispatchable, OriginOf: From>, UnsignedValidator: ValidateUnsigned>, @@ -160,7 +160,7 @@ impl< > Executive where Block::Extrinsic: Checkable + Codec, - CheckedOf: Applyable + Weigh, + CheckedOf: Applyable + GetDispatchInfo, CallOf: Dispatchable, OriginOf: From>, UnsignedValidator: ValidateUnsigned>, @@ -284,8 +284,8 @@ where // AUDIT: Under no circumstances may this function panic from here onwards. // Decode parameters and dispatch - let weight = xt.weigh(); - let r = Applyable::dispatch(xt, weight, encoded_len) + let dispatch_info = xt.get_dispatch_info(); + let r = Applyable::dispatch(xt, dispatch_info, encoded_len) .map_err(internal::ApplyError::from)?; >::note_applied_extrinsic(&r, encoded_len as u32); @@ -339,8 +339,8 @@ where Err(_) => return TransactionValidity::Invalid(UNKNOWN_ERROR), }; - let weight = xt.weigh(); - xt.validate::(weight, encoded_len) + let dispatch_info = xt.get_dispatch_info(); + xt.validate::(dispatch_info, encoded_len) } /// Start an offchain worker and generate extrinsics. @@ -380,6 +380,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Runtime { type Origin = Origin; @@ -393,6 +394,7 @@ mod tests { type Event = MetaEvent; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } parameter_types! { pub const ExistentialDeposit: u64 = 0; @@ -548,57 +550,60 @@ mod tests { #[test] fn block_weight_limit_enforced() { - let run_test = |should_fail: bool| { - let mut t = new_test_ext(); - let xt = primitives::testing::TestXt(Some(1), Call::transfer(33, 69), extra(0, 0)); - let xt2 = primitives::testing::TestXt(Some(1), Call::transfer(33, 69), extra(1, 0)); - let encoded = xt2.encode(); - let len = if should_fail { ( ::MaximumBlockWeight::get() - 1) as usize } else { encoded.len() }; - let encoded_len = encoded.len() as u32; - with_externalities(&mut t, || { - Executive::initialize_block(&Header::new( - 1, - H256::default(), - H256::default(), - [69u8; 32].into(), - Digest::default(), - )); - assert_eq!(>::all_extrinsics_weight(), 0); - - Executive::apply_extrinsic(xt).unwrap(); - let res = Executive::apply_extrinsic_with_len(xt2, len, Some(encoded)); - - if should_fail { - assert!(res.is_err()); - assert_eq!(>::all_extrinsics_weight(), encoded_len); - assert_eq!(>::extrinsic_index(), Some(1)); + let mut t = new_test_ext(); + // given: TestXt uses the encoded len as fixed Len: + let xt = primitives::testing::TestXt(Some(1), Call::transfer::(33, 0), extra(0, 0)); + let encoded = xt.encode(); + let encoded_len = encoded.len() as u32; + let limit = >::get() / 4; + let num_to_exhaust_block = limit / encoded_len; + with_externalities(&mut t, || { + Executive::initialize_block(&Header::new( + 1, + H256::default(), + H256::default(), + [69u8; 32].into(), + Digest::default(), + )); + assert_eq!(>::all_extrinsics_weight(), 0); + + for nonce in 0..=num_to_exhaust_block { + let xt = primitives::testing::TestXt(Some(1), Call::transfer::(33, 0), extra(nonce.into(), 0)); + let res = Executive::apply_extrinsic(xt); + if nonce != num_to_exhaust_block { + assert_eq!(res.unwrap(), ApplyOutcome::Success); + assert_eq!(>::all_extrinsics_weight(), encoded_len * (nonce + 1)); + assert_eq!(>::extrinsic_index(), Some(nonce + 1)); } else { - assert!(res.is_ok()); - assert_eq!(>::all_extrinsics_weight(), encoded_len * 2); - assert_eq!(>::extrinsic_index(), Some(2)); + assert_eq!(res, Err(ApplyError::CantPay)); } - }); - }; - - run_test(false); - run_test(true); + } + }); } #[test] - fn default_block_weight_is_stored() { + fn block_weight_and_size_is_stored_per_tx() { let xt = primitives::testing::TestXt(Some(1), Call::transfer(33, 0), extra(0, 0)); let x1 = primitives::testing::TestXt(Some(1), Call::transfer(33, 0), extra(1, 0)); let x2 = primitives::testing::TestXt(Some(1), Call::transfer(33, 0), extra(2, 0)); let len = xt.clone().encode().len() as u32; let mut t = new_test_ext(); with_externalities(&mut t, || { - Executive::apply_extrinsic(xt.clone()).unwrap(); - Executive::apply_extrinsic(x1.clone()).unwrap(); - Executive::apply_extrinsic(x2.clone()).unwrap(); - assert_eq!( - >::all_extrinsics_weight(), - 3 * (0 /*base*/ + len /*len*/ * 1 /*byte*/) - ); + assert_eq!(>::all_extrinsics_weight(), 0); + assert_eq!(>::all_extrinsics_weight(), 0); + + assert_eq!(Executive::apply_extrinsic(xt.clone()).unwrap(), ApplyOutcome::Success); + assert_eq!(Executive::apply_extrinsic(x1.clone()).unwrap(), ApplyOutcome::Success); + assert_eq!(Executive::apply_extrinsic(x2.clone()).unwrap(), ApplyOutcome::Success); + + // default weight for `TestXt` == encoded length. + assert_eq!( >::all_extrinsics_weight(), 3 * len); + assert_eq!(>::all_extrinsics_len(), 3 * len); + + let _ = >::finalize(); + + assert_eq!(>::all_extrinsics_weight(), 0); + assert_eq!(>::all_extrinsics_weight(), 0); }); } diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs index 2e17d9688f1c9..b6d59be474972 100644 --- a/srml/finality-tracker/src/lib.rs +++ b/srml/finality-tracker/src/lib.rs @@ -300,6 +300,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -313,6 +314,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } parameter_types! { pub const WindowSize: u64 = 11; diff --git a/srml/generic-asset/src/lib.rs b/srml/generic-asset/src/lib.rs index 60370600a69a6..d4a341c6ffd90 100644 --- a/srml/generic-asset/src/lib.rs +++ b/srml/generic-asset/src/lib.rs @@ -1056,6 +1056,8 @@ impl system::Trait for ElevatedTrait { type Lookup = T::Lookup; type Header = T::Header; type Event = (); + type MaximumBlockWeight = T::MaximumBlockWeight; + type MaximumBlockLength = T::MaximumBlockLength; type BlockHashCount = T::BlockHashCount; } impl Trait for ElevatedTrait { diff --git a/srml/generic-asset/src/mock.rs b/srml/generic-asset/src/mock.rs index 02e18fc335839..04c5b2d2ce157 100644 --- a/srml/generic-asset/src/mock.rs +++ b/srml/generic-asset/src/mock.rs @@ -40,6 +40,8 @@ impl_outer_origin! { pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -51,6 +53,8 @@ impl system::Trait for Test { type Lookup = IdentityLookup; type Header = Header; type Event = TestEvent; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; type BlockHashCount = BlockHashCount; } diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index 1420d65eb5576..71992655d1450 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -44,6 +44,7 @@ impl Trait for Test { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -57,6 +58,7 @@ impl system::Trait for Test { type Event = TestEvent; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } mod grandpa { diff --git a/srml/indices/src/mock.rs b/srml/indices/src/mock.rs index 938aec2bc3311..ae6b31bb8cc86 100644 --- a/srml/indices/src/mock.rs +++ b/srml/indices/src/mock.rs @@ -67,6 +67,7 @@ pub struct Runtime; parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Runtime { type Origin = Origin; @@ -80,6 +81,7 @@ impl system::Trait for Runtime { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } impl Trait for Runtime { type AccountIndex = u64; diff --git a/srml/session/src/mock.rs b/srml/session/src/mock.rs index 915c315b1eba6..137642ca4cc69 100644 --- a/srml/session/src/mock.rs +++ b/srml/session/src/mock.rs @@ -110,6 +110,7 @@ pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; pub const MinimumPeriod: u64 = 5; } impl system::Trait for Test { @@ -124,6 +125,7 @@ impl system::Trait for Test { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } impl timestamp::Trait for Test { type Moment = u64; diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 1c420f6e1c47b..2bf95bbf8b44b 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -88,6 +88,7 @@ pub struct Test; parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -101,6 +102,7 @@ impl system::Trait for Test { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } parameter_types! { pub const TransferFee: u64 = 0; diff --git a/srml/support/Cargo.toml b/srml/support/Cargo.toml index 88cad9651a81e..6abe1fb336481 100644 --- a/srml/support/Cargo.toml +++ b/srml/support/Cargo.toml @@ -20,7 +20,7 @@ bitmask = { version = "0.5", default-features = false } [dev-dependencies] pretty_assertions = "0.6.1" -srml-system = { path = "../system", default-features = false } +srml-system = { path = "../system" } [features] default = ["std"] diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index ac5e0604446e4..476c82a1136c7 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -25,9 +25,11 @@ pub use srml_metadata::{ FunctionMetadata, DecodeDifferent, DecodeDifferentArray, FunctionArgumentMetadata, ModuleConstantMetadata, DefaultByte, DefaultByteGetter, }; -pub use sr_primitives::{ - weights::{TransactionWeight, Weigh, Weight, WeighData}, traits::{Dispatchable, DispatchResult} +pub use sr_primitives::weights::{SimpleDispatchInfo, GetDispatchInfo, DispatchInfo, WeighData, + ClassifyDispatch, + TransactionPriority }; +pub use sr_primitives::traits::{Dispatchable, DispatchResult}; /// A type that cannot be instantiated. pub enum Never {} @@ -584,7 +586,7 @@ macro_rules! decl_module { { $( $constants )* } [ $( $dispatchables )* ] $(#[doc = $doc_attr])* - #[weight = $crate::dispatch::TransactionWeight::default()] + #[weight = $crate::dispatch::SimpleDispatchInfo::default()] $fn_vis fn $fn_name( $from $(, $(#[$codec_attr])* $param_name : $param )* ) $( -> $result )* { $( $impl )* } @@ -1108,15 +1110,38 @@ macro_rules! decl_module { } // Implement weight calculation function for Call - impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Weigh + impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::GetDispatchInfo for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { - fn weigh(&self) -> $crate::dispatch::Weight { - match self { - $( $call_type::$fn_name($( ref $param_name ),*) => - <$crate::dispatch::WeighData<( $( & $param, )* )>>::weigh_data(&$weight, ($( $param_name, )*)), )* - $call_type::__PhantomItem(_, _) => { unreachable!("__PhantomItem should never be used.") }, - } + fn get_dispatch_info(&self) -> $crate::dispatch::DispatchInfo { + $( + if let $call_type::$fn_name($( ref $param_name ),*) = self { + let weight = >::weigh_data( + &$weight, + ($( $param_name, )*) + ); + let class = >::classify_dispatch( + &$weight, + ($( $param_name, )*) + ); + return $crate::dispatch::DispatchInfo { weight, class }; + } + if let $call_type::__PhantomItem(_, _) = self { unreachable!("__PhantomItem should never be used.") } + )* + // Defensive only: this function must have already returned at this point. + // all dispatchable function will have a weight which has the `::default` + // implementation of `SimpleDispatchInfo`. Nonetheless, we create one if it does + // not exist. + let weight = >::weigh_data( + &$crate::dispatch::SimpleDispatchInfo::default(), + () + ); + let class = >::classify_dispatch( + &$crate::dispatch::SimpleDispatchInfo::default(), + () + ); + $crate::dispatch::DispatchInfo { weight, class } + } } @@ -1261,10 +1286,10 @@ macro_rules! impl_outer_dispatch { $camelcase ( $crate::dispatch::CallableCallFor<$camelcase, $runtime> ) ,)* } - impl $crate::dispatch::Weigh for $call_type { - fn weigh(&self) -> $crate::dispatch::Weight { + impl $crate::dispatch::GetDispatchInfo for $call_type { + fn get_dispatch_info(&self) -> $crate::dispatch::DispatchInfo { match self { - $( $call_type::$camelcase(call) => call.weigh(), )* + $( $call_type::$camelcase(call) => call.get_dispatch_info(), )* } } } @@ -1571,6 +1596,7 @@ macro_rules! __check_reserved_fn_name { mod tests { use super::*; use crate::runtime_primitives::traits::{OnInitialize, OnFinalize}; + use sr_primitives::weights::{DispatchInfo, DispatchClass}; pub trait Trait: system::Trait + Sized where Self::AccountId: From { type Origin; @@ -1596,7 +1622,7 @@ mod tests { fn aux_0(_origin) -> Result { unreachable!() } fn aux_1(_origin, #[compact] _data: u32) -> Result { unreachable!() } fn aux_2(_origin, _data: i32, _data2: String) -> Result { unreachable!() } - #[weight = TransactionWeight::Basic(10, 100)] + #[weight = SimpleDispatchInfo::FixedNormal(10)] fn aux_3(_origin) -> Result { unreachable!() } fn aux_4(_origin, _data: i32) -> Result { unreachable!() } fn aux_5(_origin, _data: i32, #[compact] _data2: u32) -> Result { unreachable!() } @@ -1605,8 +1631,8 @@ mod tests { fn on_finalize(n: T::BlockNumber) { if n.into() == 42 { panic!("on_finalize") } } fn offchain_worker() {} - #[weight = TransactionWeight::Max] - fn weighted(_origin) { unreachable!() } + #[weight = SimpleDispatchInfo::FixedOperational(5)] + fn operational(_origin) { unreachable!() } } } @@ -1672,7 +1698,7 @@ mod tests { documentation: DecodeDifferent::Encode(&[]), }, FunctionMetadata { - name: DecodeDifferent::Encode("weighted"), + name: DecodeDifferent::Encode("operational"), arguments: DecodeDifferent::Encode(&[]), documentation: DecodeDifferent::Encode(&[]), }, @@ -1747,10 +1773,19 @@ mod tests { #[test] fn weight_should_attach_to_call_enum() { // max weight. not dependent on input. - assert_eq!(Call::::weighted().weight(100), 3 * 1024 * 1024); + assert_eq!( + Call::::operational().get_dispatch_info(), + DispatchInfo { weight: 5, class: DispatchClass::Operational }, + ); // default weight. - assert_eq!(Call::::aux_0().weight(5), 5 /*tx-len*/); + assert_eq!( + Call::::aux_0().get_dispatch_info(), + DispatchInfo { weight: 1, class: DispatchClass::Normal }, + ); // custom basic - assert_eq!(Call::::aux_3().weight(5), 10 + 100 * 5 ); + assert_eq!( + Call::::aux_3().get_dispatch_info(), + DispatchInfo { weight: 10, class: DispatchClass::Normal }, + ); } } diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 897d7c727635f..3ed20f247f82f 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -78,7 +78,7 @@ use rstd::prelude::*; use rstd::map; use rstd::marker::PhantomData; use primitives::{ - generic::{self, Era}, weights::Weight, traits::{ + generic::{self, Era}, weights::{Weight, DispatchInfo, DispatchClass} , traits::{ self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, CurrentHeight, BlockNumberToHash, MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded, @@ -194,6 +194,9 @@ pub trait Trait: 'static + Eq + Clone { /// The maximum weight of a block. type MaximumBlockWeight: Get; + + /// The maximum length of a block (in bytes). + type MaximumBlockLength: Get; } pub type DigestOf = generic::Digest<::Hash>; @@ -324,7 +327,9 @@ decl_storage! { /// Total extrinsics count for the current block. ExtrinsicCount: Option; /// Total weight for all extrinsics put together, for the current block. - AllExtrinsicsWeight: Option; + AllExtrinsicsWeight: Option; + /// Total length (in bytes) for all extrinsics put together, for the current block. + AllExtrinsicsLen: Option; /// Map of block numbers to block hashes. pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash; /// Extrinsics data for the current block (maps an extrinsic's index to its data). @@ -546,6 +551,11 @@ impl Module { AllExtrinsicsWeight::get().unwrap_or_default() } + /// Gets a total length of all executed extrinsics. + pub fn all_extrinsics_len() -> u32 { + AllExtrinsicsLen::get().unwrap_or_default() + } + /// Start the execution of a particular block. pub fn initialize( number: &T::BlockNumber, @@ -575,6 +585,7 @@ impl Module { pub fn finalize() -> T::Header { ExtrinsicCount::kill(); AllExtrinsicsWeight::kill(); + AllExtrinsicsLen::kill(); let number = >::take(); let parent_hash = >::take(); @@ -755,19 +766,63 @@ impl Module { } } -/// Weight limit check and increment. +/// resource limit check. #[derive(Encode, Decode, Clone, Eq, PartialEq)] pub struct CheckWeight(PhantomData); impl CheckWeight { - fn internal_check_weight(weight: Weight) -> Result<(), DispatchError> { + + /// Get the quota divisor of each dispatch class type. This indicates that all operational + /// dispatches can use the full capacity of any resource, while user-triggered ones can consume + /// a quarter. + fn get_dispatch_limit_divisor(class: DispatchClass) -> Weight { + match class { + DispatchClass::Operational => 1, + DispatchClass::Normal => 4, + } + } + /// Checks if the current extrinsic can fit into the block with respect to block weight limits. + /// + /// Upon successes, it returns the new block weight as a `Result`. + fn check_weight(info: DispatchInfo) -> Result { let current_weight = Module::::all_extrinsics_weight(); - let next_weight = current_weight.saturating_add(weight); - if next_weight > T::MaximumBlockWeight::get() { - return Err(DispatchError::Payment) + let maximum_weight = T::MaximumBlockWeight::get(); + let limit = maximum_weight / Self::get_dispatch_limit_divisor(info.class); + let added_weight = info.weight.min(limit); + let next_weight = current_weight.saturating_add(added_weight); + if next_weight > limit { + return Err(DispatchError::BadState) } - AllExtrinsicsWeight::put(next_weight); - Ok(()) + Ok(next_weight) + } + + /// Checks if the current extrinsic can fit into the block with respect to block length limits. + /// + /// Upon successes, it returns the new block length as a `Result`. + fn check_block_length(info: DispatchInfo, len: usize) -> Result { + let current_len = Module::::all_extrinsics_len(); + let maximum_len = T::MaximumBlockLength::get(); + let limit = maximum_len / Self::get_dispatch_limit_divisor(info.class); + let added_len = len as u32; + let next_len = current_len.saturating_add(added_len); + if next_len > limit { + return Err(DispatchError::BadState) + } + Ok(next_len) + } + + /// get the priority of an extrinsic denoted by `info`. + fn get_priority(info: DispatchInfo) -> TransactionPriority { + match info.class { + DispatchClass::Normal => info.weight.into(), + DispatchClass::Operational => Bounded::max_value() + } + } + + /// Utility constructor for tests and client code. + #[cfg(feature = "std")] + pub fn from() -> Self { + Self(PhantomData) } } @@ -780,28 +835,28 @@ impl SignedExtension for CheckWeight { fn pre_dispatch( self, _who: &Self::AccountId, - weight: Weight, - _len: usize, + info: DispatchInfo, + len: usize, ) -> Result<(), DispatchError> { - Self::internal_check_weight(weight) + let next_len = Self::check_block_length(info, len)?; + AllExtrinsicsLen::put(next_len); + let next_weight = Self::check_weight(info)?; + AllExtrinsicsWeight::put(next_weight); + Ok(()) } fn validate( &self, _who: &Self::AccountId, - _weight: Weight, - _len: usize, + info: DispatchInfo, + len: usize, ) -> Result { - // TODO: check for a maximum size and weight here as well. - // write priority based on tx weight type + tip. - Ok(ValidTransaction::default()) - } -} - -#[cfg(feature = "std")] -impl CheckWeight { - pub fn from() -> Self { - Self(PhantomData) + // There is no point in writing to storage here since changes are discarded. This basically + // discards any transaction which is bigger than the length or weight limit alone, which is + // a guarantee that it will fail in the pre-dispatch phase. + let _ = Self::check_block_length(info, len)?; + let _ = Self::check_weight(info)?; + Ok(ValidTransaction { priority: Self::get_priority(info), ..Default::default() }) } } @@ -840,7 +895,7 @@ impl SignedExtension for CheckNonce { fn pre_dispatch( self, who: &Self::AccountId, - _weight: Weight, + _info: DispatchInfo, _len: usize, ) -> Result<(), DispatchError> { let expected = >::get(who); @@ -856,7 +911,7 @@ impl SignedExtension for CheckNonce { fn validate( &self, who: &Self::AccountId, - _weight: Weight, + info: DispatchInfo, _len: usize, ) -> Result { // check index @@ -873,7 +928,7 @@ impl SignedExtension for CheckNonce { }; Ok(ValidTransaction { - priority: _weight as TransactionPriority, + priority: info.weight as TransactionPriority, requires, provides, longevity: TransactionLongevity::max_value(), @@ -960,6 +1015,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 10; pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl Trait for Test { @@ -974,6 +1030,7 @@ mod tests { type Event = u16; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } impl From for u16 { @@ -1129,31 +1186,126 @@ mod tests { fn signed_ext_check_nonce_works() { with_externalities(&mut new_test_ext(), || { >::insert(1, 1); + let info = DispatchInfo::default(); + let len = 0_usize; // stale - assert!(CheckNonce::(0).validate(&1, 0).is_err()); - assert!(CheckNonce::(0).pre_dispatch(&1, 0).is_err()); + assert!(CheckNonce::(0).validate(&1, info, len).is_err()); + assert!(CheckNonce::(0).pre_dispatch(&1, info, len).is_err()); // correct - assert!(CheckNonce::(1).validate(&1, 0).is_ok()); - assert!(CheckNonce::(1).pre_dispatch(&1, 0).is_ok()); + assert!(CheckNonce::(1).validate(&1, info, len).is_ok()); + assert!(CheckNonce::(1).pre_dispatch(&1, info, len).is_ok()); // future - assert!(CheckNonce::(5).validate(&1, 0).is_ok()); - assert!(CheckNonce::(5).pre_dispatch(&1, 0).is_err()); + assert!(CheckNonce::(5).validate(&1, info, len).is_ok()); + assert!(CheckNonce::(5).pre_dispatch(&1, info, len).is_err()); + }) + } + + #[test] + fn signed_ext_check_weight_works_user_tx() { + with_externalities(&mut new_test_ext(), || { + let small = DispatchInfo { weight: 100, ..Default::default() }; + let medium = DispatchInfo { + weight: >::get() / 4 - 1, + ..Default::default() + }; + let big = DispatchInfo { + weight: >::get() / 4 + 1, + ..Default::default() + }; + let len = 0_usize; + + let reset_check_weight = |i, f, s| { + AllExtrinsicsWeight::put(s); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, i, len); + if f { assert!(r.is_err()) } else { assert!(r.is_ok()) } + }; + + reset_check_weight(small, false, 0); + reset_check_weight(medium, false, 0); + reset_check_weight(big, true, 1); + }) + } + + #[test] + fn signed_ext_check_weight_fee_works() { + with_externalities(&mut new_test_ext(), || { + let free = DispatchInfo { weight: 0, ..Default::default() }; + let len = 0_usize; + + assert_eq!(System::all_extrinsics_weight(), 0); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, free, len); + assert!(r.is_ok()); + assert_eq!(System::all_extrinsics_weight(), 0); + }) + } + + #[test] + fn signed_ext_check_weight_max_works() { + with_externalities(&mut new_test_ext(), || { + let max = DispatchInfo { weight: Weight::max_value(), ..Default::default() }; + let len = 0_usize; + + assert_eq!(System::all_extrinsics_weight(), 0); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, max, len); + assert!(r.is_ok()); + assert_eq!(System::all_extrinsics_weight(), >::get() / 4); }) } #[test] - fn signed_ext_check_weight_works() { + fn signed_ext_check_weight_works_operational_tx() { with_externalities(&mut new_test_ext(), || { - // small - AllExtrinsicsWeight::put(512); - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, 100).is_ok()); - // almost - AllExtrinsicsWeight::put(512); - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, 512).is_ok()); - // big - AllExtrinsicsWeight::put(512); - assert!(CheckWeight::(PhantomData).pre_dispatch(&1, 513).is_err()); + let normal = DispatchInfo { weight: 100, ..Default::default() }; + let op = DispatchInfo { weight: 100, class: DispatchClass::Operational }; + let len = 0_usize; + + // given almost full block + AllExtrinsicsWeight::put(>::get() / 4); + // will not fit. + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, normal, len).is_err()); + // will fit. + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, op, len).is_ok()); + + // likewise for length limit. + let len = 100_usize; + AllExtrinsicsLen::put(>::get() / 4); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, normal, len).is_err()); + assert!(CheckWeight::(PhantomData).pre_dispatch(&1, op, len).is_ok()); + }) + } + + #[test] + fn signed_ext_check_weight_priority_works() { + with_externalities(&mut new_test_ext(), || { + let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal }; + let op = DispatchInfo { weight: 100, class: DispatchClass::Operational }; + let len = 0_usize; + + assert_eq!( + CheckWeight::(PhantomData).validate(&1, normal, len).unwrap().priority, + 100, + ); + assert_eq!( + CheckWeight::(PhantomData).validate(&1, op, len).unwrap().priority, + Bounded::max_value(), + ); + }) + } + + #[test] + fn signed_ext_check_weight_block_size_works() { + with_externalities(&mut new_test_ext(), || { + let tx = DispatchInfo::default(); + + let reset_check_weight = |s, f| { + AllExtrinsicsLen::put(0); + let r = CheckWeight::(PhantomData).pre_dispatch(&1, tx, s); + if f { assert!(r.is_err()) } else { assert!(r.is_ok()) } + }; + reset_check_weight(128, false); + reset_check_weight(512, false); + reset_check_weight(513, true); }) } diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index b25cab3e03156..9fdc05ee2a248 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -339,6 +339,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -352,6 +353,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } parameter_types! { pub const MinimumPeriod: u64 = 5; diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index aa49190d5abb2..85edc89a30c83 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -371,6 +371,7 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; } impl system::Trait for Test { type Origin = Origin; @@ -384,6 +385,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; } parameter_types! { pub const ExistentialDeposit: u64 = 0; From b8f564e7d268e3eef52723e7a94cf0ca30df378b Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 19 Jul 2019 14:31:28 +0200 Subject: [PATCH 12/33] Bump transaction version --- core/sr-primitives/src/generic/unchecked_extrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index 190fff168c770..c7b83110c88e8 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -25,7 +25,7 @@ use crate::codec::{Decode, Encode, Input}; use crate::traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic}; use super::CheckedExtrinsic; -const TRANSACTION_VERSION: u8 = 1; +const TRANSACTION_VERSION: u8 = 2; /// A extrinsic right from the external world. This is unchecked and so /// can contain a signature. From 7a0fbc949df08b85fff6a692d86a0ae9e70094b1 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 19 Jul 2019 17:57:55 +0200 Subject: [PATCH 13/33] Fix weight mult test. --- node/runtime/src/impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/runtime/src/impls.rs b/node/runtime/src/impls.rs index ec7f596605fe4..85365b6a7e73e 100644 --- a/node/runtime/src/impls.rs +++ b/node/runtime/src/impls.rs @@ -108,7 +108,7 @@ mod tests { } fn ideal() -> Weight { - max() / 4 + max() / 4 / 4 } // poc reference implementation. From 84fa279ece1b210be0032fee9a4fd613a5678312 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 19 Jul 2019 18:18:40 +0200 Subject: [PATCH 14/33] Fix more tests and improve doc. --- core/sr-primitives/src/weights.rs | 6 +++--- node-template/runtime/src/lib.rs | 2 +- srml/support/src/dispatch.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index 68bf1a5b06195..c592d9e19546c 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -32,7 +32,7 @@ use crate::traits::Bounded; /// Numeric range of a transaction weight. pub type Weight = u32; -/// A broad range of dispatch types. This is only distinguishing normal, user-triggered transactions +/// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions /// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`). #[cfg_attr(feature = "std", derive(Debug))] #[derive(PartialEq, Eq, Clone, Copy)] @@ -110,7 +110,7 @@ pub trait ClassifyDispatch { /// A user may pass in any other type that implements the correct traits. If not, the `Default` /// implementation of [`SimpleDispatchInfo`] is used. /// -/// For each broad group (`Normal` and `Operation`): +/// For each generalized group (`Normal` and `Operation`): /// - A `Fixed` variant means weight fee is charged normally and the weight is the number /// specified in the inner value of the variant. /// - A `Free` variant is equal to `::Fixed(0)`. Note that this does not guarantee inclusion. @@ -120,7 +120,7 @@ pub trait ClassifyDispatch { /// - A _weight-fee_ is deducted. /// - The block weight is consumed proportionally. /// -/// As for the broad groups themselves: +/// As for the generalized groups themselves: /// - `Normal` variants will be assigned a priority proportional to their weight. They can only /// consume a portion (1/4) of the maximum block resource limits. /// - `Operational` variants will be assigned the maximum priority. They can potentially consume diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 3a03add715a04..77407e696d669 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -116,7 +116,7 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const BlockHashCount: BlockNumber = 250; pub const MaximumBlockWeight: Weight = 4 * 1024 * 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; + pub const MaximumBlockLength: u32 = 4 * 1024 * 1024; } impl system::Trait for Runtime { diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index 476c82a1136c7..7afbd11cd1d0d 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -1780,7 +1780,7 @@ mod tests { // default weight. assert_eq!( Call::::aux_0().get_dispatch_info(), - DispatchInfo { weight: 1, class: DispatchClass::Normal }, + DispatchInfo { weight: 100, class: DispatchClass::Normal }, ); // custom basic assert_eq!( From f4d457921ad000482bee082c42ab9c47f85775aa Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 19 Jul 2019 18:22:03 +0200 Subject: [PATCH 15/33] Bump. --- node/runtime/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 92ca0a691c591..a9aa77bb07762 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -75,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: 114, - impl_version: 114, + spec_version: 115, + impl_version: 115, apis: RUNTIME_API_VERSIONS, }; @@ -117,7 +117,7 @@ pub const DAYS: Moment = HOURS * 24; parameter_types! { pub const BlockHashCount: BlockNumber = 250; - pub const MaximumBlockWeight: Weight = 4 * 1024; + pub const MaximumBlockWeight: Weight = 4 * 1024 * 1024; pub const MaximumBlockLength: u32 = 4 * 1024 * 1024; } From d12713a151ffd2775d85bb89d0e219d3aa2cb2ee Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sat, 20 Jul 2019 15:21:04 +0200 Subject: [PATCH 16/33] Make some tests work again. --- srml/executive/src/lib.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 2bed6a446e507..326c3d7ab95d9 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -449,6 +449,10 @@ mod tests { ) } + fn sign_extra(who: u64, nonce: u64, fee: u64) -> Option<(u64, SignedExtra)> { + Some((who, extra(nonce, fee))) + } + #[test] fn balance_transfer_dispatch_works() { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); @@ -456,7 +460,7 @@ mod tests { balances: vec![(1, 111)], vesting: vec![], }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); - let xt = primitives::testing::TestXt(Some(1), Call::transfer(2, 69), extra(0, 0)); + let xt = primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer(2, 69)); let weight = xt.get_dispatch_info().weight as u64; let mut t = runtime_io::TestExternalities::::new_with_children(t); with_externalities(&mut t, || { @@ -537,7 +541,7 @@ mod tests { fn bad_extrinsic_not_inserted() { let mut t = new_test_ext(1); // bad nonce check! - let xt = primitives::testing::TestXt(Some(1), Call::transfer(33, 69), extra(30, 0)); + let xt = primitives::testing::TestXt(sign_extra(1, 30, 0), Call::transfer(33, 69)); with_externalities(&mut t, || { Executive::initialize_block(&Header::new( 1, @@ -555,7 +559,7 @@ mod tests { fn block_weight_limit_enforced() { let mut t = new_test_ext(10000); // given: TestXt uses the encoded len as fixed Len: - let xt = primitives::testing::TestXt(Some(1), Call::transfer::(33, 0), extra(0, 0)); + let xt = primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer::(33, 0)); let encoded = xt.encode(); let encoded_len = encoded.len() as u32; let limit = >::get() / 4; @@ -571,7 +575,7 @@ mod tests { assert_eq!(>::all_extrinsics_weight(), 0); for nonce in 0..=num_to_exhaust_block { - let xt = primitives::testing::TestXt(Some(1), Call::transfer::(33, 0), extra(nonce.into(), 0)); + let xt = primitives::testing::TestXt(sign_extra(1, nonce.into(), 0), Call::transfer::(33, 0)); let res = Executive::apply_extrinsic(xt); if nonce != num_to_exhaust_block { assert_eq!(res.unwrap(), ApplyOutcome::Success); @@ -586,9 +590,9 @@ mod tests { #[test] fn block_weight_and_size_is_stored_per_tx() { - let xt = primitives::testing::TestXt(Some(1), Call::transfer(33, 0), extra(0, 0)); - let x1 = primitives::testing::TestXt(Some(1), Call::transfer(33, 0), extra(1, 0)); - let x2 = primitives::testing::TestXt(Some(1), Call::transfer(33, 0), extra(2, 0)); + let xt = primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer(33, 0)); + let x1 = primitives::testing::TestXt(sign_extra(1, 1, 0), Call::transfer(33, 0)); + let x2 = primitives::testing::TestXt(sign_extra(1, 2, 0), Call::transfer(33, 0)); let len = xt.clone().encode().len() as u32; let mut t = new_test_ext(1); with_externalities(&mut t, || { @@ -612,7 +616,7 @@ mod tests { #[test] fn validate_unsigned() { - let xt = primitives::testing::TestXt(None, Call::set_balance(33, 69, 69), extra(0, 0)); + let xt = primitives::testing::TestXt(None, Call::set_balance(33, 69, 69)); let valid = TransactionValidity::Valid(Default::default()); let mut t = new_test_ext(1); @@ -635,7 +639,7 @@ mod tests { 10, lock, ); - let xt = primitives::testing::TestXt(Some(1), Call::transfer(2, 10), extra(0, 0)); + let xt = primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer(2, 10)); let weight = xt.get_dispatch_info().weight as u64; Executive::initialize_block(&Header::new( 1, From 3350f9c6bbab21159e10a178acf1a01285db1fc5 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sat, 20 Jul 2019 16:31:30 +0200 Subject: [PATCH 17/33] Fix subkey. --- subkey/src/main.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/subkey/src/main.rs b/subkey/src/main.rs index ea72acd8b4d61..f9432b42c12b3 100644 --- a/subkey/src/main.rs +++ b/subkey/src/main.rs @@ -26,7 +26,6 @@ use substrate_primitives::{ ed25519, sr25519, hexdisplay::HexDisplay, Pair, Public, blake2_256, crypto::{Ss58Codec, set_default_ss58_version, Ss58AddressFormat} }; -use parity_codec::{Encode, Decode}; use parity_codec::{Encode, Decode, Compact}; use sr_primitives::generic::Era; use node_primitives::{Balance, Index, Hash}; @@ -91,14 +90,14 @@ fn execute(matches: clap::ArgMatches) where <::Pair as Pair>::Signature: AsRef<[u8]> + AsMut<[u8]> + Default, <::Pair as Pair>::Public: Sized + AsRef<[u8]> + Ss58Codec + AsRef<<::Pair as Pair>::Public>, { - let extra = |i: Index, f: Balance| { - ( - system::CheckEra::::from(Era::Immortal), - system::CheckNonce::::from(i), - system::CheckWeight::::from(), - balances::TakeFees::::from(f), - ) - }; + // let extra = |i: Index, f: Balance| { + // ( + // system::CheckEra::::from(Era::Immortal), + // system::CheckNonce::::from(i), + // system::CheckWeight::::from(), + // balances::TakeFees::::from(f), + // ) + // }; let password = matches.value_of("password"); let maybe_network = matches.value_of("network"); if let Some(network) = maybe_network { From b7885073ce948f72a22b28b0288c5d28fdbb45f4 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sat, 20 Jul 2019 16:43:37 +0200 Subject: [PATCH 18/33] Remove todos + bump. --- core/sr-primitives/src/traits.rs | 2 +- node/runtime/src/lib.rs | 4 ++-- srml/system/src/lib.rs | 5 ----- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index a460b4b785d8b..eccf9751322ca 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -929,7 +929,7 @@ macro_rules! tuple_impl_indexed { }; } -// TODO: merge this into `tuple_impl` once codec supports `trait Codec` for longer tuple lengths. +// TODO: merge this into `tuple_impl` once codec supports `trait Codec` for longer tuple lengths. #3152 #[allow(non_snake_case)] tuple_impl_indexed!(A, B, C, D, E, F, G, H, I, J, ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,); diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 84f7e73730f43..a0a8af0b5c586 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -75,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: 115, - impl_version: 115, + spec_version: 116, + impl_version: 116, apis: RUNTIME_API_VERSIONS, }; diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 0c58002f939e9..bd1f76299e49c 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -201,10 +201,6 @@ pub trait Trait: 'static + Eq + Clone { /// The maximum weight of a block. type MaximumBlockWeight: Get; - /// portion of the block weight that is allowed to be consumed by normal extrinsics. The weight - /// multiplier also updates proportional to this. - // type IdealBlockWeightRatio: Get; - /// The maximum length of a block (in bytes). type MaximumBlockLength: Get; } @@ -802,7 +798,6 @@ impl CheckWeight { fn get_dispatch_limit_divisor(class: DispatchClass) -> Weight { match class { DispatchClass::Operational => 1, - // TODO: make this an associated const. DispatchClass::Normal => 4, } } From b9b6b530ecc2077486116881f732d7ab3753ab80 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Sun, 21 Jul 2019 11:30:19 +0200 Subject: [PATCH 19/33] First draft of annotating weights. --- core/sr-primitives/src/lib.rs | 6 +- core/sr-primitives/src/traits.rs | 14 ++-- core/sr-primitives/src/weights.rs | 12 ++-- node-template/runtime/src/lib.rs | 4 +- node/executor/src/lib.rs | 103 ++++++++++++++++++++---------- node/runtime/src/impls.rs | 92 ++++++++++++++------------ node/runtime/src/lib.rs | 4 +- srml/authorship/src/lib.rs | 2 + srml/balances/src/lib.rs | 4 +- srml/collective/src/lib.rs | 30 +++++---- srml/democracy/src/lib.rs | 18 ++++++ srml/elections/src/lib.rs | 11 ++++ srml/executive/src/lib.rs | 6 +- srml/session/src/lib.rs | 2 + srml/staking/src/lib.rs | 14 ++++ srml/sudo/src/lib.rs | 2 + srml/support/src/dispatch.rs | 8 +-- srml/support/src/lib.rs | 31 +++++++++ srml/system/src/lib.rs | 62 +++++++++++------- srml/timestamp/src/lib.rs | 2 + srml/treasury/src/lib.rs | 4 ++ 21 files changed, 300 insertions(+), 131 deletions(-) diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 0b6321034cda4..9220fb5455d1e 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -170,7 +170,7 @@ pub type ConsensusEngineId = [u8; 4]; /// Permill is parts-per-million (i.e. after multiplying by this, divide by 1000000). #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Ord, PartialOrd))] #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)] -pub struct Permill(u32); +pub struct Permill(pub u32); impl Permill { /// Nothing. @@ -274,7 +274,7 @@ impl From> for Permill { /// provides a means to multiply some other value by that. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)] -pub struct Perbill(u32); +pub struct Perbill(pub u32); impl Perbill { /// Nothing. @@ -383,7 +383,7 @@ impl From> for Perbill { /// cannot hold a value larger than +-`9223372036854775807 / 1_000_000_000` (~9 billion). #[cfg_attr(feature = "std", derive(Debug))] #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct Fixed64(i64); +pub struct Fixed64(pub i64); /// The maximum value of the `Fixed64` type const DIV: i64 = 1_000_000_000; diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index eccf9751322ca..079e0b94a41ed 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -771,6 +771,9 @@ pub enum DispatchError { /// General error to do with the inability to pay some fees (e.g. account balance too low). Payment, + /// General error to do with the exhaustion of block resources. + Resource, + /// General error to do with the permissions of the sender. NoPermission, @@ -794,11 +797,12 @@ impl From for i8 { fn from(e: DispatchError) -> i8 { match e { DispatchError::Payment => -64, - DispatchError::NoPermission => -65, - DispatchError::BadState => -66, - DispatchError::Stale => -67, - DispatchError::Future => -68, - DispatchError::BadProof => -69, + DispatchError::Resource => -65, + DispatchError::NoPermission => -66, + DispatchError::BadState => -67, + DispatchError::Stale => -68, + DispatchError::Future => -69, + DispatchError::BadProof => -70, } } } diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index c592d9e19546c..bae0b0c636459 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -144,11 +144,11 @@ pub enum SimpleDispatchInfo { impl WeighData for SimpleDispatchInfo { fn weigh_data(&self, _: T) -> Weight { match self { - SimpleDispatchInfo::FixedNormal(w) => *w, + SimpleDispatchInfo::FixedNormal(w) => *w * 1000, SimpleDispatchInfo::MaxNormal => Bounded::max_value(), SimpleDispatchInfo::FreeNormal => Bounded::min_value(), - SimpleDispatchInfo::FixedOperational(w) => *w, + SimpleDispatchInfo::FixedOperational(w) => *w * 1000, SimpleDispatchInfo::MaxOperational => Bounded::max_value(), SimpleDispatchInfo::FreeOperational => Bounded::min_value(), } @@ -162,11 +162,11 @@ impl ClassifyDispatch for SimpleDispatchInfo { } impl Default for SimpleDispatchInfo { + // TODO: based on the fact that this has a system-wide impact, it should probably be + // configurable at the `node/runtime` level. fn default() -> Self { - // This implies that the weight is currently equal to 100, nothing more - // for all substrate transactions that do NOT explicitly annotate weight. - // TODO #2431 needs to be updated with proper max values. - SimpleDispatchInfo::FixedNormal(100) + // Default weight of all transactions. For simplicity, all weights are factored by 10^3. + SimpleDispatchInfo::FixedNormal(10) } } diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 332df0ec0dfae..2f9927235ad1d 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -102,8 +102,8 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const BlockHashCount: BlockNumber = 250; - pub const MaximumBlockWeight: Weight = 4 * 1024 * 1024; - pub const MaximumBlockLength: u32 = 4 * 1024 * 1024; + pub const MaximumBlockWeight: Weight = 1_000_000_000; + pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; } impl system::Trait for Runtime { diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index cc050b015f080..f7088d51fb4f4 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -40,7 +40,7 @@ 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, Get}}; + use runtime_support::{Hashable, StorageValue, StorageMap, assert_eq_error_rate, traits::{Currency, Get}}; use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities}; use primitives::{ twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, @@ -49,7 +49,7 @@ mod tests { 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::{WeightMultiplier, SimpleDispatchInfo, WeighData}; + use runtime_primitives::weights::{WeightMultiplier, SimpleDispatchInfo, GetDispatchInfo, WeighData}; use {balances, contracts, indices, staking, system, timestamp}; use contracts::ContractAddressFor; use system::{EventRecord, Phase}; @@ -86,12 +86,16 @@ mod tests { let length_fee = >::get() + >::get() * (extrinsic.encode().len() as Balance); - let weight_fee = SimpleDispatchInfo::default().weigh_data(()) as Balance; + let weight_fee = default_transfer_call().get_dispatch_info().weight as Balance; + // TODO: with this we have 100% accurate fee estimation. Should probably be able to get rid + // of `assert_eq_error_rate!` now. But it makes test mockup much more complicated because + // the fee for each block can only be estimated _before_ that block. + // weight_fee = >::next_weight_multiplier().apply_to(weight_fee as u32) as Balance; length_fee + weight_fee } - fn multiplier_ideal() -> u32 { - >::get() / 4 / 4 + fn multiplier_target() -> u32 { + >::get() / 4 } fn creation_fee() -> Balance { @@ -155,10 +159,14 @@ mod tests { ) } + fn default_transfer_call() -> balances::Call { + balances::Call::transfer::(bob().into(), 69 * DOLLARS) + } + fn xt() -> UncheckedExtrinsic { sign(CheckedExtrinsic { signed: Some((alice(), signed_extra(0, 0))), - function: Call::Balances(balances::Call::transfer::(bob().into(), 69 * DOLLARS)), + function: Call::Balances(default_transfer_call()), }) } @@ -576,9 +584,19 @@ mod tests { ).0.unwrap(); runtime_io::with_externalities(&mut t, || { - // 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()); + // TODO: this needs investigating: why are we deducting creation fee twice here? and why bob also pays it? + // NOTE: fees differ slightly in tests that execute more than one block due to the + // weight update. + assert_eq_error_rate!( + Balances::total_balance(&alice()), + 32 * DOLLARS - 2 * transfer_fee(&xt()) - 2 * creation_fee(), + 10 + ); + assert_eq_error_rate!( + Balances::total_balance(&bob()), + 179 * DOLLARS - transfer_fee(&xt()) - creation_fee(), + 10 + ); let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), @@ -640,8 +658,16 @@ mod tests { WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block2.0).unwrap(); runtime_io::with_externalities(&mut t, || { - 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()); + assert_eq_error_rate!( + Balances::total_balance(&alice()), + 32 * DOLLARS - 2 * transfer_fee(&xt()) - 2 * creation_fee(), + 10 + ); + assert_eq_error_rate!( + Balances::total_balance(&bob()), + 179 * DOLLARS - 1 * transfer_fee(&xt()) - creation_fee(), + 10 + ); }); } @@ -803,15 +829,14 @@ mod tests { fn wasm_big_block_import_fails() { let mut t = new_test_ext(COMPACT_CODE, false); - assert!( - WasmExecutor::new().call( - &mut t, - 4, - COMPACT_CODE, - "Core_execute_block", - &block_with_size(42, 0, 120_000).0 - ).is_err() + let result = WasmExecutor::new().call( + &mut t, + 4, + COMPACT_CODE, + "Core_execute_block", + &block_with_size(42, 0, 120_000).0 ); + assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) }))) } #[test] @@ -946,25 +971,37 @@ mod tests { }); let mut tt = new_test_ext(COMPACT_CODE, false); + + // This test can either use `fill_block()`, which is controversial, or should be dropped. // 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::>(); - xts.insert(0, CheckedExtrinsic { - signed: None, - function: Call::Timestamp(timestamp::Call::set(42)), - }); + // let num_to_exhaust = (multiplier_target() + 100) / SimpleDispatchInfo::default().weigh_data(()); + // println!("++ Generating {} transactions to fill {} weight units", num_to_exhaust, multiplier_target() + 100); + // 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::>(); + // xts.insert(0, CheckedExtrinsic { + // signed: None, + // function: Call::Timestamp(timestamp::Call::set(42)), + // }); + + println!("++ Generated all extrinsics. Constructing blocks."); // big one in terms of weight. let block1 = construct_block( &mut tt, 1, GENESIS_HASH.into(), - xts + vec![ + CheckedExtrinsic { + signed: None, + function: Call::Timestamp(timestamp::Call::set(42)), + }, + CheckedExtrinsic { + signed: Some((charlie(), signed_extra(0, 0))), + function: Call::System(system::Call::fill_block()), + } + ] ); // small one in terms of weight. @@ -978,12 +1015,14 @@ mod tests { function: Call::Timestamp(timestamp::Call::set(52)), }, CheckedExtrinsic { - signed: Some((charlie(), signed_extra(num_to_exhaust.into(), 0))), + signed: Some((charlie(), signed_extra(1, 0))), function: Call::System(system::Call::remark(vec![0; 1])), } ] ); + println!("++ Block 1 size: {} / Block 2 size {}", block1.0.encode().len(), block2.0.encode().len()); + // execute a big block. executor().call::<_, NeverNativeValue, fn() -> _>( &mut t, diff --git a/node/runtime/src/impls.rs b/node/runtime/src/impls.rs index 85365b6a7e73e..532baa582cb82 100644 --- a/node/runtime/src/impls.rs +++ b/node/runtime/src/impls.rs @@ -19,7 +19,7 @@ use node_primitives::Balance; use runtime_primitives::weights::{Weight, WeightMultiplier}; use runtime_primitives::traits::{Convert, Saturating}; -use runtime_primitives::Fixed64; +use runtime_primitives::{Fixed64, Perbill}; use support::traits::Get; use crate::{Balances, MaximumBlockWeight}; @@ -44,27 +44,38 @@ impl Convert for CurrencyToVoteHandler { /// /// This assumes that weight is a numeric value in the u32 range. /// +/// Given `TARGET_BLOCK_FULLNESS = 1/2`, a block saturation greater than 1/2 will cause the system +/// fees to slightly grow and the opposite for block saturations less than 1/2. +/// /// Formula: -/// diff = (ideal_weight - current_block_weight) +/// diff = (target_weight - current_block_weight) /// v = 0.00004 /// next_weight = weight * (1 + (v . diff) + (v . diff)^2 / 2) /// /// https://research.web3.foundation/en/latest/polkadot/Token%20Economics/#relay-chain-transaction-fees pub struct WeightMultiplierUpdateHandler; + +// CRITICAL NOTE: The system module maintains two constants: a _maximum_ block weight and a +// _ratio_ of it yielding the portion which is accessible to normal transactions (reserving the rest +// for operational ones). `TARGET_BLOCK_FULLNESS` is entirely independent and the system module is +// not aware of if, nor should it care about it. This constant simply denotes on which ratio of the +// _maximum_ block weight we tweak the fees. It does NOT care about the type of the dispatch. +// +// For the system to be configured in a sane way, `TARGET_BLOCK_FULLNESS` should always be less than +// the ratio that `system` module uses to find normal transaction quota. +/// The block saturation level. Fees will be updates based on this value. +pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill(1_000_000_000 / 4); + impl Convert<(Weight, WeightMultiplier), WeightMultiplier> for WeightMultiplierUpdateHandler { fn convert(previous_state: (Weight, WeightMultiplier)) -> WeightMultiplier { let (block_weight, multiplier) = previous_state; - // 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 = >::get() / 4; - let ideal_weight = (max_weight / 4) as u128; + let max_weight = >::get(); + let target_weight = (TARGET_BLOCK_FULLNESS * max_weight) as u128; let block_weight = block_weight as u128; // determines if the first_term is positive - let positive = block_weight >= ideal_weight; - let diff_abs = block_weight.max(ideal_weight) - block_weight.min(ideal_weight); + let positive = block_weight >= target_weight; + let diff_abs = block_weight.max(target_weight) - block_weight.min(target_weight); // diff is within u32, safe. let diff = Fixed64::from_rational(diff_abs as i64, max_weight as u64); let diff_squared = diff.saturating_mul(diff); @@ -102,13 +113,14 @@ mod tests { use super::*; use runtime_primitives::weights::Weight; use runtime_primitives::Perbill; + use crate::MaximumBlockWeight; fn max() -> Weight { >::get() } - fn ideal() -> Weight { - max() / 4 / 4 + fn target() -> Weight { + TARGET_BLOCK_FULLNESS * max() } // poc reference implementation. @@ -120,7 +132,7 @@ mod tests { // maximum tx weight let m = max() as f32; // Ideal saturation in terms of weight - let ss = ideal() as f32; + let ss = target() as f32; // Current saturation in terms of weight let s = block_weight; @@ -130,7 +142,7 @@ mod tests { Perbill::from_parts((fm * 1_000_000_000_f32) as u32) } - fn fm(parts: i64) -> WeightMultiplier { + fn wm(parts: i64) -> WeightMultiplier { WeightMultiplier::from_parts(parts) } @@ -138,44 +150,44 @@ mod tests { fn stateless_weight_mul() { // Light block. Fee is reduced a little. assert_eq!( - WeightMultiplierUpdateHandler::convert((ideal() / 4, WeightMultiplier::default())), - fm(-7500) + WeightMultiplierUpdateHandler::convert((target() / 4, WeightMultiplier::default())), + wm(-7500) ); // a bit more. Fee is decreased less, meaning that the fee increases as the block grows. assert_eq!( - WeightMultiplierUpdateHandler::convert((ideal() / 2, WeightMultiplier::default())), - fm(-5000) + WeightMultiplierUpdateHandler::convert((target() / 2, WeightMultiplier::default())), + wm(-5000) ); // ideal. Original fee. No changes. assert_eq!( - WeightMultiplierUpdateHandler::convert((ideal() as u32, WeightMultiplier::default())), - fm(0) + WeightMultiplierUpdateHandler::convert((target() as u32, WeightMultiplier::default())), + wm(0) ); // // More than ideal. Fee is increased. assert_eq!( - WeightMultiplierUpdateHandler::convert(((ideal() * 2) as u32, WeightMultiplier::default())), - fm(10000) + WeightMultiplierUpdateHandler::convert(((target() * 2) as u32, WeightMultiplier::default())), + wm(10000) ); } #[test] fn stateful_weight_mul_grow_to_infinity() { assert_eq!( - WeightMultiplierUpdateHandler::convert((ideal() * 2, WeightMultiplier::default())), - fm(10000) + WeightMultiplierUpdateHandler::convert((target() * 2, WeightMultiplier::default())), + wm(10000) ); assert_eq!( - WeightMultiplierUpdateHandler::convert((ideal() * 2, fm(10000))), - fm(20000) + WeightMultiplierUpdateHandler::convert((target() * 2, wm(10000))), + wm(20000) ); assert_eq!( - WeightMultiplierUpdateHandler::convert((ideal() * 2, fm(20000))), - fm(30000) + WeightMultiplierUpdateHandler::convert((target() * 2, wm(20000))), + wm(30000) ); // ... assert_eq!( - WeightMultiplierUpdateHandler::convert((ideal() * 2, fm(1_000_000_000))), - fm(1_000_000_000 + 10000) + WeightMultiplierUpdateHandler::convert((target() * 2, wm(1_000_000_000))), + wm(1_000_000_000 + 10000) ); } @@ -183,27 +195,25 @@ mod tests { fn stateful_weight_mil_collapse_to_minus_one() { assert_eq!( WeightMultiplierUpdateHandler::convert((0, WeightMultiplier::default())), - fm(-10000) + wm(-10000) ); assert_eq!( - WeightMultiplierUpdateHandler::convert((0, fm(-10000))), - fm(-20000) + WeightMultiplierUpdateHandler::convert((0, wm(-10000))), + wm(-20000) ); assert_eq!( - WeightMultiplierUpdateHandler::convert((0, fm(-20000))), - fm(-30000) + WeightMultiplierUpdateHandler::convert((0, wm(-20000))), + wm(-30000) ); // ... assert_eq!( - WeightMultiplierUpdateHandler::convert((0, fm(1_000_000_000 * -1))), - fm(-1_000_000_000) + WeightMultiplierUpdateHandler::convert((0, wm(1_000_000_000 * -1))), + wm(-1_000_000_000) ); } #[test] fn weight_to_fee_should_not_overflow_on_large_weights() { - // defensive-only test. at the moment we are not allowing any weight more than - // 4 * 1024 * 1024 in a block. let kb = 1024_u32; let mb = kb * kb; let max_fm = WeightMultiplier::from_fixed(Fixed64::from_natural(i64::max_value())); @@ -214,7 +224,9 @@ mod tests { WeightMultiplierUpdateHandler::convert((i, WeightMultiplier::default())); }); - vec![10 * mb, Weight::max_value() / 2, Weight::max_value()] + // Some values that are all above the target and will cause an increase. + let target_weight = TARGET_BLOCK_FULLNESS * >::get(); + vec![target_weight + 100, target_weight * 2, target_weight * 4] .into_iter() .for_each(|i| { let fm = WeightMultiplierUpdateHandler::convert(( diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index a0a8af0b5c586..18bef27402143 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -117,8 +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; + pub const MaximumBlockWeight: Weight = 1_000_000_000; + pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; } impl system::Trait for Runtime { diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index 50b27f83f6694..81a1b840c371d 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -28,6 +28,7 @@ use srml_support::dispatch::Result as DispatchResult; use parity_codec::{Encode, Decode}; use system::ensure_none; use primitives::traits::{SimpleArithmetic, Header as HeaderT, One, Zero}; +use primitives::weights::SimpleDispatchInfo; pub trait Trait: system::Trait { /// Find the author of a block. @@ -217,6 +218,7 @@ decl_module! { } /// Provide a set of uncles. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn set_uncles(origin, new_uncles: Vec) -> DispatchResult { ensure_none(origin)?; diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 48960f1e544eb..ba3b034851d66 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -164,7 +164,7 @@ use primitives::traits::{ Saturating, Bounded, SignedExtension, SaturatedConversion, DispatchError }; use primitives::transaction_validity::{TransactionPriority, ValidTransaction}; -use primitives::weights::DispatchInfo; +use primitives::weights::{DispatchInfo, SimpleDispatchInfo}; use system::{IsDeadAccount, OnNewAccount, ensure_signed, ensure_root}; mod mock; @@ -428,6 +428,7 @@ decl_module! { /// `T::DustRemoval::on_unbalanced` and `T::OnFreeBalanceZero::on_free_balance_zero`. /// /// # + #[weight = SimpleDispatchInfo::FixedNormal(1_000)] pub fn transfer( origin, dest: ::Source, @@ -451,6 +452,7 @@ decl_module! { /// - Independent of the arguments. /// - Contains a limited number of reads and writes. /// # + #[weight = SimpleDispatchInfo::FixedOperational(500)] fn set_balance( origin, who: ::Source, diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index d729b8a300f7a..aa74c9a723aa1 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -23,6 +23,7 @@ use rstd::{prelude::*, result}; use substrate_primitives::u32_trait::Value as U32; use primitives::traits::{Hash, EnsureOrigin}; +use primitives::weights::SimpleDispatchInfo; use srml_support::{ dispatch::{Dispatchable, Parameter}, codec::{Encode, Decode}, traits::ChangeMembers, StorageValue, StorageMap, decl_module, decl_event, decl_storage, ensure @@ -118,6 +119,9 @@ decl_event!( } ); +// Note: this module is not benchmarked. The weights are obtained based on the similarity fo the +// executed logic with other democracy function. Note that councillor operations are assigned to the +// operational class. decl_module! { pub struct Module, I: Instance=DefaultInstance> for enum Call where origin: ::Origin { fn deposit_event() = default; @@ -126,6 +130,7 @@ decl_module! { /// provide it pre-sorted. /// /// Requires root origin. + #[weight = SimpleDispatchInfo::FixedOperational(100)] fn set_members(origin, new_members: Vec) { ensure_root(origin)?; @@ -168,6 +173,7 @@ decl_module! { /// Dispatch a proposal from a member using the `Member` origin. /// /// Origin must be a member of the collective. + #[weight = SimpleDispatchInfo::FixedOperational(1_00)] fn execute(origin, proposal: Box<>::Proposal>) { let who = ensure_signed(origin)?; ensure!(Self::is_member(&who), "proposer not a member"); @@ -181,9 +187,9 @@ decl_module! { /// - Bounded storage reads and writes. /// - Argument `threshold` has bearing on weight. /// # + #[weight = SimpleDispatchInfo::FixedOperational(5_000)] fn propose(origin, #[compact] threshold: MemberCount, proposal: Box<>::Proposal>) { let who = ensure_signed(origin)?; - ensure!(Self::is_member(&who), "proposer not a member"); let proposal_hash = T::Hashing::hash_of(&proposal); @@ -210,9 +216,9 @@ decl_module! { /// - Bounded storage read and writes. /// - Will be slightly heavier if the proposal is approved / disapproved after the vote. /// # + #[weight = SimpleDispatchInfo::FixedOperational(200)] fn vote(origin, proposal: T::Hash, #[compact] index: ProposalIndex, approve: bool) { let who = ensure_signed(origin)?; - ensure!(Self::is_member(&who), "voter not a member"); let mut voting = Self::voting(&proposal).ok_or("proposal must exist")?; @@ -554,7 +560,7 @@ mod tests { event: Event::collective_Instance1(RawEvent::Proposed( 1, 0, - hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + hex!["68eea8f20b542ec656c6ac2d10435ae3bd1729efc34d1354ab85af840aad2d35"].into(), 3, )), topics: vec![], @@ -622,7 +628,7 @@ mod tests { event: Event::collective_Instance1(RawEvent::Proposed( 1, 0, - hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + hex!["68eea8f20b542ec656c6ac2d10435ae3bd1729efc34d1354ab85af840aad2d35"].into(), 2, )), topics: vec![], @@ -631,7 +637,7 @@ mod tests { phase: Phase::Finalization, event: Event::collective_Instance1(RawEvent::Voted( 1, - hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + hex!["68eea8f20b542ec656c6ac2d10435ae3bd1729efc34d1354ab85af840aad2d35"].into(), false, 0, 1, @@ -658,7 +664,7 @@ mod tests { RawEvent::Proposed( 1, 0, - hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + hex!["68eea8f20b542ec656c6ac2d10435ae3bd1729efc34d1354ab85af840aad2d35"].into(), 3, )), topics: vec![], @@ -667,7 +673,7 @@ mod tests { phase: Phase::Finalization, event: Event::collective_Instance1(RawEvent::Voted( 2, - hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + hex!["68eea8f20b542ec656c6ac2d10435ae3bd1729efc34d1354ab85af840aad2d35"].into(), false, 1, 1, @@ -677,7 +683,7 @@ mod tests { EventRecord { phase: Phase::Finalization, event: Event::collective_Instance1(RawEvent::Disapproved( - hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + hex!["68eea8f20b542ec656c6ac2d10435ae3bd1729efc34d1354ab85af840aad2d35"].into(), )), topics: vec![], } @@ -700,7 +706,7 @@ mod tests { event: Event::collective_Instance1(RawEvent::Proposed( 1, 0, - hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + hex!["68eea8f20b542ec656c6ac2d10435ae3bd1729efc34d1354ab85af840aad2d35"].into(), 2, )), topics: vec![], @@ -709,7 +715,7 @@ mod tests { phase: Phase::Finalization, event: Event::collective_Instance1(RawEvent::Voted( 2, - hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + hex!["68eea8f20b542ec656c6ac2d10435ae3bd1729efc34d1354ab85af840aad2d35"].into(), true, 2, 0, @@ -719,14 +725,14 @@ mod tests { EventRecord { phase: Phase::Finalization, event: Event::collective_Instance1(RawEvent::Approved( - hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + hex!["68eea8f20b542ec656c6ac2d10435ae3bd1729efc34d1354ab85af840aad2d35"].into(), )), topics: vec![], }, EventRecord { phase: Phase::Finalization, event: Event::collective_Instance1(RawEvent::Executed( - hex!["10b209e55d0f37cd45574674bba42519a29bf0ccf3c85c3c773fcbacab820bb4"].into(), + hex!["68eea8f20b542ec656c6ac2d10435ae3bd1729efc34d1354ab85af840aad2d35"].into(), false, )), topics: vec![], diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index cb7f665b30cc5..ae38f6cc779ae 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -21,6 +21,7 @@ use rstd::prelude::*; use rstd::{result, convert::TryFrom}; use primitives::traits::{Zero, Bounded, CheckedMul, CheckedDiv, EnsureOrigin, Hash}; +use primitives::weights::SimpleDispatchInfo; use parity_codec::{Encode, Decode, Input, Output}; use srml_support::{ decl_module, decl_storage, decl_event, ensure, @@ -359,6 +360,7 @@ decl_module! { /// - O(1). /// - Two DB changes, one DB entry. /// # + #[weight = SimpleDispatchInfo::FixedNormal(5_000)] fn propose(origin, proposal: Box, #[compact] value: BalanceOf @@ -386,6 +388,7 @@ decl_module! { /// - O(1). /// - One DB entry. /// # + #[weight = SimpleDispatchInfo::FixedNormal(5_000)] fn second(origin, #[compact] proposal: PropIndex) { let who = ensure_signed(origin)?; let mut deposit = Self::deposit_of(proposal) @@ -403,6 +406,7 @@ decl_module! { /// - O(1). /// - One DB change, one DB entry. /// # + #[weight = SimpleDispatchInfo::FixedNormal(200)] fn vote(origin, #[compact] ref_index: ReferendumIndex, vote: Vote @@ -418,6 +422,7 @@ decl_module! { /// - O(1). /// - One DB change, one DB entry. /// # + #[weight = SimpleDispatchInfo::FixedNormal(200)] fn proxy_vote(origin, #[compact] ref_index: ReferendumIndex, vote: Vote @@ -432,6 +437,7 @@ decl_module! { /// exceed `threshold` and, if approved, enacted after the given `delay`. /// /// It may be called from either the Root or the Emergency origin. + #[weight = SimpleDispatchInfo::FixedOperational(500)] fn emergency_propose(origin, proposal: Box, threshold: VoteThreshold, @@ -453,6 +459,7 @@ decl_module! { /// Schedule an emergency cancellation of a referendum. Cannot happen twice to the same /// referendum. + #[weight = SimpleDispatchInfo::FixedOperational(500)] fn emergency_cancel(origin, ref_index: ReferendumIndex) { T::CancellationOrigin::ensure_origin(origin)?; @@ -466,6 +473,7 @@ decl_module! { /// Schedule a referendum to be tabled once it is legal to schedule an external /// referendum. + #[weight = SimpleDispatchInfo::FixedNormal(5_000)] fn external_propose(origin, proposal: Box) { T::ExternalOrigin::ensure_origin(origin)?; ensure!(!>::exists(), "proposal already made"); @@ -478,6 +486,7 @@ decl_module! { /// Schedule a majority-carries referendum to be tabled next once it is legal to schedule /// an external referendum. + #[weight = SimpleDispatchInfo::FixedNormal(5_000)] fn external_propose_majority(origin, proposal: Box) { T::ExternalMajorityOrigin::ensure_origin(origin)?; ensure!(!>::exists(), "proposal already made"); @@ -496,6 +505,7 @@ decl_module! { /// - `voting_period`: The period that is allowed for voting on this proposal. /// - `delay`: The number of block after voting has ended in approval and this should be /// enacted. Increased to `EmergencyVotingPeriod` if too low. + #[weight = SimpleDispatchInfo::FixedNormal(200)] fn external_push(origin, proposal_hash: T::Hash, voting_period: T::BlockNumber, @@ -514,6 +524,7 @@ decl_module! { } /// Veto and blacklist the external proposal hash. + #[weight = SimpleDispatchInfo::FixedNormal(200)] fn veto_external(origin, proposal_hash: T::Hash) { let who = T::VetoOrigin::ensure_origin(origin)?; @@ -538,12 +549,14 @@ decl_module! { } /// Remove a referendum. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn cancel_referendum(origin, #[compact] ref_index: ReferendumIndex) { ensure_root(origin)?; Self::clear_referendum(ref_index); } /// Cancel a proposal queued for enactment. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn cancel_queued( origin, #[compact] when: T::BlockNumber, @@ -572,6 +585,7 @@ decl_module! { /// # /// - One extra DB entry. /// # + #[weight = SimpleDispatchInfo::FixedNormal(100)] fn set_proxy(origin, proxy: T::AccountId) { let who = ensure_signed(origin)?; ensure!(!>::exists(&proxy), "already a proxy"); @@ -583,6 +597,7 @@ decl_module! { /// # /// - One DB clear. /// # + #[weight = SimpleDispatchInfo::FixedNormal(100)] fn resign_proxy(origin) { let who = ensure_signed(origin)?; >::remove(who); @@ -593,6 +608,7 @@ decl_module! { /// # /// - One DB clear. /// # + #[weight = SimpleDispatchInfo::FixedNormal(100)] fn remove_proxy(origin, proxy: T::AccountId) { let who = ensure_signed(origin)?; ensure!(&Self::proxy(&proxy).ok_or("not a proxy")? == &who, "wrong proxy"); @@ -604,6 +620,7 @@ decl_module! { /// # /// - One extra DB entry. /// # + #[weight = SimpleDispatchInfo::FixedNormal(500)] pub fn delegate(origin, to: T::AccountId, conviction: Conviction) { let who = ensure_signed(origin)?; >::insert(who.clone(), (to.clone(), conviction)); @@ -623,6 +640,7 @@ decl_module! { /// # /// - O(1). /// # + #[weight = SimpleDispatchInfo::FixedNormal(500)] fn undelegate(origin) { let who = ensure_signed(origin)?; ensure!(>::exists(&who), "not delegated"); diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 0f2bf3df12f71..d17a1e0948eb3 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -25,6 +25,7 @@ use rstd::prelude::*; use primitives::traits::{Zero, One, StaticLookup, Bounded, Saturating}; +use primitives::weights::SimpleDispatchInfo; use runtime_io::print; use srml_support::{ StorageValue, StorageMap, @@ -326,6 +327,7 @@ decl_module! { /// - Two extra DB entries, one DB change. /// - Argument `votes` is limited in length to number of candidates. /// # + #[weight = SimpleDispatchInfo::FixedNormal(2_500)] fn set_approvals(origin, votes: Vec, #[compact] index: VoteIndex, hint: SetIndex) -> Result { let who = ensure_signed(origin)?; Self::do_set_approvals(who, votes, index, hint) @@ -337,6 +339,7 @@ decl_module! { /// # /// - Same as `set_approvals` with one additional storage read. /// # + #[weight = SimpleDispatchInfo::FixedNormal(2_500)] fn proxy_set_approvals(origin, votes: Vec, #[compact] index: VoteIndex, @@ -358,6 +361,7 @@ decl_module! { /// - O(1). /// - Two fewer DB entries, one DB change. /// # + #[weight = SimpleDispatchInfo::FixedNormal(2_500)] fn reap_inactive_voter( origin, #[compact] reporter_index: u32, @@ -431,6 +435,7 @@ decl_module! { /// - O(1). /// - Two fewer DB entries, one DB change. /// # + #[weight = SimpleDispatchInfo::FixedNormal(1_250)] fn retract_voter(origin, #[compact] index: u32) { let who = ensure_signed(origin)?; @@ -458,6 +463,7 @@ decl_module! { /// - Independent of input. /// - Three DB changes. /// # + #[weight = SimpleDispatchInfo::FixedNormal(2_500)] fn submit_candidacy(origin, #[compact] slot: u32) { let who = ensure_signed(origin)?; @@ -493,6 +499,7 @@ decl_module! { /// - O(voters) compute. /// - One DB change. /// # + #[weight = SimpleDispatchInfo::FixedNormal(10_000)] fn present_winner( origin, candidate: ::Source, @@ -561,6 +568,7 @@ decl_module! { /// Set the desired member count; if lower than the current count, then seats will not be up /// election when they expire. If more, then a new vote will be started if one is not /// already in progress. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn set_desired_seats(origin, #[compact] count: u32) { ensure_root(origin)?; DesiredSeats::put(count); @@ -570,6 +578,7 @@ decl_module! { /// /// Note: A tally should happen instantly (if not already in a presentation /// period) to fill the seat if removal means that the desired members are not met. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn remove_member(origin, who: ::Source) { ensure_root(origin)?; let who = T::Lookup::lookup(who)?; @@ -584,6 +593,7 @@ decl_module! { /// Set the presentation duration. If there is currently a vote being presented for, will /// invoke `finalize_vote`. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn set_presentation_duration(origin, #[compact] count: T::BlockNumber) { ensure_root(origin)?; >::put(count); @@ -591,6 +601,7 @@ decl_module! { /// Set the presentation duration. If there is current a vote being presented for, will /// invoke `finalize_vote`. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn set_term_duration(origin, #[compact] count: T::BlockNumber) { ensure_root(origin)?; >::put(count); diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 326c3d7ab95d9..2910d1a5ddca5 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -108,6 +108,7 @@ mod internal { fn from(d: DispatchError) -> Self { match d { DispatchError::Payment => ApplyError::CantPay, + DispatchError::Resource => ApplyError::FullBlock, DispatchError::NoPermission => ApplyError::CantPay, DispatchError::BadState => ApplyError::CantPay, DispatchError::Stale => ApplyError::Stale, @@ -562,7 +563,8 @@ mod tests { let xt = primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer::(33, 0)); let encoded = xt.encode(); let encoded_len = encoded.len() as u32; - let limit = >::get() / 4; + // TODO: this should be fetched from the test system once the ratio is exposed as a const. + let limit = >::get() * 3 / 4; let num_to_exhaust_block = limit / encoded_len; with_externalities(&mut t, || { Executive::initialize_block(&Header::new( @@ -582,7 +584,7 @@ mod tests { assert_eq!(>::all_extrinsics_weight(), encoded_len * (nonce + 1)); assert_eq!(>::extrinsic_index(), Some(nonce + 1)); } else { - assert_eq!(res, Err(ApplyError::CantPay)); + assert_eq!(res, Err(ApplyError::FullBlock)); } } }); diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 546513c953afb..0476b2b1137a8 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -122,6 +122,7 @@ use rstd::{prelude::*, marker::PhantomData, ops::{Sub, Rem}}; use parity_codec::{Decode, Encode}; use primitives::KeyTypeId; +use primitives::weights::SimpleDispatchInfo; use primitives::traits::{Convert, Zero, Member, OpaqueKeys, TypedKey, Hash}; use srml_support::{ dispatch::Result, @@ -355,6 +356,7 @@ decl_module! { /// - O(log n) in number of accounts. /// - One extra DB entry. /// # + #[weight = SimpleDispatchInfo::FixedOperational(150)] // TODO: this is operational? fn set_keys(origin, keys: T::Keys, proof: Vec) -> Result { let who = ensure_signed(origin)?; diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index 7dfe7b60e9f03..eac5951b3b906 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -283,6 +283,7 @@ use srml_support::{ }; use session::{historical::OnSessionEnding, SelectInitialValidators, SessionIndex}; use primitives::Perbill; +use primitives::weights::SimpleDispatchInfo; use primitives::traits::{ Convert, Zero, One, StaticLookup, CheckedSub, CheckedShl, Saturating, Bounded, }; @@ -665,6 +666,7 @@ decl_module! { /// NOTE: Two of the storage writes (`Self::bonded`, `Self::payee`) are _never_ cleaned unless /// the `origin` falls below _existential deposit_ and gets removed as dust. /// # + #[weight = SimpleDispatchInfo::FixedNormal(500)] fn bond(origin, controller: ::Source, #[compact] value: BalanceOf, @@ -712,6 +714,7 @@ decl_module! { /// - O(1). /// - One DB entry. /// # + #[weight = SimpleDispatchInfo::FixedNormal(500)] fn bond_extra(origin, #[compact] max_additional: BalanceOf) { let stash = ensure_signed(origin)?; @@ -751,6 +754,7 @@ decl_module! { /// The only way to clean the aforementioned storage item is also user-controlled via `withdraw_unbonded`. /// - One DB entry. /// + #[weight = SimpleDispatchInfo::FixedNormal(400)] fn unbond(origin, #[compact] value: BalanceOf) { let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -792,6 +796,7 @@ decl_module! { /// - Contains a limited number of reads, yet the size of which could be large based on `ledger`. /// - Writes are limited to the `origin` account key. /// # + #[weight = SimpleDispatchInfo::FixedNormal(400)] fn withdraw_unbonded(origin) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -823,6 +828,7 @@ decl_module! { /// - Contains a limited number of reads. /// - Writes are limited to the `origin` account key. /// # + #[weight = SimpleDispatchInfo::FixedNormal(750)] fn validate(origin, prefs: ValidatorPrefs>) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -846,6 +852,7 @@ decl_module! { /// which is capped at `MAX_NOMINATIONS`. /// - Both the reads and writes follow a similar pattern. /// # + #[weight = SimpleDispatchInfo::FixedNormal(750)] fn nominate(origin, targets: Vec<::Source>) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -871,6 +878,7 @@ decl_module! { /// - Contains one read. /// - Writes are limited to the `origin` account key. /// # + #[weight = SimpleDispatchInfo::FixedNormal(500)] fn chill(origin) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -890,6 +898,7 @@ decl_module! { /// - Contains a limited number of reads. /// - Writes are limited to the `origin` account key. /// # + #[weight = SimpleDispatchInfo::FixedNormal(500)] fn set_payee(origin, payee: RewardDestination) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -908,6 +917,7 @@ decl_module! { /// - Contains a limited number of reads. /// - Writes are limited to the `origin` account key. /// # + #[weight = SimpleDispatchInfo::FixedNormal(750)] fn set_controller(origin, controller: ::Source) { let stash = ensure_signed(origin)?; let old_controller = Self::bonded(&stash).ok_or("not a stash")?; @@ -924,6 +934,7 @@ decl_module! { } /// The ideal number of validators. + #[weight = SimpleDispatchInfo::FixedOperational(150)] fn set_validator_count(origin, #[compact] new: u32) { ensure_root(origin)?; ValidatorCount::put(new); @@ -939,18 +950,21 @@ decl_module! { /// - Triggers the Phragmen election. Expensive but not user-controlled. /// - Depends on state: `O(|edges| * |validators|)`. /// # + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn force_new_era(origin) { ensure_root(origin)?; Self::apply_force_new_era() } /// Set the offline slash grace period. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn set_offline_slash_grace(origin, #[compact] new: u32) { ensure_root(origin)?; OfflineSlashGrace::put(new); } /// Set the validators who cannot be slashed (if any). + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn set_invulnerables(origin, validators: Vec) { ensure_root(origin)?; >::put(validators); diff --git a/srml/sudo/src/lib.rs b/srml/sudo/src/lib.rs index a421bdae68a52..2662db7adfd6a 100644 --- a/srml/sudo/src/lib.rs +++ b/srml/sudo/src/lib.rs @@ -88,6 +88,7 @@ use sr_std::prelude::*; use sr_primitives::traits::StaticLookup; +use sr_primitives::weights::SimpleDispatchInfo; use srml_support::{ StorageValue, Parameter, Dispatchable, decl_module, decl_event, decl_storage, ensure @@ -116,6 +117,7 @@ decl_module! { /// - Limited storage reads. /// - No DB writes. /// # + #[weight = SimpleDispatchInfo::FixedOperational(1_000)] fn sudo(origin, proposal: Box) { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index 7afbd11cd1d0d..3d2cc3b924e66 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -1622,7 +1622,7 @@ mod tests { fn aux_0(_origin) -> Result { unreachable!() } fn aux_1(_origin, #[compact] _data: u32) -> Result { unreachable!() } fn aux_2(_origin, _data: i32, _data2: String) -> Result { unreachable!() } - #[weight = SimpleDispatchInfo::FixedNormal(10)] + #[weight = SimpleDispatchInfo::FixedNormal(3)] fn aux_3(_origin) -> Result { unreachable!() } fn aux_4(_origin, _data: i32) -> Result { unreachable!() } fn aux_5(_origin, _data: i32, #[compact] _data2: u32) -> Result { unreachable!() } @@ -1775,17 +1775,17 @@ mod tests { // max weight. not dependent on input. assert_eq!( Call::::operational().get_dispatch_info(), - DispatchInfo { weight: 5, class: DispatchClass::Operational }, + DispatchInfo { weight: 5 * 1000, class: DispatchClass::Operational }, ); // default weight. assert_eq!( Call::::aux_0().get_dispatch_info(), - DispatchInfo { weight: 100, class: DispatchClass::Normal }, + DispatchInfo { weight: 10 * 1000, class: DispatchClass::Normal }, ); // custom basic assert_eq!( Call::::aux_3().get_dispatch_info(), - DispatchInfo { weight: 10, class: DispatchClass::Normal }, + DispatchInfo { weight: 3 * 1000, class: DispatchClass::Normal }, ); } } diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index 361fef969b3a1..a6840c8b8b463 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -220,6 +220,37 @@ macro_rules! __assert_eq_uvec { } } +/// Checks that `$x` is equal to `$y` with an error rate of `$error`. +/// +/// # Example +/// +/// ```rust +/// #[macro_use] +/// # extern crate srml_support; +/// # use srml_support::{assert_eq_error_rate}; +/// # fn main() { +/// assert_eq_error_rate!(10, 10, 0); +/// assert_eq_error_rate!(10, 11, 1); +/// assert_eq_error_rate!(12, 10, 2); +/// # } +/// ``` +/// +/// ```rust,should_panic +/// #[macro_use] +/// # extern crate srml_support; +/// # use srml_support::{assert_eq_error_rate}; +/// # fn main() { +/// assert_eq_error_rate!(12, 10, 1); +/// # } +/// ``` +#[macro_export] +#[cfg(feature = "std")] +macro_rules! assert_eq_error_rate { + ($x:expr, $y:expr, $error:expr) => { + assert!(($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error))); + }; +} + /// The void type - it cannot exist. // Oh rust, you crack me up... #[derive(Clone, Eq, PartialEq)] diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index bd1f76299e49c..623bb8bc750d6 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -78,7 +78,8 @@ use rstd::prelude::*; use rstd::map; use rstd::marker::PhantomData; use primitives::generic::{self, Era}; -use primitives::weights::{Weight, DispatchInfo, DispatchClass, WeightMultiplier}; +use primitives::Perbill; +use primitives::weights::{Weight, DispatchInfo, DispatchClass, WeightMultiplier, SimpleDispatchInfo}; use primitives::transaction_validity::{ValidTransaction, TransactionPriority, TransactionLongevity}; use primitives::traits::{self, CheckEqual, SimpleArithmetic, Zero, SignedExtension, Convert, SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, CurrentHeight, BlockNumberToHash, @@ -218,24 +219,35 @@ decl_module! { Self::deposit_event_indexed(&[], event); } + /// A big dispatch that will disallow any other transaction to be included. + // TODO: this must be preferable available for testing really (not possible at the moment). + #[weight = SimpleDispatchInfo::MaxOperational] + fn fill_block(origin) { + ensure_root(origin)?; + } + /// Make some on-chain remark. + #[weight = SimpleDispatchInfo::FixedNormal(1_000)] fn remark(origin, _remark: Vec) { ensure_signed(origin)?; } /// Set the number of pages in the WebAssembly environment's heap. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn set_heap_pages(origin, pages: u64) { ensure_root(origin)?; storage::unhashed::put_raw(well_known_keys::HEAP_PAGES, &pages.encode()); } /// Set the new code. + #[weight = SimpleDispatchInfo::FixedOperational(200)] pub fn set_code(origin, new: Vec) { ensure_root(origin)?; storage::unhashed::put_raw(well_known_keys::CODE, &new); } /// Set some items of storage. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn set_storage(origin, items: Vec) { ensure_root(origin)?; for i in &items { @@ -244,6 +256,7 @@ decl_module! { } /// Kill some items from storage. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn kill_storage(origin, keys: Vec) { ensure_root(origin)?; for key in &keys { @@ -792,26 +805,28 @@ pub struct CheckWeight(PhantomData); impl CheckWeight { - /// Get the quota divisor of each dispatch class type. This indicates that all operational + /// Get the quota ratio of each dispatch class type. This indicates that all operational /// dispatches can use the full capacity of any resource, while user-triggered ones can consume - /// a quarter. - fn get_dispatch_limit_divisor(class: DispatchClass) -> Weight { + /// a portion. + fn get_dispatch_limit_ratio(class: DispatchClass) -> Perbill { match class { - DispatchClass::Operational => 1, - DispatchClass::Normal => 4, + DispatchClass::Operational => Perbill::one(), + // TODO: this must be some sort of a constant. + DispatchClass::Normal => Perbill::from_percent(75), } } + /// Checks if the current extrinsic can fit into the block with respect to block weight limits. /// /// Upon successes, it returns the new block weight as a `Result`. fn check_weight(info: DispatchInfo) -> Result { let current_weight = Module::::all_extrinsics_weight(); let maximum_weight = T::MaximumBlockWeight::get(); - let limit = maximum_weight / Self::get_dispatch_limit_divisor(info.class); + let limit = Self::get_dispatch_limit_ratio(info.class) * maximum_weight; let added_weight = info.weight.min(limit); let next_weight = current_weight.saturating_add(added_weight); if next_weight > limit { - return Err(DispatchError::BadState) + return Err(DispatchError::Resource) } Ok(next_weight) } @@ -822,11 +837,11 @@ impl CheckWeight { fn check_block_length(info: DispatchInfo, len: usize) -> Result { let current_len = Module::::all_extrinsics_len(); let maximum_len = T::MaximumBlockLength::get(); - let limit = maximum_len / Self::get_dispatch_limit_divisor(info.class); + let limit = Self::get_dispatch_limit_ratio(info.class) * maximum_len; let added_len = len as u32; let next_len = current_len.saturating_add(added_len); if next_len > limit { - return Err(DispatchError::BadState) + return Err(DispatchError::Resource) } Ok(next_len) } @@ -872,8 +887,8 @@ impl SignedExtension for CheckWeight { len: usize, ) -> Result { // There is no point in writing to storage here since changes are discarded. This basically - // discards any transaction which is bigger than the length or weight limit alone, which is - // a guarantee that it will fail in the pre-dispatch phase. + // discards any transaction which is bigger than the length or weight limit __alone__,which + // is a guarantee that it will fail in the pre-dispatch phase. let _ = Self::check_block_length(info, len)?; let _ = Self::check_weight(info)?; Ok(ValidTransaction { priority: Self::get_priority(info), ..Default::default() }) @@ -1222,15 +1237,16 @@ mod tests { } #[test] - fn signed_ext_check_weight_works_user_tx() { + fn signed_ext_check_weight_works_normal_tx() { with_externalities(&mut new_test_ext(), || { + let normal_limit = >::get() * 3 / 4; let small = DispatchInfo { weight: 100, ..Default::default() }; let medium = DispatchInfo { - weight: >::get() / 4 - 1, + weight: normal_limit - 1, ..Default::default() }; let big = DispatchInfo { - weight: >::get() / 4 + 1, + weight: normal_limit + 1, ..Default::default() }; let len = 0_usize; @@ -1265,11 +1281,12 @@ mod tests { with_externalities(&mut new_test_ext(), || { let max = DispatchInfo { weight: Weight::max_value(), ..Default::default() }; let len = 0_usize; + let normal_limit = >::get() * 3 / 4; assert_eq!(System::all_extrinsics_weight(), 0); let r = CheckWeight::(PhantomData).pre_dispatch(&1, max, len); assert!(r.is_ok()); - assert_eq!(System::all_extrinsics_weight(), >::get() / 4); + assert_eq!(System::all_extrinsics_weight(), normal_limit); }) } @@ -1279,9 +1296,10 @@ mod tests { let normal = DispatchInfo { weight: 100, ..Default::default() }; let op = DispatchInfo { weight: 100, class: DispatchClass::Operational }; let len = 0_usize; + let normal_limit = >::get() * 3 / 4; // given almost full block - AllExtrinsicsWeight::put(>::get() / 4); + AllExtrinsicsWeight::put(normal_limit); // will not fit. assert!(CheckWeight::(PhantomData).pre_dispatch(&1, normal, len).is_err()); // will fit. @@ -1289,7 +1307,7 @@ mod tests { // likewise for length limit. let len = 100_usize; - AllExtrinsicsLen::put(>::get() / 4); + AllExtrinsicsLen::put(>::get() * 3 / 4); assert!(CheckWeight::(PhantomData).pre_dispatch(&1, normal, len).is_err()); assert!(CheckWeight::(PhantomData).pre_dispatch(&1, op, len).is_ok()); }) @@ -1317,16 +1335,16 @@ mod tests { fn signed_ext_check_weight_block_size_works() { with_externalities(&mut new_test_ext(), || { let tx = DispatchInfo::default(); - + let normal_limit = (>::get() * 3 / 4) as usize; let reset_check_weight = |s, f| { AllExtrinsicsLen::put(0); let r = CheckWeight::(PhantomData).pre_dispatch(&1, tx, s); if f { assert!(r.is_err()) } else { assert!(r.is_ok()) } }; - reset_check_weight(128, false); - reset_check_weight(512, false); - reset_check_weight(513, true); + reset_check_weight(normal_limit - 1, false); + reset_check_weight(normal_limit, false); + reset_check_weight(normal_limit + 1, true); }) } diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index 43aa29e04fd24..ae99938991a68 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -98,6 +98,7 @@ use parity_codec::Decode; use inherents::ProvideInherentData; use srml_support::{StorageValue, Parameter, decl_storage, decl_module, for_each_tuple, traits::Get}; use runtime_primitives::traits::{SimpleArithmetic, Zero, SaturatedConversion}; +use runtime_primitives::weights::SimpleDispatchInfo; use system::ensure_none; use inherents::{RuntimeString, InherentIdentifier, ProvideInherent, IsFatalError, InherentData}; @@ -235,6 +236,7 @@ decl_module! { /// `MinimumPeriod`. /// /// The dispatch origin for this call must be `Inherent`. + #[weight = SimpleDispatchInfo::FixedOperational(10)] fn set(origin, #[compact] now: T::Moment) { ensure_none(origin)?; assert!(!::DidUpdate::exists(), "Timestamp must be updated only once in the block"); diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index c8cf84355aca0..3a0b218090308 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -79,6 +79,7 @@ use runtime_primitives::{Permill, ModuleId}; use runtime_primitives::traits::{ Zero, EnsureOrigin, StaticLookup, CheckedSub, CheckedMul, AccountIdConversion }; +use runtime_primitives::weights::SimpleDispatchInfo; use parity_codec::{Encode, Decode}; use system::ensure_signed; @@ -153,6 +154,7 @@ decl_module! { /// - Limited storage reads. /// - One DB change, one extra DB entry. /// # + #[weight = SimpleDispatchInfo::FixedNormal(500)] fn propose_spend( origin, #[compact] value: BalanceOf, @@ -179,6 +181,7 @@ decl_module! { /// - Limited storage reads. /// - One DB clear. /// # + #[weight = SimpleDispatchInfo::FixedOperational(100)] fn reject_proposal(origin, #[compact] proposal_id: ProposalIndex) { T::RejectOrigin::ensure_origin(origin)?; let proposal = >::take(proposal_id).ok_or("No proposal at that index")?; @@ -196,6 +199,7 @@ decl_module! { /// - Limited storage reads. /// - One DB change. /// # + #[weight = SimpleDispatchInfo::FixedOperational(100)] fn approve_proposal(origin, #[compact] proposal_id: ProposalIndex) { T::ApproveOrigin::ensure_origin(origin)?; From 045681e2e91c61b68455cce3865361bd8c870f74 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Mon, 22 Jul 2019 15:07:51 +0200 Subject: [PATCH 20/33] Refactor weight to u64. --- core/sr-primitives/src/lib.rs | 46 +++++++++++++++++------- core/sr-primitives/src/testing.rs | 4 +-- core/sr-primitives/src/weights.rs | 2 +- node-template/runtime/src/lib.rs | 3 ++ node-template/runtime/src/template.rs | 3 ++ node/cli/src/chain_spec.rs | 3 +- node/cli/src/service.rs | 3 +- node/executor/src/lib.rs | 12 +++---- node/runtime/src/constants.rs | 52 +++++++++++++++++++++++++++ node/runtime/src/impls.rs | 35 +++++++++--------- node/runtime/src/lib.rs | 30 +++++----------- srml/assets/src/lib.rs | 4 ++- srml/aura/src/mock.rs | 4 ++- srml/authorship/src/lib.rs | 3 ++ srml/balances/src/lib.rs | 4 ++- srml/balances/src/mock.rs | 4 ++- srml/collective/src/lib.rs | 4 ++- srml/contracts/src/tests.rs | 4 ++- srml/council/src/lib.rs | 3 ++ srml/democracy/src/lib.rs | 3 ++ srml/elections/src/lib.rs | 4 ++- srml/example/src/lib.rs | 4 ++- srml/executive/src/lib.rs | 13 ++++--- srml/finality-tracker/src/lib.rs | 3 ++ srml/generic-asset/src/lib.rs | 1 + srml/generic-asset/src/mock.rs | 7 ++-- srml/grandpa/src/mock.rs | 4 ++- srml/indices/src/mock.rs | 3 ++ srml/session/src/mock.rs | 3 ++ srml/staking/src/mock.rs | 2 ++ srml/system/src/lib.rs | 47 +++++++++++++++++------- srml/timestamp/src/lib.rs | 4 ++- srml/treasury/src/lib.rs | 4 ++- 33 files changed, 230 insertions(+), 95 deletions(-) create mode 100644 node/runtime/src/constants.rs diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 9220fb5455d1e..cbba1d750f996 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -170,7 +170,7 @@ pub type ConsensusEngineId = [u8; 4]; /// Permill is parts-per-million (i.e. after multiplying by this, divide by 1000000). #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Ord, PartialOrd))] #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)] -pub struct Permill(pub u32); +pub struct Permill(u32); impl Permill { /// Nothing. @@ -182,6 +182,11 @@ impl Permill { /// Everything. pub fn one() -> Self { Self(1_000_000) } + /// create a new raw instance. This can be called at compile time. + pub const fn from_const_parts(parts: u32) -> Self { + Self([parts, 1_000_000] [(parts > 1_000_000) as usize]) + } + /// From an explicitly defined number of parts per maximum of the type. pub fn from_parts(x: u32) -> Self { Self(x.min(1_000_000)) } @@ -274,7 +279,7 @@ impl From> for Permill { /// provides a means to multiply some other value by that. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)] -pub struct Perbill(pub u32); +pub struct Perbill(u32); impl Perbill { /// Nothing. @@ -286,6 +291,11 @@ impl Perbill { /// Everything. pub fn one() -> Self { Self(1_000_000_000) } + /// create a new raw instance. This can be called at compile time. + pub const fn from_const_parts(parts: u32) -> Self { + Self([parts, 1_000_000_000] [(parts > 1_000_000_000) as usize]) + } + /// From an explicitly defined number of parts per maximum of the type. pub fn from_parts(x: u32) -> Self { Self(x.min(1_000_000_000)) } @@ -383,7 +393,7 @@ impl From> for Perbill { /// cannot hold a value larger than +-`9223372036854775807 / 1_000_000_000` (~9 billion). #[cfg_attr(feature = "std", derive(Debug))] #[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct Fixed64(pub i64); +pub struct Fixed64(i64); /// The maximum value of the `Fixed64` type const DIV: i64 = 1_000_000_000; @@ -411,13 +421,17 @@ impl Fixed64 { /// Performs a saturated multiply and accumulate. /// - /// Returns `n + (self * n)`. - pub fn saturated_multiply_accumulate(&self, int: u32) -> u32 { + /// Returns a saturated `n + (self * n)`. + pub fn saturated_multiply_accumulate(&self, int: N) -> N + where N: Copy + Clone + From + Saturating + Bounded + UniqueSaturatedInto + + From + ops::Rem + ops::Div + ops::Mul + + ops::Add, + { let parts = self.0; - let positive = parts > 0; + // natural parts might overflow. - let natural_parts = self.clone().saturated_into::(); + let natural_parts = self.clone().saturated_into::(); // fractional parts can always fit into u32. let perbill_parts = (parts.abs() % DIV) as u32; @@ -439,14 +453,22 @@ impl Fixed64 { } } -impl UniqueSaturatedInto for Fixed64 { - /// Note that the maximum value of Fixed64 might be more than what can fit in u32. This is hence, - /// expected to be lossy. - fn unique_saturated_into(self) -> u32 { - (self.0.abs() / DIV).try_into().unwrap_or(Bounded::max_value()) +macro_rules! impl_from_for_unsigned { + ( $($type:ty),+ ) => { + $( + impl From for $type { + fn from(t: Fixed64) -> Self { + // Note that such implementation with `max(0)` only makes sense for unsigned + // numbers. + (t.0.max(0) / DIV).try_into().unwrap_or(Bounded::max_value()) + } + } + )* } } +impl_from_for_unsigned!(u16, u32, u64, u128); + impl Saturating for Fixed64 { fn saturating_add(self, rhs: Self) -> Self { Self(self.0.saturating_add(rhs.0)) diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index fcafe6dad97de..32c52f6981c56 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -24,7 +24,7 @@ use crate::traits::{ ValidateUnsigned, SignedExtension, Dispatchable, }; use crate::{generic, KeyTypeId}; -use crate::weights::{GetDispatchInfo, DispatchInfo}; +use crate::weights::{GetDispatchInfo, DispatchInfo, Weight}; pub use substrate_primitives::H256; use substrate_primitives::U256; use substrate_primitives::ed25519::{Public as AuthorityId}; @@ -282,7 +282,7 @@ impl GetDispatchInfo for TestXt { fn get_dispatch_info(&self) -> DispatchInfo { // for testing: weight == size. DispatchInfo { - weight: self.encode().len() as u32, + weight: self.encode().len() as Weight, ..Default::default() } } diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index bae0b0c636459..7c52f7d2dba49 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -30,7 +30,7 @@ pub use crate::transaction_validity::TransactionPriority; use crate::traits::Bounded; /// Numeric range of a transaction weight. -pub type Weight = u32; +pub type Weight = u64; /// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions /// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`). diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 2f9927235ad1d..b239c55de27e1 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -103,6 +103,7 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const BlockHashCount: BlockNumber = 250; pub const MaximumBlockWeight: Weight = 1_000_000_000; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; } @@ -131,6 +132,8 @@ impl system::Trait for Runtime { type BlockHashCount = BlockHashCount; /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. type MaximumBlockWeight = MaximumBlockWeight; + /// Portion of the block weight that is available to all normal transactions. + type AvailableBlockRatio = AvailableBlockRatio; /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. type MaximumBlockLength = MaximumBlockLength; } diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index 63b5e27b9674e..34818abe1801b 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -74,6 +74,7 @@ mod tests { use support::{impl_outer_origin, assert_ok, parameter_types}; use sr_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; use sr_primitives::weights::Weight; + use sr_primitives::Perbill; impl_outer_origin! { pub enum Origin for Test {} @@ -88,6 +89,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: Weight = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75)); } impl system::Trait for Test { type Origin = Origin; @@ -102,6 +104,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } impl Trait for Test { diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index fc07ae4cea4d9..bdfe9b65b0df9 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -22,8 +22,9 @@ use node_runtime::{ GrandpaConfig, BalancesConfig, ContractsConfig, ElectionsConfig, DemocracyConfig, CouncilConfig, AuraConfig, ImOnlineConfig, IndicesConfig, SessionConfig, StakingConfig, SudoConfig, TechnicalCommitteeConfig, SystemConfig, WASM_BINARY, Perbill, SessionKeys, - StakerStatus, DAYS, DOLLARS, MILLICENTS, + StakerStatus, }; +use node_runtime::constants::{time::*, currency::*}; pub use node_runtime::GenesisConfig; use substrate_service; use hex_literal::hex; diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 33eac33d084e1..1cd5ce2821c19 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -216,7 +216,8 @@ mod tests { use aura::CompatibleDigestItem; use consensus_common::{Environment, Proposer, ImportBlock, BlockOrigin, ForkChoiceStrategy}; use node_primitives::DigestItem; - use node_runtime::{BalancesCall, Call, CENTS, SECS_PER_BLOCK, UncheckedExtrinsic}; + use node_runtime::{BalancesCall, Call, UncheckedExtrinsic}; + use node_runtime::constants::{currency::CENTS, time::SECS_PER_BLOCK}; use parity_codec::{Encode, Decode}; use primitives::{ crypto::Pair as CryptoPair, ed25519::Pair, blake2_256, diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index f7088d51fb4f4..1605c0a24d9a3 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -49,17 +49,17 @@ mod tests { 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::{WeightMultiplier, SimpleDispatchInfo, GetDispatchInfo, WeighData}; + use runtime_primitives::weights::{WeightMultiplier, SimpleDispatchInfo, GetDispatchInfo, WeighData, Weight}; 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, CreationFee, - CENTS, DOLLARS, MILLICENTS, SignedExtra, TransactionBaseFee, TransactionByteFee, - MaximumBlockWeight, + GrandpaConfig, IndicesConfig, ContractsConfig, Event, SessionKeys, CreationFee, SignedExtra, + TransactionBaseFee, TransactionByteFee, MaximumBlockWeight, }; + use node_runtime::constants::currency::*; use wabt; use primitives::map; @@ -94,8 +94,8 @@ mod tests { length_fee + weight_fee } - fn multiplier_target() -> u32 { - >::get() / 4 + fn multiplier_target() -> Weight { + >::get() / 4 } fn creation_fee() -> Balance { diff --git a/node/runtime/src/constants.rs b/node/runtime/src/constants.rs new file mode 100644 index 0000000000000..44b7fe97a7404 --- /dev/null +++ b/node/runtime/src/constants.rs @@ -0,0 +1,52 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! A set of constant values used in substrate runtime. + +/// Money matters. +pub mod currency { + use node_primitives::Balance; + + pub const MILLICENTS: Balance = 1_000_000_000; + pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent. + pub const DOLLARS: Balance = 100 * CENTS; +} + +/// Time. +pub mod time { + use node_primitives::Moment; + + pub const SECS_PER_BLOCK: Moment = 6; + pub const MINUTES: Moment = 60 / SECS_PER_BLOCK; + pub const HOURS: Moment = MINUTES * 60; + pub const DAYS: Moment = HOURS * 24; +} + +// CRITICAL NOTE: The system module maintains two constants: a _maximum_ block weight and a +// _ratio_ of it yielding the portion which is accessible to normal transactions (reserving the rest +// for operational ones). `TARGET_BLOCK_FULLNESS` is entirely independent and the system module is +// not aware of if, nor should it care about it. This constant simply denotes on which ratio of the +// _maximum_ block weight we tweak the fees. It does NOT care about the type of the dispatch. +// +// For the system to be configured in a sane way, `TARGET_BLOCK_FULLNESS` should always be less than +// the ratio that `system` module uses to find normal transaction quota. +/// Fee-related. +pub mod fee { + pub use runtime_primitives::Perbill; + + /// The block saturation level. Fees will be updates based on this value. + pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill::from_const_parts(1_000_000_000 / 4); +} \ No newline at end of file diff --git a/node/runtime/src/impls.rs b/node/runtime/src/impls.rs index 532baa582cb82..6d8a2dd79b014 100644 --- a/node/runtime/src/impls.rs +++ b/node/runtime/src/impls.rs @@ -19,9 +19,17 @@ use node_primitives::Balance; use runtime_primitives::weights::{Weight, WeightMultiplier}; use runtime_primitives::traits::{Convert, Saturating}; -use runtime_primitives::{Fixed64, Perbill}; -use support::traits::Get; -use crate::{Balances, MaximumBlockWeight}; +use runtime_primitives::Fixed64; +use support::traits::{Get, OnUnbalanced, Currency}; +use crate::{Balances, Authorship, MaximumBlockWeight, NegativeImbalance}; +use crate::constants::fee::TARGET_BLOCK_FULLNESS; + +pub struct Author; +impl OnUnbalanced for Author { + fn on_unbalanced(amount: NegativeImbalance) { + Balances::resolve_creating(&Authorship::author(), amount); + } +} /// Struct that handles the conversion of Balance -> `u64`. This is used for staking's election /// calculation. @@ -55,21 +63,10 @@ impl Convert for CurrencyToVoteHandler { /// https://research.web3.foundation/en/latest/polkadot/Token%20Economics/#relay-chain-transaction-fees pub struct WeightMultiplierUpdateHandler; -// CRITICAL NOTE: The system module maintains two constants: a _maximum_ block weight and a -// _ratio_ of it yielding the portion which is accessible to normal transactions (reserving the rest -// for operational ones). `TARGET_BLOCK_FULLNESS` is entirely independent and the system module is -// not aware of if, nor should it care about it. This constant simply denotes on which ratio of the -// _maximum_ block weight we tweak the fees. It does NOT care about the type of the dispatch. -// -// For the system to be configured in a sane way, `TARGET_BLOCK_FULLNESS` should always be less than -// the ratio that `system` module uses to find normal transaction quota. -/// The block saturation level. Fees will be updates based on this value. -pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill(1_000_000_000 / 4); - impl Convert<(Weight, WeightMultiplier), WeightMultiplier> for WeightMultiplierUpdateHandler { fn convert(previous_state: (Weight, WeightMultiplier)) -> WeightMultiplier { let (block_weight, multiplier) = previous_state; - let max_weight = >::get(); + let max_weight = >::get(); let target_weight = (TARGET_BLOCK_FULLNESS * max_weight) as u128; let block_weight = block_weight as u128; @@ -160,12 +157,12 @@ mod tests { ); // ideal. Original fee. No changes. assert_eq!( - WeightMultiplierUpdateHandler::convert((target() as u32, WeightMultiplier::default())), + WeightMultiplierUpdateHandler::convert((target(), WeightMultiplier::default())), wm(0) ); // // More than ideal. Fee is increased. assert_eq!( - WeightMultiplierUpdateHandler::convert(((target() * 2) as u32, WeightMultiplier::default())), + WeightMultiplierUpdateHandler::convert(((target() * 2), WeightMultiplier::default())), wm(10000) ); } @@ -214,7 +211,7 @@ mod tests { #[test] fn weight_to_fee_should_not_overflow_on_large_weights() { - let kb = 1024_u32; + let kb = 1024 as Weight; let mb = kb * kb; let max_fm = WeightMultiplier::from_fixed(Fixed64::from_natural(i64::max_value())); @@ -225,7 +222,7 @@ mod tests { }); // Some values that are all above the target and will cause an increase. - let target_weight = TARGET_BLOCK_FULLNESS * >::get(); + let target_weight = TARGET_BLOCK_FULLNESS * >::get(); vec![target_weight + 100, target_weight * 2, target_weight * 4] .into_iter() .for_each(|i| { diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 18bef27402143..a90feee895d18 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -22,7 +22,7 @@ use rstd::prelude::*; use support::{ - construct_runtime, parameter_types, traits::{SplitTwoWays, Currency, OnUnbalanced} + construct_runtime, parameter_types, traits::{SplitTwoWays, Currency} }; use substrate_primitives::u32_trait::{_1, _2, _3, _4}; use node_primitives::{ @@ -57,10 +57,13 @@ pub use runtime_primitives::{Permill, Perbill}; pub use support::StorageValue; pub use staking::StakerStatus; -/// Implementations for `Convert` and other helper structs passed into runtime modules as associated -/// types. +/// Implementations of some helper traits passed into runtime modules as associated types. pub mod impls; -use impls::{CurrencyToVoteHandler, WeightMultiplierUpdateHandler}; +use impls::{CurrencyToVoteHandler, WeightMultiplierUpdateHandler, Author}; + +/// Constant values used within the runtime. +pub mod constants; +use constants::{time::*, currency::*}; // Make the WASM binary available. #[cfg(feature = "std")] @@ -89,20 +92,8 @@ pub fn native_version() -> NativeVersion { } } -pub const MILLICENTS: Balance = 1_000_000_000; -pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent. -pub const DOLLARS: Balance = 100 * CENTS; - type NegativeImbalance = >::NegativeImbalance; -pub struct Author; - -impl OnUnbalanced for Author { - fn on_unbalanced(amount: NegativeImbalance) { - Balances::resolve_creating(&Authorship::author(), amount); - } -} - pub type DealWithFees = SplitTwoWays< Balance, NegativeImbalance, @@ -110,14 +101,10 @@ pub type DealWithFees = SplitTwoWays< _1, Author, // 1 part (20%) goes to the block author. >; -pub const SECS_PER_BLOCK: Moment = 6; -pub const MINUTES: Moment = 60 / SECS_PER_BLOCK; -pub const HOURS: Moment = MINUTES * 60; -pub const DAYS: Moment = HOURS * 24; - parameter_types! { pub const BlockHashCount: BlockNumber = 250; pub const MaximumBlockWeight: Weight = 1_000_000_000; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; } @@ -134,6 +121,7 @@ impl system::Trait for Runtime { type Event = Event; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index 940f7cdf3f1c4..6dc5f321e41a4 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -244,7 +244,7 @@ mod tests { use substrate_primitives::{H256, Blake2Hasher}; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. - use primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; + use primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -259,6 +259,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -273,6 +274,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } impl Trait for Test { diff --git a/srml/aura/src/mock.rs b/srml/aura/src/mock.rs index 4348f6af2da4e..42f06b564f526 100644 --- a/srml/aura/src/mock.rs +++ b/srml/aura/src/mock.rs @@ -19,7 +19,7 @@ #![cfg(test)] use primitives::{ - traits::IdentityLookup, + traits::IdentityLookup, Perbill, testing::{Header, UintAuthorityId}, }; use srml_support::{impl_outer_origin, parameter_types}; @@ -39,6 +39,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); pub const MinimumPeriod: u64 = 1; } @@ -55,6 +56,7 @@ impl system::Trait for Test { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index 81a1b840c371d..b496bac460e9a 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -328,6 +328,7 @@ mod tests { use primitives::traits::{BlakeTwo256, IdentityLookup}; use primitives::testing::Header; use primitives::generic::DigestItem; + use primitives::Perbill; use srml_support::{parameter_types, impl_outer_origin, ConsensusEngineId}; impl_outer_origin!{ @@ -341,6 +342,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { @@ -356,6 +358,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index ba3b034851d66..67e0d67ca5d0b 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -767,6 +767,7 @@ impl, I: Instance> system::Trait for ElevatedTrait { type Event = (); type BlockHashCount = T::BlockHashCount; type MaximumBlockWeight = T::MaximumBlockWeight; + type AvailableBlockRatio = T::AvailableBlockRatio; type MaximumBlockLength = T::MaximumBlockLength; } impl, I: Instance> Trait for ElevatedTrait { @@ -1185,7 +1186,8 @@ impl, I: Instance> TakeFees { // weight fee let weight = info.weight; - let weight_fee: T::Balance = >::next_weight_multiplier().apply_to(weight).into(); + let weight_fee: T::Balance = >::next_weight_multiplier() + .apply_to(weight).saturated_into(); len_fee.saturating_add(weight_fee).saturating_add(tip) } diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index fecec82180d89..cc0dbe6ad800e 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -18,7 +18,7 @@ #![cfg(test)] -use primitives::{traits::IdentityLookup, testing::Header, weights::{DispatchInfo, Weight}}; +use primitives::{Perbill, traits::IdentityLookup, testing::Header, weights::{DispatchInfo, Weight}}; use substrate_primitives::{H256, Blake2Hasher}; use runtime_io; use srml_support::{impl_outer_origin, parameter_types}; @@ -70,6 +70,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Runtime { type Origin = Origin; @@ -84,6 +85,7 @@ impl system::Trait for Runtime { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } impl Trait for Runtime { diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index aa74c9a723aa1..479088a309488 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -399,7 +399,7 @@ mod tests { use runtime_io::with_externalities; use substrate_primitives::{H256, Blake2Hasher}; use primitives::{ - traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, BuildStorage + Perbill, traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, BuildStorage }; use crate as collective; @@ -407,6 +407,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -421,6 +422,7 @@ mod tests { type WeightMultiplierUpdate = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } impl Trait for Test { diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index 3af81d8d84194..39b25c3323cf6 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -31,7 +31,7 @@ use runtime_io; use runtime_io::with_externalities; use runtime_primitives::testing::{Digest, DigestItem, Header, UintAuthorityId, H256}; use runtime_primitives::traits::{BlakeTwo256, Hash, IdentityLookup}; -use runtime_primitives::BuildStorage; +use runtime_primitives::{Perbill, BuildStorage}; use srml_support::{ assert_ok, assert_err, impl_outer_dispatch, impl_outer_event, impl_outer_origin, parameter_types, storage::child, StorageMap, StorageValue, traits::{Currency, Get}, @@ -100,6 +100,7 @@ parameter_types! { pub const MaximumBlockLength: u32 = 2 * 1024; pub const BalancesTransactionBaseFee: u64 = 0; pub const BalancesTransactionByteFee: u64 = 0; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -114,6 +115,7 @@ impl system::Trait for Test { type Event = MetaEvent; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } impl balances::Trait for Test { diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index 0ebf50ce16508..0c74a30f1d2c1 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -44,6 +44,7 @@ mod tests { pub use substrate_primitives::{H256, Blake2Hasher, u32_trait::{_1, _2, _3, _4}}; pub use primitives::traits::{BlakeTwo256, IdentityLookup}; pub use primitives::testing::{Digest, DigestItem, Header}; + pub use primitives::Perbill; pub use {seats, motions}; use std::cell::RefCell; @@ -100,6 +101,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -114,6 +116,7 @@ mod tests { type Event = Event; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } parameter_types! { diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index ae38f6cc779ae..635f01d87a917 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -992,6 +992,7 @@ mod tests { }; use substrate_primitives::{H256, Blake2Hasher}; use primitives::{traits::{BlakeTwo256, IdentityLookup, Bounded}, testing::Header}; + use primitives::Perbill; use balances::BalanceLock; use system::EnsureSignedBy; @@ -1018,6 +1019,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -1032,6 +1034,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } parameter_types! { diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index d17a1e0948eb3..a1670243cd4eb 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -1113,7 +1113,7 @@ mod tests { use runtime_io::with_externalities; use substrate_primitives::{H256, Blake2Hasher}; use primitives::{ - traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, BuildStorage + Perbill, traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, testing::Header, BuildStorage }; use crate as elections; @@ -1121,6 +1121,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -1135,6 +1136,7 @@ mod tests { type WeightMultiplierUpdate = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } parameter_types! { diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index a64cfc0af090e..f41454d2e6565 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -510,7 +510,7 @@ mod tests { // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried. use sr_primitives::{ - traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup}, testing::Header + Perbill, traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup}, testing::Header }; impl_outer_origin! { @@ -526,6 +526,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -540,6 +541,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } parameter_types! { diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 2910d1a5ddca5..7175ba1ce3771 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -358,6 +358,8 @@ mod tests { use runtime_io::with_externalities; use substrate_primitives::{H256, Blake2Hasher}; use primitives::generic::Era; + use primitives::Perbill; + use primitives::weights::Weight; use primitives::traits::{Header as HeaderT, BlakeTwo256, IdentityLookup}; use primitives::testing::{Digest, Header, Block}; use srml_support::{impl_outer_event, impl_outer_origin, parameter_types}; @@ -383,6 +385,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Runtime { type Origin = Origin; @@ -397,6 +400,7 @@ mod tests { type BlockHashCount = BlockHashCount; type WeightMultiplierUpdate = (); type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } parameter_types! { @@ -562,9 +566,8 @@ mod tests { // given: TestXt uses the encoded len as fixed Len: let xt = primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer::(33, 0)); let encoded = xt.encode(); - let encoded_len = encoded.len() as u32; - // TODO: this should be fetched from the test system once the ratio is exposed as a const. - let limit = >::get() * 3 / 4; + let encoded_len = encoded.len() as Weight; + let limit = >::get() * >::get(); let num_to_exhaust_block = limit / encoded_len; with_externalities(&mut t, || { Executive::initialize_block(&Header::new( @@ -582,7 +585,7 @@ mod tests { if nonce != num_to_exhaust_block { assert_eq!(res.unwrap(), ApplyOutcome::Success); assert_eq!(>::all_extrinsics_weight(), encoded_len * (nonce + 1)); - assert_eq!(>::extrinsic_index(), Some(nonce + 1)); + assert_eq!(>::extrinsic_index(), Some(nonce as u32 + 1)); } else { assert_eq!(res, Err(ApplyError::FullBlock)); } @@ -606,7 +609,7 @@ mod tests { assert_eq!(Executive::apply_extrinsic(x2.clone()).unwrap(), ApplyOutcome::Success); // default weight for `TestXt` == encoded length. - assert_eq!( >::all_extrinsics_weight(), 3 * len); + assert_eq!(>::all_extrinsics_weight(), (3 * len).into()); assert_eq!(>::all_extrinsics_len(), 3 * len); let _ = >::finalize(); diff --git a/srml/finality-tracker/src/lib.rs b/srml/finality-tracker/src/lib.rs index 38377f35006ef..d59183a166fae 100644 --- a/srml/finality-tracker/src/lib.rs +++ b/srml/finality-tracker/src/lib.rs @@ -268,6 +268,7 @@ mod tests { use substrate_primitives::H256; use primitives::traits::{BlakeTwo256, IdentityLookup, OnFinalize, Header as HeaderT}; use primitives::testing::Header; + use primitives::Perbill; use srml_support::{assert_ok, impl_outer_origin, parameter_types}; use srml_system as system; use std::cell::RefCell; @@ -301,6 +302,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -315,6 +317,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } parameter_types! { diff --git a/srml/generic-asset/src/lib.rs b/srml/generic-asset/src/lib.rs index 884f4e9b9be30..b43e6b72ee686 100644 --- a/srml/generic-asset/src/lib.rs +++ b/srml/generic-asset/src/lib.rs @@ -1058,6 +1058,7 @@ impl system::Trait for ElevatedTrait { type Event = (); type MaximumBlockWeight = T::MaximumBlockWeight; type MaximumBlockLength = T::MaximumBlockLength; + type AvailableBlockRatio = T::AvailableBlockRatio; type WeightMultiplierUpdate = (); type BlockHashCount = T::BlockHashCount; } diff --git a/srml/generic-asset/src/mock.rs b/srml/generic-asset/src/mock.rs index fb7fc04caa682..d9a91ec9ebf35 100644 --- a/srml/generic-asset/src/mock.rs +++ b/srml/generic-asset/src/mock.rs @@ -20,10 +20,7 @@ #![cfg(test)] -use primitives::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, -}; +use primitives::{Perbill, testing::Header, traits::{BlakeTwo256, IdentityLookup}}; use substrate_primitives::{Blake2Hasher, H256}; use support::{parameter_types, impl_outer_event, impl_outer_origin}; @@ -42,6 +39,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -55,6 +53,7 @@ impl system::Trait for Test { type Event = TestEvent; type MaximumBlockWeight = MaximumBlockWeight; type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; type WeightMultiplierUpdate = (); type BlockHashCount = BlockHashCount; } diff --git a/srml/grandpa/src/mock.rs b/srml/grandpa/src/mock.rs index 87845a7a4d05f..44e80c77bb72d 100644 --- a/srml/grandpa/src/mock.rs +++ b/srml/grandpa/src/mock.rs @@ -18,7 +18,7 @@ #![cfg(test)] -use primitives::{DigestItem, traits::IdentityLookup, testing::{Header, UintAuthorityId}}; +use primitives::{Perbill, DigestItem, traits::IdentityLookup, testing::{Header, UintAuthorityId}}; use runtime_io; use srml_support::{impl_outer_origin, impl_outer_event, parameter_types}; use substrate_primitives::{H256, Blake2Hasher}; @@ -45,6 +45,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -59,6 +60,7 @@ impl system::Trait for Test { type Event = TestEvent; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } diff --git a/srml/indices/src/mock.rs b/srml/indices/src/mock.rs index 151a5186f79b6..60595b08ba994 100644 --- a/srml/indices/src/mock.rs +++ b/srml/indices/src/mock.rs @@ -21,6 +21,7 @@ use std::collections::HashSet; use ref_thread_local::{ref_thread_local, RefThreadLocal}; use primitives::testing::Header; +use primitives::Perbill; use substrate_primitives::{H256, Blake2Hasher}; use srml_support::{impl_outer_origin, parameter_types}; use {runtime_io, system}; @@ -68,6 +69,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Runtime { type Origin = Origin; @@ -82,6 +84,7 @@ impl system::Trait for Runtime { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } impl Trait for Runtime { diff --git a/srml/session/src/mock.rs b/srml/session/src/mock.rs index c469993bcfe1a..0ae2efc56057d 100644 --- a/srml/session/src/mock.rs +++ b/srml/session/src/mock.rs @@ -21,6 +21,7 @@ use std::cell::RefCell; use srml_support::{impl_outer_origin, parameter_types}; use substrate_primitives::H256; use primitives::{ + Perbill, traits::{BlakeTwo256, IdentityLookup, ConvertInto}, testing::{Header, UintAuthorityId} }; @@ -112,6 +113,7 @@ parameter_types! { pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; pub const MinimumPeriod: u64 = 5; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -126,6 +128,7 @@ impl system::Trait for Test { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } impl timestamp::Trait for Test { diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 329bdcda2cf83..7b6404a57b2f2 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -89,6 +89,7 @@ parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -103,6 +104,7 @@ impl system::Trait for Test { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } parameter_types! { diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 623bb8bc750d6..e529c97671d8e 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -204,6 +204,12 @@ pub trait Trait: 'static + Eq + Clone { /// The maximum length of a block (in bytes). type MaximumBlockLength: Get; + + /// The portion of the block that is available to normal transaction. The rest can only be used + /// by operational transactions. This can be applied to any resource limit managed by the system + /// module, including weight and length. + type AvailableBlockRatio: Get; + } pub type DigestOf = generic::Digest<::Hash>; @@ -812,7 +818,7 @@ impl CheckWeight { match class { DispatchClass::Operational => Perbill::one(), // TODO: this must be some sort of a constant. - DispatchClass::Normal => Perbill::from_percent(75), + DispatchClass::Normal => T::AvailableBlockRatio::get(), } } @@ -1050,7 +1056,8 @@ mod tests { parameter_types! { pub const BlockHashCount: u64 = 10; pub const MaximumBlockWeight: Weight = 1024; - pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); + pub const MaximumBlockLength: u32 = 1024; } impl Trait for Test { @@ -1066,6 +1073,7 @@ mod tests { type Event = u16; type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } @@ -1084,6 +1092,14 @@ mod tests { GenesisConfig::default().build_storage::().unwrap().0.into() } + fn normal_weight_limit() -> Weight { + ::AvailableBlockRatio::get() * ::MaximumBlockWeight::get() + } + + fn normal_length_limit() -> u32 { + ::AvailableBlockRatio::get() * ::MaximumBlockLength::get() + } + #[test] fn origin_works() { let o = Origin::from(RawOrigin::::Signed(1u64)); @@ -1239,7 +1255,7 @@ mod tests { #[test] fn signed_ext_check_weight_works_normal_tx() { with_externalities(&mut new_test_ext(), || { - let normal_limit = >::get() * 3 / 4; + let normal_limit = normal_weight_limit(); let small = DispatchInfo { weight: 100, ..Default::default() }; let medium = DispatchInfo { weight: normal_limit - 1, @@ -1281,7 +1297,7 @@ mod tests { with_externalities(&mut new_test_ext(), || { let max = DispatchInfo { weight: Weight::max_value(), ..Default::default() }; let len = 0_usize; - let normal_limit = >::get() * 3 / 4; + let normal_limit = normal_weight_limit(); assert_eq!(System::all_extrinsics_weight(), 0); let r = CheckWeight::(PhantomData).pre_dispatch(&1, max, len); @@ -1296,7 +1312,7 @@ mod tests { let normal = DispatchInfo { weight: 100, ..Default::default() }; let op = DispatchInfo { weight: 100, class: DispatchClass::Operational }; let len = 0_usize; - let normal_limit = >::get() * 3 / 4; + let normal_limit = normal_weight_limit(); // given almost full block AllExtrinsicsWeight::put(normal_limit); @@ -1307,7 +1323,7 @@ mod tests { // likewise for length limit. let len = 100_usize; - AllExtrinsicsLen::put(>::get() * 3 / 4); + AllExtrinsicsLen::put(normal_length_limit()); assert!(CheckWeight::(PhantomData).pre_dispatch(&1, normal, len).is_err()); assert!(CheckWeight::(PhantomData).pre_dispatch(&1, op, len).is_ok()); }) @@ -1334,17 +1350,24 @@ mod tests { #[test] fn signed_ext_check_weight_block_size_works() { with_externalities(&mut new_test_ext(), || { - let tx = DispatchInfo::default(); - let normal_limit = (>::get() * 3 / 4) as usize; - let reset_check_weight = |s, f| { + let normal = DispatchInfo::default(); + let normal_limit = normal_weight_limit() as usize; + let reset_check_weight = |tx, s, f| { AllExtrinsicsLen::put(0); let r = CheckWeight::(PhantomData).pre_dispatch(&1, tx, s); if f { assert!(r.is_err()) } else { assert!(r.is_ok()) } }; - reset_check_weight(normal_limit - 1, false); - reset_check_weight(normal_limit, false); - reset_check_weight(normal_limit + 1, true); + reset_check_weight(normal, normal_limit - 1, false); + reset_check_weight(normal, normal_limit, false); + reset_check_weight(normal, normal_limit + 1, true); + + // Operational ones don't have this limit. + let op = DispatchInfo { weight: 0, class: DispatchClass::Operational }; + reset_check_weight(op, normal_limit, false); + reset_check_weight(op, normal_limit + 100, false); + reset_check_weight(op, 1024, false); + reset_check_weight(op, 1025, true); }) } diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index ae99938991a68..5219fee325b6c 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -330,7 +330,7 @@ mod tests { use srml_support::{impl_outer_origin, assert_ok, parameter_types}; use runtime_io::{with_externalities, TestExternalities}; use substrate_primitives::H256; - use runtime_primitives::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; + use runtime_primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -342,6 +342,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -356,6 +357,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } parameter_types! { diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 3a0b218090308..69652c1ae3a35 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -364,7 +364,7 @@ mod tests { use runtime_io::with_externalities; use srml_support::{assert_noop, assert_ok, impl_outer_origin, parameter_types}; use substrate_primitives::{H256, Blake2Hasher}; - use runtime_primitives::{traits::{BlakeTwo256, OnFinalize, IdentityLookup}, testing::Header}; + use runtime_primitives::{Perbill, traits::{BlakeTwo256, OnFinalize, IdentityLookup}, testing::Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -376,6 +376,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { type Origin = Origin; @@ -390,6 +391,7 @@ mod tests { type Event = (); type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; + type AvailableBlockRatio = AvailableBlockRatio; type MaximumBlockLength = MaximumBlockLength; } parameter_types! { From bfcfa36d311c2b59f8730fe715c3acd5ed5f912a Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 23 Jul 2019 09:40:24 +0200 Subject: [PATCH 21/33] More refactoring and tests. --- core/sr-primitives/src/weights.rs | 6 +- node-template/runtime/src/lib.rs | 13 ++- node-template/runtime/src/template.rs | 2 +- node/executor/src/lib.rs | 109 +++++++++++++++++++++----- node/runtime/src/impls.rs | 4 +- node/runtime/src/lib.rs | 4 +- srml/balances/src/lib.rs | 26 ++++-- srml/balances/src/mock.rs | 13 ++- srml/balances/src/tests.rs | 32 ++++++-- srml/contracts/src/tests.rs | 2 + srml/council/src/lib.rs | 2 + srml/democracy/src/lib.rs | 2 + srml/elections/src/lib.rs | 2 + srml/example/src/lib.rs | 2 + srml/executive/src/lib.rs | 6 +- srml/staking/src/mock.rs | 2 + srml/support/src/dispatch.rs | 6 +- srml/treasury/src/lib.rs | 2 + 18 files changed, 181 insertions(+), 54 deletions(-) diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index 7c52f7d2dba49..04b0fc2906891 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -30,7 +30,7 @@ pub use crate::transaction_validity::TransactionPriority; use crate::traits::Bounded; /// Numeric range of a transaction weight. -pub type Weight = u64; +pub type Weight = u32; /// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions /// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`). @@ -144,11 +144,11 @@ pub enum SimpleDispatchInfo { impl WeighData for SimpleDispatchInfo { fn weigh_data(&self, _: T) -> Weight { match self { - SimpleDispatchInfo::FixedNormal(w) => *w * 1000, + SimpleDispatchInfo::FixedNormal(w) => *w, SimpleDispatchInfo::MaxNormal => Bounded::max_value(), SimpleDispatchInfo::FreeNormal => Bounded::min_value(), - SimpleDispatchInfo::FixedOperational(w) => *w * 1000, + SimpleDispatchInfo::FixedOperational(w) => *w, SimpleDispatchInfo::MaxOperational => Bounded::max_value(), SimpleDispatchInfo::FreeOperational => Bounded::min_value(), } diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index b239c55de27e1..080f7f292e169 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -8,16 +8,11 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -#[cfg(feature = "std")] -use serde::{Serialize, Deserialize}; -use parity_codec::{Encode, Decode}; use rstd::prelude::*; -#[cfg(feature = "std")] -use primitives::bytes; use primitives::{ed25519, sr25519, OpaqueMetadata}; use sr_primitives::{ ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str, - traits::{self, NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify}, weights::Weight, + traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify}, weights::Weight, }; use client::{ block_builder::api::{CheckInherentsResult, InherentData, self as block_builder_api}, @@ -169,8 +164,9 @@ parameter_types! { pub const ExistentialDeposit: u128 = 500; pub const TransferFee: u128 = 0; pub const CreationFee: u128 = 0; - pub const TransactionBaseFee: u128 = 1; - pub const TransactionByteFee: u128 = 0; + pub const TransactionBaseFee: u128 = 0; + pub const TransactionByteFee: u128 = 1; + pub const TransactionWeightFee: u128 = 1; } impl balances::Trait for Runtime { @@ -191,6 +187,7 @@ impl balances::Trait for Runtime { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; + type TransactionWeightFee = TransactionWeightFee; } impl sudo::Trait for Runtime { diff --git a/node-template/runtime/src/template.rs b/node-template/runtime/src/template.rs index 34818abe1801b..2999d9ea27abb 100644 --- a/node-template/runtime/src/template.rs +++ b/node-template/runtime/src/template.rs @@ -89,7 +89,7 @@ mod tests { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: Weight = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75)); + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); } impl system::Trait for Test { type Origin = Origin; diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 1605c0a24d9a3..bc23fc5b58bbb 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -49,7 +49,7 @@ mod tests { 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::{WeightMultiplier, SimpleDispatchInfo, GetDispatchInfo, WeighData, Weight}; + use runtime_primitives::weights::{WeightMultiplier, GetDispatchInfo, Weight}; use {balances, contracts, indices, staking, system, timestamp}; use contracts::ContractAddressFor; use system::{EventRecord, Phase}; @@ -82,22 +82,25 @@ mod tests { type TestExternalities = CoreTestExternalities; + /// Default transfer fee fn transfer_fee(extrinsic: &E) -> Balance { let length_fee = >::get() + >::get() * (extrinsic.encode().len() as Balance); - let weight_fee = default_transfer_call().get_dispatch_info().weight as Balance; - // TODO: with this we have 100% accurate fee estimation. Should probably be able to get rid - // of `assert_eq_error_rate!` now. But it makes test mockup much more complicated because - // the fee for each block can only be estimated _before_ that block. + let mut weight_fee = default_transfer_call().get_dispatch_info().weight as Balance; + weight_fee = weight_fee * 1_000_000 as Balance; + // NOTE: we don't need this anymore, but in case needed, this makes the fee accurate over + // multiple blocks. // weight_fee = >::next_weight_multiplier().apply_to(weight_fee as u32) as Balance; length_fee + weight_fee } - fn multiplier_target() -> Weight { + /// Get the target weight of the fee multiplier. + fn _multiplier_target() -> Weight { >::get() / 4 } + /// Default creation fee. fn creation_fee() -> Balance { >::get() } @@ -972,21 +975,6 @@ mod tests { let mut tt = new_test_ext(COMPACT_CODE, false); - // This test can either use `fill_block()`, which is controversial, or should be dropped. - // NOTE: This assumes that system::remark has the default. - // let num_to_exhaust = (multiplier_target() + 100) / SimpleDispatchInfo::default().weigh_data(()); - // println!("++ Generating {} transactions to fill {} weight units", num_to_exhaust, multiplier_target() + 100); - // 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::>(); - // xts.insert(0, CheckedExtrinsic { - // signed: None, - // function: Call::Timestamp(timestamp::Call::set(42)), - // }); - - println!("++ Generated all extrinsics. Constructing blocks."); - // big one in terms of weight. let block1 = construct_block( &mut tt, @@ -1057,6 +1045,85 @@ mod tests { }); } + #[test] + fn transaction_fee_is_correct_ultimate() { + // This uses the exact values of substrate-node. + // + // weight of transfer call as of now: 1_000 + // if weight of cheapest weight would be 10^7, this would be 10^9, which is: + // - 1 MILLICENTS in substrate node. + // - 1 milldot based on current polkadot runtime. + // (this baed on assigning 0.1 CENT to the cheapest tx with `weight = 100`) + let mut t = TestExternalities::::new_with_code(COMPACT_CODE, map![ + blake2_256(&>::key_for(alice())).to_vec() => { + (100 * DOLLARS).encode() + }, + blake2_256(&>::key_for(bob())).to_vec() => { + (10 * DOLLARS).encode() + }, + twox_128(>::key()).to_vec() => { + (110 * DOLLARS).encode() + }, + twox_128(>::key()).to_vec() => vec![0u8; 16], + blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] + ]); + + let tip = 1_000_000; + let xt = sign(CheckedExtrinsic { + signed: Some((alice(), signed_extra(0, tip))), + function: Call::Balances(default_transfer_call()), + }); + + let r = executor().call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "Core_initialize_block", + &vec![].and(&from_block_number(1u64)), + true, + None, + ).0; + + assert!(r.is_ok()); + let r = executor().call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "BlockBuilder_apply_extrinsic", + &vec![].and(&xt.clone()), + true, + None, + ).0; + assert!(r.is_ok()); + + runtime_io::with_externalities(&mut t, || { + assert_eq!(Balances::total_balance(&bob()), (10 + 69) * DOLLARS); + // Components deducted from alice's balances: + // - Weight fee + // - Length fee + // - Tip + // - Creation-fee of bob's account. + let mut balance_alice = (100 - 69) * DOLLARS; + + let length_fee = >::get() + + >::get() * + (xt.clone().encode().len() as Balance); + println!("++ len fee = {:?}", length_fee); + balance_alice -= length_fee; + + // TODO: the 1_000_000 should go away. + let weight_fee = default_transfer_call().get_dispatch_info().weight as Balance * 1_000_000; + // we know that weight to fee multiplier is effect-less in block 1. + assert_eq!(weight_fee as Balance, MILLICENTS); + balance_alice -= weight_fee; + println!("++ wei fee = {:?}", weight_fee); + + balance_alice -= tip; + println!("++ tip fee = {:?}", tip); + + // TODO: why again??? creation fee should not be deducted here. + balance_alice -= creation_fee(); + + assert_eq!(Balances::total_balance(&alice()), balance_alice); + }); + } + #[cfg(feature = "benchmarks")] mod benches { use super::*; diff --git a/node/runtime/src/impls.rs b/node/runtime/src/impls.rs index 6d8a2dd79b014..288dac3ea9941 100644 --- a/node/runtime/src/impls.rs +++ b/node/runtime/src/impls.rs @@ -222,8 +222,8 @@ mod tests { }); // Some values that are all above the target and will cause an increase. - let target_weight = TARGET_BLOCK_FULLNESS * >::get(); - vec![target_weight + 100, target_weight * 2, target_weight * 4] + let t = target(); + vec![t + 100, t * 2, t * 4] .into_iter() .for_each(|i| { let fm = WeightMultiplierUpdateHandler::convert(( diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index a90feee895d18..168bb666ef29c 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -103,7 +103,7 @@ pub type DealWithFees = SplitTwoWays< parameter_types! { pub const BlockHashCount: BlockNumber = 250; - pub const MaximumBlockWeight: Weight = 1_000_000_000; + pub const MaximumBlockWeight: Weight = 1_000_000; pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; } @@ -143,6 +143,7 @@ parameter_types! { pub const CreationFee: Balance = 1 * CENTS; pub const TransactionBaseFee: Balance = 1 * CENTS; pub const TransactionByteFee: Balance = 10 * MILLICENTS; + pub const TransactionWeightFee: Balance = MILLICENTS / 1000; } impl balances::Trait for Runtime { @@ -158,6 +159,7 @@ impl balances::Trait for Runtime { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; + type TransactionWeightFee = TransactionWeightFee; } parameter_types! { diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 67e0d67ca5d0b..075df2f5f46a2 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -206,6 +206,9 @@ pub trait Subtrait: system::Trait { /// The fee to be paid for making a transaction; the per-byte portion. type TransactionByteFee: Get; + + /// The amount of fee deducted oer unit of weight. + type TransactionWeightFee: Get; } pub trait Trait: system::Trait { @@ -249,6 +252,9 @@ pub trait Trait: system::Trait { /// The fee to be paid for making a transaction; the per-byte portion. type TransactionByteFee: Get; + + /// The amount of fee deducted oer unit of weight. + type TransactionWeightFee: Get; } impl, I: Instance> Subtrait for T { @@ -260,6 +266,7 @@ impl, I: Instance> Subtrait for T { type CreationFee = T::CreationFee; type TransactionBaseFee = T::TransactionBaseFee; type TransactionByteFee = T::TransactionByteFee; + type TransactionWeightFee = T::TransactionWeightFee; } decl_event!( @@ -783,6 +790,7 @@ impl, I: Instance> Trait for ElevatedTrait { type CreationFee = T::CreationFee; type TransactionBaseFee = T::TransactionBaseFee; type TransactionByteFee = T::TransactionByteFee; + type TransactionWeightFee = T::TransactionWeightFee; } impl, I: Instance> Currency for Module @@ -1174,20 +1182,24 @@ impl, I: Instance> TakeFees { /// - (optional) _tip_: if included in the transaction, it will be added on top. Only signed /// transactions can have a tip. fn compute_fee(len: usize, info: DispatchInfo, tip: T::Balance) -> T::Balance { - // length fee let len_fee = if info.pay_length_fee() { let len = T::Balance::from(len as u32); let base = T::TransactionBaseFee::get(); - let byte = T::TransactionByteFee::get(); - base.saturating_add(byte.saturating_mul(len)) + let per_byte = T::TransactionByteFee::get(); + base.saturating_add(per_byte.saturating_mul(len)) } else { Zero::zero() }; - // weight fee - let weight = info.weight; - let weight_fee: T::Balance = >::next_weight_multiplier() - .apply_to(weight).saturated_into(); + let weight_fee = { + // cap the weight to the maximum defined in runtime, otherwise it will be the `Bounded` + // maximum of its data type, which is not desired. + let capped_weight = info.weight.min(::MaximumBlockWeight::get()); + let weight_fee: T::Balance = >::next_weight_multiplier() + .apply_to(capped_weight).saturated_into(); + let per_weight = T::TransactionWeightFee::get(); + weight_fee.saturating_mul(per_weight) + }; len_fee.saturating_add(weight_fee).saturating_add(tip) } diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index cc0dbe6ad800e..0f5a37e1db4eb 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -36,6 +36,7 @@ thread_local! { static CREATION_FEE: RefCell = RefCell::new(0); static TRANSACTION_BASE_FEE: RefCell = RefCell::new(0); static TRANSACTION_BYTE_FEE: RefCell = RefCell::new(1); + static TRANSACTION_WEIGHT_FEE: RefCell = RefCell::new(1); } pub struct ExistentialDeposit; @@ -63,6 +64,11 @@ impl Get for TransactionByteFee { fn get() -> u64 { TRANSACTION_BYTE_FEE.with(|v| *v.borrow()) } } +pub struct TransactionWeightFee; +impl Get for TransactionWeightFee { + fn get() -> u64 { TRANSACTION_WEIGHT_FEE.with(|v| *v.borrow()) } +} + // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Runtime; @@ -101,11 +107,13 @@ impl Trait for Runtime { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; + type TransactionWeightFee = TransactionWeightFee; } pub struct ExtBuilder { transaction_base_fee: u64, transaction_byte_fee: u64, + transaction_weight_fee: u64, existential_deposit: u64, transfer_fee: u64, creation_fee: u64, @@ -117,6 +125,7 @@ impl Default for ExtBuilder { Self { transaction_base_fee: 0, transaction_byte_fee: 0, + transaction_weight_fee: 0, existential_deposit: 0, transfer_fee: 0, creation_fee: 0, @@ -126,9 +135,10 @@ impl Default for ExtBuilder { } } impl ExtBuilder { - pub fn transaction_fees(mut self, base_fee: u64, byte_fee: u64) -> Self { + pub fn transaction_fees(mut self, base_fee: u64, byte_fee: u64, weight_fee: u64) -> Self { self.transaction_base_fee = base_fee; self.transaction_byte_fee = byte_fee; + self.transaction_weight_fee = weight_fee; self } pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { @@ -161,6 +171,7 @@ impl ExtBuilder { CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee); TRANSACTION_BASE_FEE.with(|v| *v.borrow_mut() = self.transaction_base_fee); TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.transaction_byte_fee); + TRANSACTION_WEIGHT_FEE.with(|v| *v.borrow_mut() = self.transaction_weight_fee); } pub fn build(self) -> runtime_io::TestExternalities { self.set_associated_consts(); diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 2828d40e63ff8..f40335f9008a8 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -114,7 +114,7 @@ fn lock_reasons_should_work() { with_externalities( &mut ExtBuilder::default() .existential_deposit(1) - .monied(true).transaction_fees(0, 1) + .monied(true).transaction_fees(0, 1, 0) .build(), || { Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into()); @@ -752,15 +752,37 @@ fn signed_extension_take_fees_work() { with_externalities( &mut ExtBuilder::default() .existential_deposit(10) - .transaction_fees(10, 1) + .transaction_fees(10, 1, 5) .monied(true) .build(), || { let len = 10; - assert!(TakeFees::::from(0).pre_dispatch(&1, info_from_weight(0), len).is_ok()); - assert_eq!(Balances::free_balance(&1), 100 - 20); - assert!(TakeFees::::from(5 /* tipped */).pre_dispatch(&1, info_from_weight(0), len).is_ok()); + assert!(TakeFees::::from(0).pre_dispatch(&1, info_from_weight(5), len).is_ok()); assert_eq!(Balances::free_balance(&1), 100 - 20 - 25); + assert!(TakeFees::::from(5 /* tipped */).pre_dispatch(&1, info_from_weight(3), len).is_ok()); + assert_eq!(Balances::free_balance(&1), 100 - 20 - 25 - 20 - 5 - 15); + } + ); +} + +#[test] +fn signed_extension_take_fees_is_bounded() { + with_externalities( + &mut ExtBuilder::default() + .existential_deposit(1000) + .transaction_fees(0, 0, 1) + .monied(true) + .build(), + || { + use primitives::weights::Weight; + + // maximum weight possible + assert!(TakeFees::::from(0).pre_dispatch(&1, info_from_weight(Weight::max_value()), 10).is_ok()); + // fee will be proportional to what is the actual maximum weight in the runtime. + assert_eq!( + Balances::free_balance(&1), + (10000 - <::MaximumBlockWeight as Get>::get()) as u64 + ); } ); } diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index 39b25c3323cf6..6c81bac39c8f4 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -100,6 +100,7 @@ parameter_types! { pub const MaximumBlockLength: u32 = 2 * 1024; pub const BalancesTransactionBaseFee: u64 = 0; pub const BalancesTransactionByteFee: u64 = 0; + pub const BalancesTransactionWeightFee: u64 = 0; pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { @@ -131,6 +132,7 @@ impl balances::Trait for Test { type CreationFee = CreationFee; type TransactionBaseFee = BalancesTransactionBaseFee; type TransactionByteFee = BalancesTransactionByteFee; + type TransactionWeightFee = BalancesTransactionWeightFee; } parameter_types! { pub const MinimumPeriod: u64 = 1; diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index 0c74a30f1d2c1..27e4d1454eb6a 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -125,6 +125,7 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 1; pub const TransactionByteFee: u64 = 0; + pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -139,6 +140,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; + type TransactionWeightFee = TransactionWeightFee; } parameter_types! { pub const LaunchPeriod: u64 = 1; diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index 635f01d87a917..fd3b9de57221a 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -1043,6 +1043,7 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 0; pub const TransactionByteFee: u64 = 0; + pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -1057,6 +1058,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; + type TransactionWeightFee = TransactionWeightFee; } parameter_types! { pub const LaunchPeriod: u64 = 2; diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index a1670243cd4eb..87a4c4d834e78 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -1145,6 +1145,7 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 0; pub const TransactionByteFee: u64 = 0; + pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -1159,6 +1160,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; + type TransactionWeightFee = TransactionWeightFee; } parameter_types! { pub const CandidacyBond: u64 = 3; diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index f41454d2e6565..81296be4dae70 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -550,6 +550,7 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 0; pub const TransactionByteFee: u64 = 0; + pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -564,6 +565,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; + type TransactionWeightFee = TransactionWeightFee; } impl Trait for Test { type Event = (); diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 7175ba1ce3771..12646d48c23dc 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -409,6 +409,7 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 10; pub const TransactionByteFee: u64 = 0; + pub const TransactionWeightFee: u64 = 1; } impl balances::Trait for Runtime { type Balance = u64; @@ -423,6 +424,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; + type TransactionWeightFee = TransactionWeightFee; } impl ValidateUnsigned for Runtime { @@ -462,7 +464,7 @@ mod tests { fn balance_transfer_dispatch_works() { let mut t = system::GenesisConfig::default().build_storage::().unwrap(); balances::GenesisConfig:: { - balances: vec![(1, 111)], + balances: vec![(1, 211)], vesting: vec![], }.assimilate_storage(&mut t.0, &mut t.1).unwrap(); let xt = primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer(2, 69)); @@ -478,7 +480,7 @@ mod tests { )); let r = Executive::apply_extrinsic(xt); assert_eq!(r, Ok(ApplyOutcome::Success)); - assert_eq!(>::total_balance(&1), 42 - 10 - weight); + assert_eq!(>::total_balance(&1), 142 - 10 - weight); assert_eq!(>::total_balance(&2), 69); }); } diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 7b6404a57b2f2..78e3243065fb0 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -112,6 +112,7 @@ parameter_types! { pub const CreationFee: Balance = 0; pub const TransactionBaseFee: u64 = 0; pub const TransactionByteFee: u64 = 0; + pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = Balance; @@ -126,6 +127,7 @@ impl balances::Trait for Test { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; + type TransactionWeightFee = TransactionWeightFee; } parameter_types! { pub const Period: BlockNumber = 1; diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index 3d2cc3b924e66..f427d5f61ac32 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -1775,17 +1775,17 @@ mod tests { // max weight. not dependent on input. assert_eq!( Call::::operational().get_dispatch_info(), - DispatchInfo { weight: 5 * 1000, class: DispatchClass::Operational }, + DispatchInfo { weight: 5, class: DispatchClass::Operational }, ); // default weight. assert_eq!( Call::::aux_0().get_dispatch_info(), - DispatchInfo { weight: 10 * 1000, class: DispatchClass::Normal }, + DispatchInfo { weight: 10, class: DispatchClass::Normal }, ); // custom basic assert_eq!( Call::::aux_3().get_dispatch_info(), - DispatchInfo { weight: 3 * 1000, class: DispatchClass::Normal }, + DispatchInfo { weight: 3, class: DispatchClass::Normal }, ); } } diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 69652c1ae3a35..3bdf395c10e39 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -400,6 +400,7 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 0; pub const TransactionByteFee: u64 = 0; + pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -414,6 +415,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; + type TransactionWeightFee = TransactionWeightFee; } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); From c100df94c6605ee6fb679350d40caf88297cdd3a Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 23 Jul 2019 12:16:49 +0200 Subject: [PATCH 22/33] New convert for weight to fee --- core/sr-primitives/src/traits.rs | 1 - node-template/runtime/src/lib.rs | 10 ++++------ node/executor/src/lib.rs | 11 +++++------ node/runtime/src/impls.rs | 21 +++++++++++++++++++++ node/runtime/src/lib.rs | 5 ++--- srml/balances/src/lib.rs | 23 +++++++++++------------ srml/balances/src/mock.rs | 21 ++++++++++++--------- srml/contracts/src/tests.rs | 3 +-- srml/council/src/lib.rs | 3 +-- srml/democracy/src/lib.rs | 3 +-- srml/elections/src/lib.rs | 3 +-- srml/example/src/lib.rs | 3 +-- srml/executive/src/lib.rs | 5 ++--- srml/staking/src/mock.rs | 3 +-- srml/treasury/src/lib.rs | 3 +-- 15 files changed, 64 insertions(+), 54 deletions(-) diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 079e0b94a41ed..670f8d181d1b5 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -166,7 +166,6 @@ impl Convert for Identity { /// A structure that performs standard conversion using the standard Rust conversion traits. pub struct ConvertInto; - impl> Convert for ConvertInto { fn convert(a: A) -> B { a.into() } } diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index af107f5daae60..c56e57542cbd9 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -10,10 +10,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use rstd::prelude::*; use primitives::{ed25519, sr25519, OpaqueMetadata}; -use sr_primitives::{ - ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str, - traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify}, weights::Weight, -}; +use sr_primitives::{ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str}; +use sr_primitives::traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto}; +use sr_primitives::weights::Weight; use client::{ block_builder::api::{CheckInherentsResult, InherentData, self as block_builder_api}, runtime_api, impl_runtime_apis @@ -166,7 +165,6 @@ parameter_types! { pub const CreationFee: u128 = 0; pub const TransactionBaseFee: u128 = 0; pub const TransactionByteFee: u128 = 1; - pub const TransactionWeightFee: u128 = 1; } impl balances::Trait for Runtime { @@ -187,7 +185,7 @@ impl balances::Trait for Runtime { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type TransactionWeightFee = TransactionWeightFee; + type WeightToFee = ConvertInto; } impl sudo::Trait for Runtime { diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index bc23fc5b58bbb..5463f2413ac59 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -47,7 +47,7 @@ mod tests { NativeOrEncoded }; use node_primitives::{Hash, BlockNumber, AccountId, Balance, Index}; - use runtime_primitives::traits::{Header as HeaderT, Hash as HashT}; + use runtime_primitives::traits::{Header as HeaderT, Hash as HashT, Convert}; use runtime_primitives::{generic::Era, ApplyOutcome, ApplyError, ApplyResult, Perbill}; use runtime_primitives::weights::{WeightMultiplier, GetDispatchInfo, Weight}; use {balances, contracts, indices, staking, system, timestamp}; @@ -60,6 +60,7 @@ mod tests { TransactionBaseFee, TransactionByteFee, MaximumBlockWeight, }; use node_runtime::constants::currency::*; + use node_runtime::impls::WeightToFee; use wabt; use primitives::map; @@ -1104,18 +1105,16 @@ mod tests { let length_fee = >::get() + >::get() * (xt.clone().encode().len() as Balance); - println!("++ len fee = {:?}", length_fee); balance_alice -= length_fee; - // TODO: the 1_000_000 should go away. - let weight_fee = default_transfer_call().get_dispatch_info().weight as Balance * 1_000_000; + let weight = default_transfer_call().get_dispatch_info().weight; + let weight_fee = WeightToFee::convert(weight); + // we know that weight to fee multiplier is effect-less in block 1. assert_eq!(weight_fee as Balance, MILLICENTS); balance_alice -= weight_fee; - println!("++ wei fee = {:?}", weight_fee); balance_alice -= tip; - println!("++ tip fee = {:?}", tip); // TODO: why again??? creation fee should not be deducted here. balance_alice -= creation_fee(); diff --git a/node/runtime/src/impls.rs b/node/runtime/src/impls.rs index 288dac3ea9941..71e6e3215ec35 100644 --- a/node/runtime/src/impls.rs +++ b/node/runtime/src/impls.rs @@ -47,6 +47,27 @@ impl Convert for CurrencyToVoteHandler { fn convert(x: u128) -> Balance { x * Self::factor() } } +/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the +/// node's balance type. +/// +/// This should typically create a mapping between the following ranges: +/// - [0, system::MaximumBlockWeight] +/// - [Balance::min, Balance::max] +/// +/// Yet, it can be used for any other sort of change to weight-fee. Some examples being: +/// - Setting it to `0` will essentially disable the weight fee. +/// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. +/// +/// By default, substrate node will have a weight range of [0, 1_000_000]. +pub struct WeightToFee; +impl Convert for WeightToFee { + fn convert(x: Weight) -> Balance { + // substrate-node a weight of 10 (smallest non-zero weight) to be mapped to 10^7 units of + // fees, hence: + Balance::from(x).saturating_mul(1_000_000) + } +} + /// A struct that updates the weight multiplier based on the saturation level of the previous block. /// This should typically be called once per-block. /// diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 5315f6fa160cd..de5fa4301d370 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -59,7 +59,7 @@ pub use staking::StakerStatus; /// Implementations of some helper traits passed into runtime modules as associated types. pub mod impls; -use impls::{CurrencyToVoteHandler, WeightMultiplierUpdateHandler, Author}; +use impls::{CurrencyToVoteHandler, WeightMultiplierUpdateHandler, Author, WeightToFee}; /// Constant values used within the runtime. pub mod constants; @@ -143,7 +143,6 @@ parameter_types! { pub const CreationFee: Balance = 1 * CENTS; pub const TransactionBaseFee: Balance = 1 * CENTS; pub const TransactionByteFee: Balance = 10 * MILLICENTS; - pub const TransactionWeightFee: Balance = MILLICENTS / 1000; } impl balances::Trait for Runtime { @@ -159,7 +158,7 @@ impl balances::Trait for Runtime { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type TransactionWeightFee = TransactionWeightFee; + type WeightToFee = WeightToFee; } parameter_types! { diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 02b6b89266a87..030cb92ed5896 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -161,10 +161,10 @@ use srml_support::traits::{ use srml_support::dispatch::Result; use primitives::traits::{ Zero, SimpleArithmetic, StaticLookup, Member, CheckedAdd, CheckedSub, MaybeSerializeDebug, - Saturating, Bounded, SignedExtension, SaturatedConversion, DispatchError + Saturating, Bounded, SignedExtension, SaturatedConversion, DispatchError, Convert, }; use primitives::transaction_validity::{TransactionPriority, ValidTransaction}; -use primitives::weights::{DispatchInfo, SimpleDispatchInfo}; +use primitives::weights::{DispatchInfo, SimpleDispatchInfo, Weight}; use system::{IsDeadAccount, OnNewAccount, ensure_signed, ensure_root}; mod mock; @@ -207,8 +207,8 @@ pub trait Subtrait: system::Trait { /// The fee to be paid for making a transaction; the per-byte portion. type TransactionByteFee: Get; - /// The amount of fee deducted oer unit of weight. - type TransactionWeightFee: Get; + /// Convert a weight value into a deductible fee based on the currency type. + type WeightToFee: Convert; } pub trait Trait: system::Trait { @@ -253,8 +253,8 @@ pub trait Trait: system::Trait { /// The fee to be paid for making a transaction; the per-byte portion. type TransactionByteFee: Get; - /// The amount of fee deducted oer unit of weight. - type TransactionWeightFee: Get; + /// Convert a weight value into a deductible fee based on the currency type. + type WeightToFee: Convert; } impl, I: Instance> Subtrait for T { @@ -266,7 +266,7 @@ impl, I: Instance> Subtrait for T { type CreationFee = T::CreationFee; type TransactionBaseFee = T::TransactionBaseFee; type TransactionByteFee = T::TransactionByteFee; - type TransactionWeightFee = T::TransactionWeightFee; + type WeightToFee = T::WeightToFee; } decl_event!( @@ -790,7 +790,7 @@ impl, I: Instance> Trait for ElevatedTrait { type CreationFee = T::CreationFee; type TransactionBaseFee = T::TransactionBaseFee; type TransactionByteFee = T::TransactionByteFee; - type TransactionWeightFee = T::TransactionWeightFee; + type WeightToFee = T::WeightToFee; } impl, I: Instance> Currency for Module @@ -1195,10 +1195,9 @@ impl, I: Instance> TakeFees { // cap the weight to the maximum defined in runtime, otherwise it will be the `Bounded` // maximum of its data type, which is not desired. let capped_weight = info.weight.min(::MaximumBlockWeight::get()); - let weight_fee: T::Balance = >::next_weight_multiplier() - .apply_to(capped_weight).saturated_into(); - let per_weight = T::TransactionWeightFee::get(); - weight_fee.saturating_mul(per_weight) + let weight_update = >::next_weight_multiplier(); + let adjusted_weight = weight_update.apply_to(capped_weight); + T::WeightToFee::convert(adjusted_weight) }; len_fee.saturating_add(weight_fee).saturating_add(tip) diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index cb60501e42bf3..116515c368f53 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -18,7 +18,7 @@ #![cfg(test)] -use primitives::{Perbill, traits::IdentityLookup, testing::Header, weights::{DispatchInfo, Weight}}; +use primitives::{Perbill, traits::{Convert, IdentityLookup}, testing::Header, weights::{DispatchInfo, Weight}}; use substrate_primitives::{H256, Blake2Hasher}; use runtime_io; use srml_support::{impl_outer_origin, parameter_types}; @@ -37,6 +37,7 @@ thread_local! { static TRANSACTION_BASE_FEE: RefCell = RefCell::new(0); static TRANSACTION_BYTE_FEE: RefCell = RefCell::new(1); static TRANSACTION_WEIGHT_FEE: RefCell = RefCell::new(1); + static WEIGHT_TO_FEE: RefCell = RefCell::new(1); } pub struct ExistentialDeposit; @@ -64,9 +65,11 @@ impl Get for TransactionByteFee { fn get() -> u64 { TRANSACTION_BYTE_FEE.with(|v| *v.borrow()) } } -pub struct TransactionWeightFee; -impl Get for TransactionWeightFee { - fn get() -> u64 { TRANSACTION_WEIGHT_FEE.with(|v| *v.borrow()) } +pub struct WeightToFee(u64); +impl Convert for WeightToFee { + fn convert(t: Weight) -> u64 { + WEIGHT_TO_FEE.with(|v| *v.borrow() * (t as u64)) + } } // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. @@ -107,13 +110,13 @@ impl Trait for Runtime { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type TransactionWeightFee = TransactionWeightFee; + type WeightToFee = WeightToFee; } pub struct ExtBuilder { transaction_base_fee: u64, transaction_byte_fee: u64, - transaction_weight_fee: u64, + weight_to_fee: u64, existential_deposit: u64, transfer_fee: u64, creation_fee: u64, @@ -125,7 +128,7 @@ impl Default for ExtBuilder { Self { transaction_base_fee: 0, transaction_byte_fee: 0, - transaction_weight_fee: 0, + weight_to_fee: 0, existential_deposit: 0, transfer_fee: 0, creation_fee: 0, @@ -138,7 +141,7 @@ impl ExtBuilder { pub fn transaction_fees(mut self, base_fee: u64, byte_fee: u64, weight_fee: u64) -> Self { self.transaction_base_fee = base_fee; self.transaction_byte_fee = byte_fee; - self.transaction_weight_fee = weight_fee; + self.weight_to_fee = weight_fee; self } pub fn existential_deposit(mut self, existential_deposit: u64) -> Self { @@ -171,7 +174,7 @@ impl ExtBuilder { CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee); TRANSACTION_BASE_FEE.with(|v| *v.borrow_mut() = self.transaction_base_fee); TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.transaction_byte_fee); - TRANSACTION_WEIGHT_FEE.with(|v| *v.borrow_mut() = self.transaction_weight_fee); + WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); } pub fn build(self) -> runtime_io::TestExternalities { self.set_associated_consts(); diff --git a/srml/contracts/src/tests.rs b/srml/contracts/src/tests.rs index 6c81bac39c8f4..db196ef7fe779 100644 --- a/srml/contracts/src/tests.rs +++ b/srml/contracts/src/tests.rs @@ -100,7 +100,6 @@ parameter_types! { pub const MaximumBlockLength: u32 = 2 * 1024; pub const BalancesTransactionBaseFee: u64 = 0; pub const BalancesTransactionByteFee: u64 = 0; - pub const BalancesTransactionWeightFee: u64 = 0; pub const AvailableBlockRatio: Perbill = Perbill::one(); } impl system::Trait for Test { @@ -132,7 +131,7 @@ impl balances::Trait for Test { type CreationFee = CreationFee; type TransactionBaseFee = BalancesTransactionBaseFee; type TransactionByteFee = BalancesTransactionByteFee; - type TransactionWeightFee = BalancesTransactionWeightFee; + type WeightToFee = (); } parameter_types! { pub const MinimumPeriod: u64 = 1; diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index 6b22010144e07..3fc9926942e70 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -125,7 +125,6 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 1; pub const TransactionByteFee: u64 = 0; - pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -140,7 +139,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type TransactionWeightFee = TransactionWeightFee; + type WeightToFee = (); } parameter_types! { pub const LaunchPeriod: u64 = 1; diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index 2d42c4ace032f..c90e3609c4e8d 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -1043,7 +1043,6 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 0; pub const TransactionByteFee: u64 = 0; - pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -1058,7 +1057,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type TransactionWeightFee = TransactionWeightFee; + type WeightToFee = (); } parameter_types! { pub const LaunchPeriod: u64 = 2; diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 7c3e572713bbd..72b1c60b52ac0 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -1145,7 +1145,6 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 0; pub const TransactionByteFee: u64 = 0; - pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -1160,7 +1159,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type TransactionWeightFee = TransactionWeightFee; + type WeightToFee = (); } parameter_types! { pub const CandidacyBond: u64 = 3; diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index d8220b40ee5cb..68b52425ed007 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -550,7 +550,6 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 0; pub const TransactionByteFee: u64 = 0; - pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -565,7 +564,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type TransactionWeightFee = TransactionWeightFee; + type WeightToFee = (); } impl Trait for Test { type Event = (); diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 12646d48c23dc..079efc59b79bd 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -360,7 +360,7 @@ mod tests { use primitives::generic::Era; use primitives::Perbill; use primitives::weights::Weight; - use primitives::traits::{Header as HeaderT, BlakeTwo256, IdentityLookup}; + use primitives::traits::{Header as HeaderT, BlakeTwo256, IdentityLookup, ConvertInto}; use primitives::testing::{Digest, Header, Block}; use srml_support::{impl_outer_event, impl_outer_origin, parameter_types}; use srml_support::traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason, Get}; @@ -409,7 +409,6 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 10; pub const TransactionByteFee: u64 = 0; - pub const TransactionWeightFee: u64 = 1; } impl balances::Trait for Runtime { type Balance = u64; @@ -424,7 +423,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type TransactionWeightFee = TransactionWeightFee; + type WeightToFee = ConvertInto; } impl ValidateUnsigned for Runtime { diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 78e3243065fb0..a81d64db6897d 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -112,7 +112,6 @@ parameter_types! { pub const CreationFee: Balance = 0; pub const TransactionBaseFee: u64 = 0; pub const TransactionByteFee: u64 = 0; - pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = Balance; @@ -127,7 +126,7 @@ impl balances::Trait for Test { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type TransactionWeightFee = TransactionWeightFee; + type WeightToFee = (); } parameter_types! { pub const Period: BlockNumber = 1; diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 3bdf395c10e39..56a4d12aa3437 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -400,7 +400,6 @@ mod tests { pub const CreationFee: u64 = 0; pub const TransactionBaseFee: u64 = 0; pub const TransactionByteFee: u64 = 0; - pub const TransactionWeightFee: u64 = 0; } impl balances::Trait for Test { type Balance = u64; @@ -415,7 +414,7 @@ mod tests { type CreationFee = CreationFee; type TransactionBaseFee = TransactionBaseFee; type TransactionByteFee = TransactionByteFee; - type TransactionWeightFee = TransactionWeightFee; + type WeightToFee = (); } parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); From f5d33c60aeffecace42079d75a6fb89d9320479b Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 23 Jul 2019 16:27:27 +0200 Subject: [PATCH 23/33] more tests. --- core/sr-primitives/src/lib.rs | 35 ++++++++--------------- node-template/runtime/src/lib.rs | 2 +- node/executor/src/lib.rs | 1 - node/runtime/src/impls.rs | 48 ++++++++++++++++++++++++++++++-- 4 files changed, 59 insertions(+), 27 deletions(-) diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index cbba1d750f996..5eb18807dca6c 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -422,16 +422,13 @@ impl Fixed64 { /// Performs a saturated multiply and accumulate. /// /// Returns a saturated `n + (self * n)`. - pub fn saturated_multiply_accumulate(&self, int: N) -> N - where N: Copy + Clone + From + Saturating + Bounded + UniqueSaturatedInto - + From + ops::Rem + ops::Div + ops::Mul - + ops::Add, - { + /// TODO: generalize this to any weight type. + pub fn saturated_multiply_accumulate(&self, int: u32) -> u32 { let parts = self.0; let positive = parts > 0; // natural parts might overflow. - let natural_parts = self.clone().saturated_into::(); + let natural_parts = self.clone().saturated_into::(); // fractional parts can always fit into u32. let perbill_parts = (parts.abs() % DIV) as u32; @@ -453,22 +450,14 @@ impl Fixed64 { } } -macro_rules! impl_from_for_unsigned { - ( $($type:ty),+ ) => { - $( - impl From for $type { - fn from(t: Fixed64) -> Self { - // Note that such implementation with `max(0)` only makes sense for unsigned - // numbers. - (t.0.max(0) / DIV).try_into().unwrap_or(Bounded::max_value()) - } - } - )* +impl UniqueSaturatedInto for Fixed64 { + /// Note that the maximum value of Fixed64 might be more than what can fit in u32. This is hence, + /// expected to be lossy. + fn unique_saturated_into(self) -> u32 { + (self.0.abs() / DIV).try_into().unwrap_or(Bounded::max_value()) } } -impl_from_for_unsigned!(u16, u32, u64, u128); - impl Saturating for Fixed64 { fn saturating_add(self, rhs: Self) -> Self { Self(self.0.saturating_add(rhs.0)) @@ -481,8 +470,8 @@ impl Saturating for Fixed64 { } } -/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait for -/// safe addition. +/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait +/// for safe addition. impl ops::Add for Fixed64 { type Output = Self; @@ -491,8 +480,8 @@ impl ops::Add for Fixed64 { } } -/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait for -/// safe subtraction. +/// Note that this is a standard, _potentially-panicking_, implementation. Use `Saturating` trait +/// for safe subtraction. impl ops::Sub for Fixed64 { type Output = Self; diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index c56e57542cbd9..eedcda4d149c4 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -96,7 +96,7 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const BlockHashCount: BlockNumber = 250; - pub const MaximumBlockWeight: Weight = 1_000_000_000; + pub const MaximumBlockWeight: Weight = 1_000_000; pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; } diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 5463f2413ac59..d805b7678eae0 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -588,7 +588,6 @@ mod tests { ).0.unwrap(); runtime_io::with_externalities(&mut t, || { - // TODO: this needs investigating: why are we deducting creation fee twice here? and why bob also pays it? // NOTE: fees differ slightly in tests that execute more than one block due to the // weight update. assert_eq_error_rate!( diff --git a/node/runtime/src/impls.rs b/node/runtime/src/impls.rs index 71e6e3215ec35..5c91c44468ec4 100644 --- a/node/runtime/src/impls.rs +++ b/node/runtime/src/impls.rs @@ -110,6 +110,8 @@ impl Convert<(Weight, WeightMultiplier), WeightMultiplier> for WeightMultiplierU let second_term = v_squared_2.saturating_mul(diff_squared); if positive { + // Note: this is merely bounded by how big the multiplier and the inner value can go, + // not by any economical reasoning. let excess = first_term.saturating_add(second_term); multiplier.saturating_add(WeightMultiplier::from_fixed(excess)) } else { @@ -119,7 +121,7 @@ impl Convert<(Weight, WeightMultiplier), WeightMultiplier> for WeightMultiplierU // despite the fact that apply_to saturates weight (final fee cannot go below 0) // it is crucially important to stop here and don't further reduce the weight fee // multiplier. While at -1, it means that the network is so un-congested that all - // transactions are practically free. We stop here and only increase if the network + // transactions have no weight fee. We stop here and only increase if the network // became more busy. .max(WeightMultiplier::from_rational(-1, 1)) } @@ -131,7 +133,8 @@ mod tests { use super::*; use runtime_primitives::weights::Weight; use runtime_primitives::Perbill; - use crate::MaximumBlockWeight; + use crate::{MaximumBlockWeight, AvailableBlockRatio, Runtime}; + use crate::constants::currency::*; fn max() -> Weight { >::get() @@ -164,6 +167,47 @@ mod tests { WeightMultiplier::from_parts(parts) } + #[test] + fn empty_chain_simulation() { + // just a few txs per_block. + let block_weight = 1000; + let mut wm = WeightMultiplier::default(); + let mut iterations: u64 = 0; + loop { + let next = WeightMultiplierUpdateHandler::convert((block_weight, wm)); + wm = next; + if wm == WeightMultiplier::from_rational(-1, 1) { break; } + iterations += 1; + } + println!("iteration {}, new wm = {:?}. Weight fee is now zero", iterations, wm); + } + + #[test] + #[ignore] + fn congested_chain_simulation() { + // `cargo test congested_chain_simulation -- --nocapture` to get some insight. + // almost full. The entire quota of normal transactions is taken. + let block_weight = >::get() * max(); + let tx_weight = 1000; + let mut wm = WeightMultiplier::default(); + let mut iterations: u64 = 0; + loop { + let next = WeightMultiplierUpdateHandler::convert((block_weight, wm)); + if wm == next { break; } + wm = next; + iterations += 1; + let fee = ::WeightToFee::convert(wm.apply_to(tx_weight)); + println!( + "iteration {}, new wm = {:?}. Fee at this point is: {} millicents, {} cents, {} dollars", + iterations, + wm, + fee / MILLICENTS, + fee / CENTS, + fee / DOLLARS + ); + } + } + #[test] fn stateless_weight_mul() { // Light block. Fee is reduced a little. From 0c1c26832943b74d62b0d6d7865a6836beb54616 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 23 Jul 2019 16:48:28 +0200 Subject: [PATCH 24/33] remove merge redundancy. --- srml/system/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index e529c97671d8e..cd189ec7b9045 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -1096,10 +1096,6 @@ mod tests { ::AvailableBlockRatio::get() * ::MaximumBlockWeight::get() } - fn normal_length_limit() -> u32 { - ::AvailableBlockRatio::get() * ::MaximumBlockLength::get() - } - #[test] fn origin_works() { let o = Origin::from(RawOrigin::::Signed(1u64)); From 6a0a1d47273091b8d3c274f933004f91b16c7e00 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 24 Jul 2019 11:01:00 +0200 Subject: [PATCH 25/33] Fix system test. --- srml/system/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index cd189ec7b9045..e529c97671d8e 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -1096,6 +1096,10 @@ mod tests { ::AvailableBlockRatio::get() * ::MaximumBlockWeight::get() } + fn normal_length_limit() -> u32 { + ::AvailableBlockRatio::get() * ::MaximumBlockLength::get() + } + #[test] fn origin_works() { let o = Origin::from(RawOrigin::::Signed(1u64)); From c3e0ee3677af555b6a85195ef263ef524dde0879 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 24 Jul 2019 11:33:27 +0200 Subject: [PATCH 26/33] Bring back subkey stuff. --- core/test-runtime/src/lib.rs | 5 +++-- srml/system/benches/bench.rs | 7 +++---- subkey/src/main.rs | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index 13b8a9eac86c6..3bfa891ef0227 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -34,8 +34,7 @@ use substrate_client::{ impl_runtime_apis, }; use runtime_primitives::{ - ApplyResult, - create_runtime_str, + ApplyResult, create_runtime_str, Perbill, transaction_validity::{TransactionValidity, ValidTransaction}, traits::{ BlindCheckable, BlakeTwo256, Block as BlockT, Extrinsic as ExtrinsicT, @@ -331,6 +330,7 @@ parameter_types! { pub const MinimumPeriod: u64 = 5; pub const MaximumBlockWeight: u32 = 4 * 1024 * 1024; pub const MaximumBlockLength: u32 = 4 * 1024 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); } impl srml_system::Trait for Runtime { @@ -347,6 +347,7 @@ impl srml_system::Trait for Runtime { type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; } impl srml_timestamp::Trait for Runtime { diff --git a/srml/system/benches/bench.rs b/srml/system/benches/bench.rs index 5ff63baa1cdb4..071446ea355f7 100644 --- a/srml/system/benches/bench.rs +++ b/srml/system/benches/bench.rs @@ -19,10 +19,7 @@ use srml_system as system; use srml_support::{decl_module, decl_event, impl_outer_origin, impl_outer_event}; use runtime_io::{with_externalities, Blake2Hasher}; use substrate_primitives::H256; -use primitives::{ - traits::{BlakeTwo256, IdentityLookup}, - testing::Header, -}; +use primitives::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; mod module { use super::*; @@ -58,6 +55,7 @@ srml_support::parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: u32 = 4 * 1024 * 1024; pub const MaximumBlockLength: u32 = 4 * 1024 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); } #[derive(Clone, Eq, PartialEq)] pub struct Runtime; @@ -75,6 +73,7 @@ impl system::Trait for Runtime { type BlockHashCount = BlockHashCount; type MaximumBlockWeight = MaximumBlockWeight; type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; } impl module::Trait for Runtime { diff --git a/subkey/src/main.rs b/subkey/src/main.rs index f9432b42c12b3..16abc8723aba7 100644 --- a/subkey/src/main.rs +++ b/subkey/src/main.rs @@ -26,10 +26,10 @@ use substrate_primitives::{ ed25519, sr25519, hexdisplay::HexDisplay, Pair, Public, blake2_256, crypto::{Ss58Codec, set_default_ss58_version, Ss58AddressFormat} }; -use parity_codec::{Encode, Decode, Compact}; +use parity_codec::{Encode, Decode}; use sr_primitives::generic::Era; use node_primitives::{Balance, Index, Hash}; -use node_runtime::{Call, UncheckedExtrinsic, /*CheckNonce, TakeFees, */BalancesCall}; +use node_runtime::{Call, UncheckedExtrinsic, BalancesCall, Runtime}; mod vanity; @@ -90,14 +90,14 @@ fn execute(matches: clap::ArgMatches) where <::Pair as Pair>::Signature: AsRef<[u8]> + AsMut<[u8]> + Default, <::Pair as Pair>::Public: Sized + AsRef<[u8]> + Ss58Codec + AsRef<<::Pair as Pair>::Public>, { - // let extra = |i: Index, f: Balance| { - // ( - // system::CheckEra::::from(Era::Immortal), - // system::CheckNonce::::from(i), - // system::CheckWeight::::from(), - // balances::TakeFees::::from(f), - // ) - // }; + let extra = |i: Index, f: Balance| { + ( + system::CheckEra::::from(Era::Immortal), + system::CheckNonce::::from(i), + system::CheckWeight::::from(), + balances::TakeFees::::from(f), + ) + }; let password = matches.value_of("password"); let maybe_network = matches.value_of("network"); if let Some(network) = maybe_network { @@ -138,7 +138,7 @@ fn execute(matches: clap::ArgMatches) where let sig = pair.sign(&message); println!("{}", hex::encode(&sig)); } - /*("transfer", Some(matches)) => { + ("transfer", Some(matches)) => { let signer = matches.value_of("from") .expect("parameter is required; thus it can't be None; qed"); let signer = Sr25519::pair_from_suri(signer, password); @@ -225,7 +225,7 @@ fn execute(matches: clap::ArgMatches) where ); println!("0x{}", hex::encode(&extrinsic.encode())); - }*/ + } ("verify", Some(matches)) => { let sig_data = matches.value_of("sig") .expect("signature parameter is required; thus it can't be None; qed"); From 5b0c7150d5f2147fc5a88f116255af238430cd1e Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 24 Jul 2019 17:09:58 +0200 Subject: [PATCH 27/33] a few stress tests. --- core/sr-primitives/src/lib.rs | 2 +- node/executor/Cargo.toml | 1 + node/executor/src/lib.rs | 134 +++++++++++++++++++++++++++++++++- srml/staking/src/mock.rs | 2 +- 4 files changed, 134 insertions(+), 5 deletions(-) diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 5eb18807dca6c..d6367d0e244c4 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -422,7 +422,7 @@ impl Fixed64 { /// Performs a saturated multiply and accumulate. /// /// Returns a saturated `n + (self * n)`. - /// TODO: generalize this to any weight type. + /// TODO: generalize this to any weight type. #3189 pub fn saturated_multiply_accumulate(&self, int: u32) -> u32 { let parts = self.0; let positive = parts > 0; diff --git a/node/executor/Cargo.toml b/node/executor/Cargo.toml index 345401141913c..2e3ba49d985ea 100644 --- a/node/executor/Cargo.toml +++ b/node/executor/Cargo.toml @@ -34,3 +34,4 @@ wabt = "~0.7.4" [features] benchmarks = [] +stress-test = [] diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index d805b7678eae0..80d807363e81e 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -59,7 +59,7 @@ mod tests { GrandpaConfig, IndicesConfig, ContractsConfig, Event, SessionKeys, CreationFee, SignedExtra, TransactionBaseFee, TransactionByteFee, MaximumBlockWeight, }; - use node_runtime::constants::currency::*; + use node_runtime::constants::{currency::*, fee::TARGET_BLOCK_FULLNESS}; use node_runtime::impls::WeightToFee; use wabt; use primitives::map; @@ -98,7 +98,7 @@ mod tests { /// Get the target weight of the fee multiplier. fn _multiplier_target() -> Weight { - >::get() / 4 + TARGET_BLOCK_FULLNESS * >::get() } /// Default creation fee. @@ -589,7 +589,7 @@ mod tests { runtime_io::with_externalities(&mut t, || { // NOTE: fees differ slightly in tests that execute more than one block due to the - // weight update. + // weight update. Hence, using `assert_eq_error_rate`. assert_eq_error_rate!( Balances::total_balance(&alice()), 32 * DOLLARS - 2 * transfer_fee(&xt()) - 2 * creation_fee(), @@ -1122,6 +1122,134 @@ mod tests { }); } + #[test] + #[should_panic] + #[cfg(feature = "stress-test")] + fn block_weight_capacity_report() { + // Just report how many transfer calls you could fit into a block. The number should at least + // be a few hundred (250 at the time of writing but can change over time). Runs until panic. + + // execution ext. + let mut t = new_test_ext(COMPACT_CODE, false); + // setup ext. + let mut tt = new_test_ext(COMPACT_CODE, false); + + let factor = 50; + let mut time = 10; + let mut nonce: Index = 0; + let mut block_number = 1; + let mut previous_hash: Hash = GENESIS_HASH.into(); + + loop { + let num_transfers = block_number * factor; + let mut xts = (0..num_transfers).map(|i| CheckedExtrinsic { + signed: Some((charlie(), signed_extra(nonce + i as Index, 0))), + function: Call::Balances(balances::Call::transfer(bob().into(), 0)), + }).collect::>(); + + xts.insert(0, CheckedExtrinsic { + signed: None, + function: Call::Timestamp(timestamp::Call::set(time)), + }); + + // NOTE: this is super slow. Can probably be improved. + let block = construct_block( + &mut tt, + block_number, + previous_hash, + xts + ); + + let len = block.0.len(); + print!( + "++ Executing block with {} transfers. Block size = {} bytes / {} kb / {} mb", + num_transfers, + len, + len / 1024, + len / 1024 / 1024, + ); + + let r = executor().call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "Core_execute_block", + &block.0, + true, + None, + ).0; + + println!(" || Result = {:?}", r); + assert!(r.is_ok()); + + previous_hash = block.1; + nonce += num_transfers; + time += 10; + block_number += 1; + } + } + + #[test] + #[should_panic] + #[cfg(feature = "stress-test")] + fn block_length_capacity_report() { + // Just report how big a block can get. Executes until panic. Should be ignored unless if + // manually inspected. The number should at least be a few megabytes (5 at the time of + // writing but can change over time). + + // execution ext. + let mut t = new_test_ext(COMPACT_CODE, false); + // setup ext. + let mut tt = new_test_ext(COMPACT_CODE, false); + + let factor = 256 * 1024; + let mut time = 10; + let mut nonce: Index = 0; + let mut block_number = 1; + let mut previous_hash: Hash = GENESIS_HASH.into(); + + loop { + // NOTE: this is super slow. Can probably be improved. + let block = construct_block( + &mut tt, + block_number, + previous_hash, + vec![ + CheckedExtrinsic { + signed: None, + function: Call::Timestamp(timestamp::Call::set(time)), + }, + CheckedExtrinsic { + signed: Some((charlie(), signed_extra(nonce, 0))), + function: Call::System(system::Call::remark(vec![0u8; (block_number * factor) as usize])), + }, + ] + ); + + let len = block.0.len(); + print!( + "++ Executing block with big remark. Block size = {} bytes / {} kb / {} mb", + len, + len / 1024, + len / 1024 / 1024, + ); + + let r = executor().call::<_, NeverNativeValue, fn() -> _>( + &mut t, + "Core_execute_block", + &block.0, + true, + None, + ).0; + + println!(" || Result = {:?}", r); + assert!(r.is_ok()); + + previous_hash = block.1; + nonce += 1; + time += 10; + block_number += 1; + } + } + #[cfg(feature = "benchmarks")] mod benches { use super::*; diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 7b5502b5cc7fc..30475be68fe79 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -98,7 +98,7 @@ parameter_types! { impl system::Trait for Test { type Origin = Origin; type Index = u64; - type BlockNumber = u64; + type BlockNumber = BlockNumber; type Hash = H256; type Hashing = ::primitives::traits::BlakeTwo256; type AccountId = AccountId; From e683829521450e4b9258cfea23206ef79923cea2 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 24 Jul 2019 18:43:00 +0200 Subject: [PATCH 28/33] fix some of the grumbles. --- core/sr-primitives/src/lib.rs | 12 ++++++------ core/sr-primitives/src/testing.rs | 4 ++-- node/executor/src/lib.rs | 16 ++++++---------- srml/support/src/lib.rs | 14 ++++---------- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index d6367d0e244c4..922fe7f9defdb 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -184,14 +184,14 @@ impl Permill { /// create a new raw instance. This can be called at compile time. pub const fn from_const_parts(parts: u32) -> Self { - Self([parts, 1_000_000] [(parts > 1_000_000) as usize]) + Self([parts, 1_000_000][(parts > 1_000_000) as usize]) } /// From an explicitly defined number of parts per maximum of the type. - pub fn from_parts(x: u32) -> Self { Self(x.min(1_000_000)) } + pub fn from_parts(parts: u32) -> Self { Self::from_const_parts(parts) } /// Converts from a percent. Equal to `x / 100`. - pub fn from_percent(x: u32) -> Self { Self(x.min(100) * 10_000) } + pub const fn from_percent(x: u32) -> Self { Self([x, 100][(x > 100) as usize] * 10_000) } /// Converts a fraction into `Permill`. #[cfg(feature = "std")] @@ -293,14 +293,14 @@ impl Perbill { /// create a new raw instance. This can be called at compile time. pub const fn from_const_parts(parts: u32) -> Self { - Self([parts, 1_000_000_000] [(parts > 1_000_000_000) as usize]) + Self([parts, 1_000_000_000][(parts > 1_000_000_000) as usize]) } /// From an explicitly defined number of parts per maximum of the type. - pub fn from_parts(x: u32) -> Self { Self(x.min(1_000_000_000)) } + pub fn from_parts(parts: u32) -> Self { Self::from_const_parts(parts) } /// Converts from a percent. Equal to `x / 100`. - pub fn from_percent(x: u32) -> Self { Self(x.min(100) * 10_000_000) } + pub const fn from_percent(x: u32) -> Self { Self([x, 100][(x > 100) as usize] * 10_000_000) } /// Construct new instance where `x` is in millionths. Value equivalent to `x / 1,000,000`. pub fn from_millionths(x: u32) -> Self { Self(x.min(1_000_000) * 1000) } diff --git a/core/sr-primitives/src/testing.rs b/core/sr-primitives/src/testing.rs index 32c52f6981c56..6ef7844fc9b3b 100644 --- a/core/sr-primitives/src/testing.rs +++ b/core/sr-primitives/src/testing.rs @@ -24,7 +24,7 @@ use crate::traits::{ ValidateUnsigned, SignedExtension, Dispatchable, }; use crate::{generic, KeyTypeId}; -use crate::weights::{GetDispatchInfo, DispatchInfo, Weight}; +use crate::weights::{GetDispatchInfo, DispatchInfo}; pub use substrate_primitives::H256; use substrate_primitives::U256; use substrate_primitives::ed25519::{Public as AuthorityId}; @@ -282,7 +282,7 @@ impl GetDispatchInfo for TestXt { fn get_dispatch_info(&self) -> DispatchInfo { // for testing: weight == size. DispatchInfo { - weight: self.encode().len() as Weight, + weight: self.encode().len() as _, ..Default::default() } } diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 80d807363e81e..676a68d2139e0 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -49,7 +49,7 @@ mod tests { use node_primitives::{Hash, BlockNumber, AccountId, Balance, Index}; use runtime_primitives::traits::{Header as HeaderT, Hash as HashT, Convert}; use runtime_primitives::{generic::Era, ApplyOutcome, ApplyError, ApplyResult, Perbill}; - use runtime_primitives::weights::{WeightMultiplier, GetDispatchInfo, Weight}; + use runtime_primitives::weights::{WeightMultiplier, GetDispatchInfo}; use {balances, contracts, indices, staking, system, timestamp}; use contracts::ContractAddressFor; use system::{EventRecord, Phase}; @@ -57,9 +57,9 @@ mod tests { Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, BuildStorage, GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, System, SystemConfig, GrandpaConfig, IndicesConfig, ContractsConfig, Event, SessionKeys, CreationFee, SignedExtra, - TransactionBaseFee, TransactionByteFee, MaximumBlockWeight, + TransactionBaseFee, TransactionByteFee, }; - use node_runtime::constants::{currency::*, fee::TARGET_BLOCK_FULLNESS}; + use node_runtime::constants::currency::*; use node_runtime::impls::WeightToFee; use wabt; use primitives::map; @@ -88,19 +88,15 @@ mod tests { let length_fee = >::get() + >::get() * (extrinsic.encode().len() as Balance); - let mut weight_fee = default_transfer_call().get_dispatch_info().weight as Balance; - weight_fee = weight_fee * 1_000_000 as Balance; + + let weight = default_transfer_call().get_dispatch_info().weight; + let weight_fee = ::WeightToFee::convert(weight); // NOTE: we don't need this anymore, but in case needed, this makes the fee accurate over // multiple blocks. // weight_fee = >::next_weight_multiplier().apply_to(weight_fee as u32) as Balance; length_fee + weight_fee } - /// Get the target weight of the fee multiplier. - fn _multiplier_target() -> Weight { - TARGET_BLOCK_FULLNESS * >::get() - } - /// Default creation fee. fn creation_fee() -> Balance { >::get() diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index 05cadb29948fc..7c4d88489b3e9 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -225,22 +225,16 @@ macro_rules! __assert_eq_uvec { /// # Example /// /// ```rust -/// #[macro_use] -/// # extern crate srml_support; -/// # use srml_support::{assert_eq_error_rate}; /// # fn main() { -/// assert_eq_error_rate!(10, 10, 0); -/// assert_eq_error_rate!(10, 11, 1); -/// assert_eq_error_rate!(12, 10, 2); +/// srml_support::assert_eq_error_rate!(10, 10, 0); +/// srml_support::assert_eq_error_rate!(10, 11, 1); +/// srml_support::assert_eq_error_rate!(12, 10, 2); /// # } /// ``` /// /// ```rust,should_panic -/// #[macro_use] -/// # extern crate srml_support; -/// # use srml_support::{assert_eq_error_rate}; /// # fn main() { -/// assert_eq_error_rate!(12, 10, 1); +/// srml_support::assert_eq_error_rate!(12, 10, 1); /// # } /// ``` #[macro_export] From 0b592e24a66e9602eb9fc2b06373519fda7e2e39 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 24 Jul 2019 22:29:41 +0200 Subject: [PATCH 29/33] Final nits. --- node/executor/src/lib.rs | 12 ++++++------ node/runtime/src/constants.rs | 2 +- node/runtime/src/impls.rs | 8 ++++---- srml/balances/src/tests.rs | 2 +- srml/executive/src/lib.rs | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 676a68d2139e0..dc92ffb73679b 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -40,7 +40,7 @@ mod tests { use substrate_executor::{WasmExecutor, NativeExecutionDispatch}; use parity_codec::{Encode, Decode, Joiner}; use keyring::{AuthorityKeyring, AccountKeyring}; - use runtime_support::{Hashable, StorageValue, StorageMap, assert_eq_error_rate, traits::{Currency, Get}}; + use runtime_support::{Hashable, StorageValue, StorageMap, assert_eq_error_rate, traits::Currency}; use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities}; use primitives::{ twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, @@ -85,8 +85,8 @@ mod tests { /// Default transfer fee fn transfer_fee(extrinsic: &E) -> Balance { - let length_fee = >::get() + - >::get() * + let length_fee = TransactionBaseFee::get() + + TransactionByteFee::get() * (extrinsic.encode().len() as Balance); let weight = default_transfer_call().get_dispatch_info().weight; @@ -99,7 +99,7 @@ mod tests { /// Default creation fee. fn creation_fee() -> Balance { - >::get() + CreationFee::get() } fn alice() -> AccountId { @@ -1097,8 +1097,8 @@ mod tests { // - Creation-fee of bob's account. let mut balance_alice = (100 - 69) * DOLLARS; - let length_fee = >::get() + - >::get() * + let length_fee = TransactionBaseFee::get() + + TransactionByteFee::get() * (xt.clone().encode().len() as Balance); balance_alice -= length_fee; diff --git a/node/runtime/src/constants.rs b/node/runtime/src/constants.rs index 44b7fe97a7404..c030f57121149 100644 --- a/node/runtime/src/constants.rs +++ b/node/runtime/src/constants.rs @@ -48,5 +48,5 @@ pub mod fee { pub use runtime_primitives::Perbill; /// The block saturation level. Fees will be updates based on this value. - pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill::from_const_parts(1_000_000_000 / 4); + pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill::from_percent(25); } \ No newline at end of file diff --git a/node/runtime/src/impls.rs b/node/runtime/src/impls.rs index 5c91c44468ec4..0c106e908ccbd 100644 --- a/node/runtime/src/impls.rs +++ b/node/runtime/src/impls.rs @@ -20,7 +20,7 @@ use node_primitives::Balance; use runtime_primitives::weights::{Weight, WeightMultiplier}; use runtime_primitives::traits::{Convert, Saturating}; use runtime_primitives::Fixed64; -use support::traits::{Get, OnUnbalanced, Currency}; +use support::traits::{OnUnbalanced, Currency}; use crate::{Balances, Authorship, MaximumBlockWeight, NegativeImbalance}; use crate::constants::fee::TARGET_BLOCK_FULLNESS; @@ -87,7 +87,7 @@ pub struct WeightMultiplierUpdateHandler; impl Convert<(Weight, WeightMultiplier), WeightMultiplier> for WeightMultiplierUpdateHandler { fn convert(previous_state: (Weight, WeightMultiplier)) -> WeightMultiplier { let (block_weight, multiplier) = previous_state; - let max_weight = >::get(); + let max_weight = MaximumBlockWeight::get(); let target_weight = (TARGET_BLOCK_FULLNESS * max_weight) as u128; let block_weight = block_weight as u128; @@ -137,7 +137,7 @@ mod tests { use crate::constants::currency::*; fn max() -> Weight { - >::get() + MaximumBlockWeight::get() } fn target() -> Weight { @@ -187,7 +187,7 @@ mod tests { fn congested_chain_simulation() { // `cargo test congested_chain_simulation -- --nocapture` to get some insight. // almost full. The entire quota of normal transactions is taken. - let block_weight = >::get() * max(); + let block_weight = AvailableBlockRatio::get() * max(); let tx_weight = 1000; let mut wm = WeightMultiplier::default(); let mut iterations: u64 = 0; diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index f40335f9008a8..595be0e1ca603 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -781,7 +781,7 @@ fn signed_extension_take_fees_is_bounded() { // fee will be proportional to what is the actual maximum weight in the runtime. assert_eq!( Balances::free_balance(&1), - (10000 - <::MaximumBlockWeight as Get>::get()) as u64 + (10000 - ::MaximumBlockWeight::get()) as u64 ); } ); diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 079efc59b79bd..9ae794d698b55 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -363,7 +363,7 @@ mod tests { use primitives::traits::{Header as HeaderT, BlakeTwo256, IdentityLookup, ConvertInto}; use primitives::testing::{Digest, Header, Block}; use srml_support::{impl_outer_event, impl_outer_origin, parameter_types}; - use srml_support::traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason, Get}; + use srml_support::traits::{Currency, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason}; use system; use hex_literal::hex; @@ -568,7 +568,7 @@ mod tests { let xt = primitives::testing::TestXt(sign_extra(1, 0, 0), Call::transfer::(33, 0)); let encoded = xt.encode(); let encoded_len = encoded.len() as Weight; - let limit = >::get() * >::get(); + let limit = AvailableBlockRatio::get() * MaximumBlockWeight::get(); let num_to_exhaust_block = limit / encoded_len; with_externalities(&mut t, || { Executive::initialize_block(&Header::new( From 58191a3fac2d471e7d40a81f123a5f47a5d87399 Mon Sep 17 00:00:00 2001 From: Kian Peymani Date: Wed, 24 Jul 2019 23:06:30 +0200 Subject: [PATCH 30/33] Update srml/system/src/lib.rs Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com> --- srml/system/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index e529c97671d8e..80e37124489e6 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -893,7 +893,7 @@ impl SignedExtension for CheckWeight { len: usize, ) -> Result { // There is no point in writing to storage here since changes are discarded. This basically - // discards any transaction which is bigger than the length or weight limit __alone__,which + // discards any transaction which is bigger than the length or weight limit **alone**,which // is a guarantee that it will fail in the pre-dispatch phase. let _ = Self::check_block_length(info, len)?; let _ = Self::check_weight(info)?; From ec6554f71c676f4c63fedb8c3f371c3bcb0df9fa Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 25 Jul 2019 10:29:00 +0200 Subject: [PATCH 31/33] Scale weights by 1000. --- node/executor/src/lib.rs | 58 ++++++++++++++++---------------------- node/runtime/src/impls.rs | 6 ++-- node/runtime/src/lib.rs | 2 +- srml/authorship/src/lib.rs | 2 +- srml/balances/src/lib.rs | 4 +-- srml/collective/src/lib.rs | 8 +++--- srml/democracy/src/lib.rs | 34 +++++++++++----------- srml/elections/src/lib.rs | 20 ++++++------- srml/session/src/lib.rs | 2 +- srml/staking/src/lib.rs | 26 ++++++++--------- srml/sudo/src/lib.rs | 2 +- srml/support/src/lib.rs | 8 +++++- srml/system/src/lib.rs | 10 +++---- srml/timestamp/src/lib.rs | 2 +- srml/treasury/src/lib.rs | 6 ++-- 15 files changed, 93 insertions(+), 97 deletions(-) diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 3483651f1d51d..b470c7aa7cfd6 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -35,29 +35,26 @@ native_executor_instance!( #[cfg(test)] mod tests { - use runtime_io; use super::Executor; + use {balances, contracts, indices, staking, system, timestamp}; + use runtime_io; use substrate_executor::{WasmExecutor, NativeExecutionDispatch}; use parity_codec::{Encode, Decode, Joiner}; use keyring::{AccountKeyring, Ed25519Keyring, Sr25519Keyring}; use runtime_support::{Hashable, StorageValue, StorageMap, assert_eq_error_rate, traits::Currency}; use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities}; - use primitives::{ - twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, - NativeOrEncoded - }; + use primitives::{ twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, NativeOrEncoded}; use node_primitives::{Hash, BlockNumber, AccountId, Balance, Index}; use runtime_primitives::traits::{Header as HeaderT, Hash as HashT, Convert}; use runtime_primitives::{generic::Era, ApplyOutcome, ApplyError, ApplyResult, Perbill}; use runtime_primitives::weights::{WeightMultiplier, GetDispatchInfo}; - 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, CreationFee, SignedExtra, - TransactionBaseFee, TransactionByteFee, + GrandpaConfig, IndicesConfig, ContractsConfig, Event, SessionKeys, SignedExtra, + TransferFee, TransactionBaseFee, TransactionByteFee, }; use node_runtime::constants::currency::*; use node_runtime::impls::WeightToFee; @@ -90,16 +87,11 @@ mod tests { (extrinsic.encode().len() as Balance); let weight = default_transfer_call().get_dispatch_info().weight; + // NOTE: this is really hard to apply, since the multiplier of each block needs to be fetched + // before the block, while we compute this after the block. + // weight = >::next_weight_multiplier().apply_to(weight); let weight_fee = ::WeightToFee::convert(weight); - // NOTE: we don't need this anymore, but in case needed, this makes the fee accurate over - // multiple blocks. - // weight_fee = >::next_weight_multiplier().apply_to(weight_fee as u32) as Balance; - length_fee + weight_fee - } - - /// Default creation fee. - fn creation_fee() -> Balance { - CreationFee::get() + length_fee + weight_fee + TransferFee::get() } fn alice() -> AccountId { @@ -281,7 +273,7 @@ mod tests { assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt()) - creation_fee()); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -317,7 +309,7 @@ mod tests { assert!(r.is_ok()); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt()) - creation_fee()); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -560,7 +552,7 @@ mod tests { ).0.unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt()) - creation_fee()); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); let events = vec![ EventRecord { @@ -599,13 +591,13 @@ mod tests { // weight update. Hence, using `assert_eq_error_rate`. assert_eq_error_rate!( Balances::total_balance(&alice()), - 32 * DOLLARS - 2 * transfer_fee(&xt()) - 2 * creation_fee(), - 10 + 32 * DOLLARS - 2 * transfer_fee(&xt()), + 10_000 ); assert_eq_error_rate!( Balances::total_balance(&bob()), - 179 * DOLLARS - transfer_fee(&xt()) - creation_fee(), - 10 + 179 * DOLLARS - transfer_fee(&xt()), + 10_000 ); let events = vec![ EventRecord { @@ -661,7 +653,7 @@ mod tests { WasmExecutor::new().call(&mut t, 8, COMPACT_CODE, "Core_execute_block", &block1.0).unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt()) - creation_fee()); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); }); @@ -670,13 +662,13 @@ mod tests { runtime_io::with_externalities(&mut t, || { assert_eq_error_rate!( Balances::total_balance(&alice()), - 32 * DOLLARS - 2 * transfer_fee(&xt()) - 2 * creation_fee(), - 10 + 32 * DOLLARS - 2 * transfer_fee(&xt()), + 10_000 ); assert_eq_error_rate!( Balances::total_balance(&bob()), - 179 * DOLLARS - 1 * transfer_fee(&xt()) - creation_fee(), - 10 + 179 * DOLLARS - 1 * transfer_fee(&xt()), + 10_000 ); }); } @@ -921,7 +913,7 @@ mod tests { assert_eq!(r, Ok(ApplyOutcome::Success)); runtime_io::with_externalities(&mut t, || { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(&xt()) - creation_fee()); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - 1 * transfer_fee(&xt())); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -1056,7 +1048,7 @@ mod tests { fn transaction_fee_is_correct_ultimate() { // This uses the exact values of substrate-node. // - // weight of transfer call as of now: 1_000 + // weight of transfer call as of now: 1_000_000 // if weight of cheapest weight would be 10^7, this would be 10^9, which is: // - 1 MILLICENTS in substrate node. // - 1 milldot based on current polkadot runtime. @@ -1121,9 +1113,7 @@ mod tests { balance_alice -= weight_fee; balance_alice -= tip; - - // TODO: why again??? creation fee should not be deducted here. - balance_alice -= creation_fee(); + balance_alice -= TransferFee::get(); assert_eq!(Balances::total_balance(&alice()), balance_alice); }); diff --git a/node/runtime/src/impls.rs b/node/runtime/src/impls.rs index 0c106e908ccbd..464f1a424b249 100644 --- a/node/runtime/src/impls.rs +++ b/node/runtime/src/impls.rs @@ -58,13 +58,13 @@ impl Convert for CurrencyToVoteHandler { /// - Setting it to `0` will essentially disable the weight fee. /// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. /// -/// By default, substrate node will have a weight range of [0, 1_000_000]. +/// By default, substrate node will have a weight range of [0, 1_000_000_000]. pub struct WeightToFee; impl Convert for WeightToFee { fn convert(x: Weight) -> Balance { - // substrate-node a weight of 10 (smallest non-zero weight) to be mapped to 10^7 units of + // substrate-node a weight of 10_000 (smallest non-zero weight) to be mapped to 10^7 units of // fees, hence: - Balance::from(x).saturating_mul(1_000_000) + Balance::from(x).saturating_mul(1_000) } } diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 266c2384a7472..5024212054272 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -104,7 +104,7 @@ pub type DealWithFees = SplitTwoWays< parameter_types! { pub const BlockHashCount: BlockNumber = 250; - pub const MaximumBlockWeight: Weight = 1_000_000; + pub const MaximumBlockWeight: Weight = 1_000_000_000; pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; } diff --git a/srml/authorship/src/lib.rs b/srml/authorship/src/lib.rs index b496bac460e9a..39a3e8000a463 100644 --- a/srml/authorship/src/lib.rs +++ b/srml/authorship/src/lib.rs @@ -218,7 +218,7 @@ decl_module! { } /// Provide a set of uncles. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn set_uncles(origin, new_uncles: Vec) -> DispatchResult { ensure_none(origin)?; diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 030cb92ed5896..cde3fa2d16cfb 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -435,7 +435,7 @@ decl_module! { /// `T::DustRemoval::on_unbalanced` and `T::OnFreeBalanceZero::on_free_balance_zero`. /// /// # - #[weight = SimpleDispatchInfo::FixedNormal(1_000)] + #[weight = SimpleDispatchInfo::FixedNormal(1_000_000)] pub fn transfer( origin, dest: ::Source, @@ -459,7 +459,7 @@ decl_module! { /// - Independent of the arguments. /// - Contains a limited number of reads and writes. /// # - #[weight = SimpleDispatchInfo::FixedOperational(500)] + #[weight = SimpleDispatchInfo::FixedOperational(500_000)] fn set_balance( origin, who: ::Source, diff --git a/srml/collective/src/lib.rs b/srml/collective/src/lib.rs index 0c9ad8fa78a8b..b05b69db77c83 100644 --- a/srml/collective/src/lib.rs +++ b/srml/collective/src/lib.rs @@ -130,7 +130,7 @@ decl_module! { /// provide it pre-sorted. /// /// Requires root origin. - #[weight = SimpleDispatchInfo::FixedOperational(100)] + #[weight = SimpleDispatchInfo::FixedOperational(100_000)] fn set_members(origin, new_members: Vec) { ensure_root(origin)?; @@ -173,7 +173,7 @@ decl_module! { /// Dispatch a proposal from a member using the `Member` origin. /// /// Origin must be a member of the collective. - #[weight = SimpleDispatchInfo::FixedOperational(1_00)] + #[weight = SimpleDispatchInfo::FixedOperational(100_000)] fn execute(origin, proposal: Box<>::Proposal>) { let who = ensure_signed(origin)?; ensure!(Self::is_member(&who), "proposer not a member"); @@ -187,7 +187,7 @@ decl_module! { /// - Bounded storage reads and writes. /// - Argument `threshold` has bearing on weight. /// # - #[weight = SimpleDispatchInfo::FixedOperational(5_000)] + #[weight = SimpleDispatchInfo::FixedOperational(5_000_000)] fn propose(origin, #[compact] threshold: MemberCount, proposal: Box<>::Proposal>) { let who = ensure_signed(origin)?; ensure!(Self::is_member(&who), "proposer not a member"); @@ -216,7 +216,7 @@ decl_module! { /// - Bounded storage read and writes. /// - Will be slightly heavier if the proposal is approved / disapproved after the vote. /// # - #[weight = SimpleDispatchInfo::FixedOperational(200)] + #[weight = SimpleDispatchInfo::FixedOperational(200_000)] fn vote(origin, proposal: T::Hash, #[compact] index: ProposalIndex, approve: bool) { let who = ensure_signed(origin)?; ensure!(Self::is_member(&who), "voter not a member"); diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index c90e3609c4e8d..1736d8a97e58c 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -360,7 +360,7 @@ decl_module! { /// - O(1). /// - Two DB changes, one DB entry. /// # - #[weight = SimpleDispatchInfo::FixedNormal(5_000)] + #[weight = SimpleDispatchInfo::FixedNormal(5_000_000)] fn propose(origin, proposal: Box, #[compact] value: BalanceOf @@ -388,7 +388,7 @@ decl_module! { /// - O(1). /// - One DB entry. /// # - #[weight = SimpleDispatchInfo::FixedNormal(5_000)] + #[weight = SimpleDispatchInfo::FixedNormal(5_000_000)] fn second(origin, #[compact] proposal: PropIndex) { let who = ensure_signed(origin)?; let mut deposit = Self::deposit_of(proposal) @@ -406,7 +406,7 @@ decl_module! { /// - O(1). /// - One DB change, one DB entry. /// # - #[weight = SimpleDispatchInfo::FixedNormal(200)] + #[weight = SimpleDispatchInfo::FixedNormal(200_000)] fn vote(origin, #[compact] ref_index: ReferendumIndex, vote: Vote @@ -422,7 +422,7 @@ decl_module! { /// - O(1). /// - One DB change, one DB entry. /// # - #[weight = SimpleDispatchInfo::FixedNormal(200)] + #[weight = SimpleDispatchInfo::FixedNormal(200_000)] fn proxy_vote(origin, #[compact] ref_index: ReferendumIndex, vote: Vote @@ -437,7 +437,7 @@ decl_module! { /// exceed `threshold` and, if approved, enacted after the given `delay`. /// /// It may be called from either the Root or the Emergency origin. - #[weight = SimpleDispatchInfo::FixedOperational(500)] + #[weight = SimpleDispatchInfo::FixedOperational(500_000)] fn emergency_propose(origin, proposal: Box, threshold: VoteThreshold, @@ -459,7 +459,7 @@ decl_module! { /// Schedule an emergency cancellation of a referendum. Cannot happen twice to the same /// referendum. - #[weight = SimpleDispatchInfo::FixedOperational(500)] + #[weight = SimpleDispatchInfo::FixedOperational(500_000)] fn emergency_cancel(origin, ref_index: ReferendumIndex) { T::CancellationOrigin::ensure_origin(origin)?; @@ -473,7 +473,7 @@ decl_module! { /// Schedule a referendum to be tabled once it is legal to schedule an external /// referendum. - #[weight = SimpleDispatchInfo::FixedNormal(5_000)] + #[weight = SimpleDispatchInfo::FixedNormal(5_000_000)] fn external_propose(origin, proposal: Box) { T::ExternalOrigin::ensure_origin(origin)?; ensure!(!>::exists(), "proposal already made"); @@ -486,7 +486,7 @@ decl_module! { /// Schedule a majority-carries referendum to be tabled next once it is legal to schedule /// an external referendum. - #[weight = SimpleDispatchInfo::FixedNormal(5_000)] + #[weight = SimpleDispatchInfo::FixedNormal(5_000_000)] fn external_propose_majority(origin, proposal: Box) { T::ExternalMajorityOrigin::ensure_origin(origin)?; ensure!(!>::exists(), "proposal already made"); @@ -505,7 +505,7 @@ decl_module! { /// - `voting_period`: The period that is allowed for voting on this proposal. /// - `delay`: The number of block after voting has ended in approval and this should be /// enacted. Increased to `EmergencyVotingPeriod` if too low. - #[weight = SimpleDispatchInfo::FixedNormal(200)] + #[weight = SimpleDispatchInfo::FixedNormal(200_000)] fn external_push(origin, proposal_hash: T::Hash, voting_period: T::BlockNumber, @@ -524,7 +524,7 @@ decl_module! { } /// Veto and blacklist the external proposal hash. - #[weight = SimpleDispatchInfo::FixedNormal(200)] + #[weight = SimpleDispatchInfo::FixedNormal(200_000)] fn veto_external(origin, proposal_hash: T::Hash) { let who = T::VetoOrigin::ensure_origin(origin)?; @@ -549,14 +549,14 @@ decl_module! { } /// Remove a referendum. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn cancel_referendum(origin, #[compact] ref_index: ReferendumIndex) { ensure_root(origin)?; Self::clear_referendum(ref_index); } /// Cancel a proposal queued for enactment. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn cancel_queued( origin, #[compact] when: T::BlockNumber, @@ -585,7 +585,7 @@ decl_module! { /// # /// - One extra DB entry. /// # - #[weight = SimpleDispatchInfo::FixedNormal(100)] + #[weight = SimpleDispatchInfo::FixedNormal(100_000)] fn set_proxy(origin, proxy: T::AccountId) { let who = ensure_signed(origin)?; ensure!(!>::exists(&proxy), "already a proxy"); @@ -597,7 +597,7 @@ decl_module! { /// # /// - One DB clear. /// # - #[weight = SimpleDispatchInfo::FixedNormal(100)] + #[weight = SimpleDispatchInfo::FixedNormal(100_000)] fn resign_proxy(origin) { let who = ensure_signed(origin)?; >::remove(who); @@ -608,7 +608,7 @@ decl_module! { /// # /// - One DB clear. /// # - #[weight = SimpleDispatchInfo::FixedNormal(100)] + #[weight = SimpleDispatchInfo::FixedNormal(100_000)] fn remove_proxy(origin, proxy: T::AccountId) { let who = ensure_signed(origin)?; ensure!(&Self::proxy(&proxy).ok_or("not a proxy")? == &who, "wrong proxy"); @@ -620,7 +620,7 @@ decl_module! { /// # /// - One extra DB entry. /// # - #[weight = SimpleDispatchInfo::FixedNormal(500)] + #[weight = SimpleDispatchInfo::FixedNormal(500_000)] pub fn delegate(origin, to: T::AccountId, conviction: Conviction) { let who = ensure_signed(origin)?; >::insert(who.clone(), (to.clone(), conviction)); @@ -640,7 +640,7 @@ decl_module! { /// # /// - O(1). /// # - #[weight = SimpleDispatchInfo::FixedNormal(500)] + #[weight = SimpleDispatchInfo::FixedNormal(500_000)] fn undelegate(origin) { let who = ensure_signed(origin)?; ensure!(>::exists(&who), "not delegated"); diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index a01bfacc32af9..8a681fa1458cc 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -332,7 +332,7 @@ decl_module! { /// - Two extra DB entries, one DB change. /// - Argument `votes` is limited in length to number of candidates. /// # - #[weight = SimpleDispatchInfo::FixedNormal(2_500)] + #[weight = SimpleDispatchInfo::FixedNormal(2_500_000)] fn set_approvals(origin, votes: Vec, #[compact] index: VoteIndex, hint: SetIndex) -> Result { let who = ensure_signed(origin)?; Self::do_set_approvals(who, votes, index, hint) @@ -344,7 +344,7 @@ decl_module! { /// # /// - Same as `set_approvals` with one additional storage read. /// # - #[weight = SimpleDispatchInfo::FixedNormal(2_500)] + #[weight = SimpleDispatchInfo::FixedNormal(2_500_000)] fn proxy_set_approvals(origin, votes: Vec, #[compact] index: VoteIndex, @@ -366,7 +366,7 @@ decl_module! { /// - O(1). /// - Two fewer DB entries, one DB change. /// # - #[weight = SimpleDispatchInfo::FixedNormal(2_500)] + #[weight = SimpleDispatchInfo::FixedNormal(2_500_000)] fn reap_inactive_voter( origin, #[compact] reporter_index: u32, @@ -440,7 +440,7 @@ decl_module! { /// - O(1). /// - Two fewer DB entries, one DB change. /// # - #[weight = SimpleDispatchInfo::FixedNormal(1_250)] + #[weight = SimpleDispatchInfo::FixedNormal(1_250_000)] fn retract_voter(origin, #[compact] index: u32) { let who = ensure_signed(origin)?; @@ -468,7 +468,7 @@ decl_module! { /// - Independent of input. /// - Three DB changes. /// # - #[weight = SimpleDispatchInfo::FixedNormal(2_500)] + #[weight = SimpleDispatchInfo::FixedNormal(2_500_000)] fn submit_candidacy(origin, #[compact] slot: u32) { let who = ensure_signed(origin)?; @@ -504,7 +504,7 @@ decl_module! { /// - O(voters) compute. /// - One DB change. /// # - #[weight = SimpleDispatchInfo::FixedNormal(10_000)] + #[weight = SimpleDispatchInfo::FixedNormal(10_000_000)] fn present_winner( origin, candidate: ::Source, @@ -573,7 +573,7 @@ decl_module! { /// Set the desired member count; if lower than the current count, then seats will not be up /// election when they expire. If more, then a new vote will be started if one is not /// already in progress. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn set_desired_seats(origin, #[compact] count: u32) { ensure_root(origin)?; DesiredSeats::put(count); @@ -583,7 +583,7 @@ decl_module! { /// /// Note: A tally should happen instantly (if not already in a presentation /// period) to fill the seat if removal means that the desired members are not met. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn remove_member(origin, who: ::Source) { ensure_root(origin)?; let who = T::Lookup::lookup(who)?; @@ -598,7 +598,7 @@ decl_module! { /// Set the presentation duration. If there is currently a vote being presented for, will /// invoke `finalize_vote`. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn set_presentation_duration(origin, #[compact] count: T::BlockNumber) { ensure_root(origin)?; >::put(count); @@ -606,7 +606,7 @@ decl_module! { /// Set the presentation duration. If there is current a vote being presented for, will /// invoke `finalize_vote`. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn set_term_duration(origin, #[compact] count: T::BlockNumber) { ensure_root(origin)?; >::put(count); diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 3b651a80fb3bf..8589f92006d88 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -379,7 +379,7 @@ decl_module! { /// - O(log n) in number of accounts. /// - One extra DB entry. /// # - #[weight = SimpleDispatchInfo::FixedOperational(150)] // TODO: this is operational? + #[weight = SimpleDispatchInfo::FixedNormal(150_000)] fn set_keys(origin, keys: T::Keys, proof: Vec) -> Result { let who = ensure_signed(origin)?; diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index 80593451400e3..dbf32ca5bd750 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -697,7 +697,7 @@ decl_module! { /// NOTE: Two of the storage writes (`Self::bonded`, `Self::payee`) are _never_ cleaned unless /// the `origin` falls below _existential deposit_ and gets removed as dust. /// # - #[weight = SimpleDispatchInfo::FixedNormal(500)] + #[weight = SimpleDispatchInfo::FixedNormal(500_000)] fn bond(origin, controller: ::Source, #[compact] value: BalanceOf, @@ -745,7 +745,7 @@ decl_module! { /// - O(1). /// - One DB entry. /// # - #[weight = SimpleDispatchInfo::FixedNormal(500)] + #[weight = SimpleDispatchInfo::FixedNormal(500_000)] fn bond_extra(origin, #[compact] max_additional: BalanceOf) { let stash = ensure_signed(origin)?; @@ -785,7 +785,7 @@ decl_module! { /// The only way to clean the aforementioned storage item is also user-controlled via `withdraw_unbonded`. /// - One DB entry. /// - #[weight = SimpleDispatchInfo::FixedNormal(400)] + #[weight = SimpleDispatchInfo::FixedNormal(400_000)] fn unbond(origin, #[compact] value: BalanceOf) { let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -827,7 +827,7 @@ decl_module! { /// - Contains a limited number of reads, yet the size of which could be large based on `ledger`. /// - Writes are limited to the `origin` account key. /// # - #[weight = SimpleDispatchInfo::FixedNormal(400)] + #[weight = SimpleDispatchInfo::FixedNormal(400_000)] fn withdraw_unbonded(origin) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -859,7 +859,7 @@ decl_module! { /// - Contains a limited number of reads. /// - Writes are limited to the `origin` account key. /// # - #[weight = SimpleDispatchInfo::FixedNormal(750)] + #[weight = SimpleDispatchInfo::FixedNormal(750_000)] fn validate(origin, prefs: ValidatorPrefs>) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -883,7 +883,7 @@ decl_module! { /// which is capped at `MAX_NOMINATIONS`. /// - Both the reads and writes follow a similar pattern. /// # - #[weight = SimpleDispatchInfo::FixedNormal(750)] + #[weight = SimpleDispatchInfo::FixedNormal(750_000)] fn nominate(origin, targets: Vec<::Source>) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -909,7 +909,7 @@ decl_module! { /// - Contains one read. /// - Writes are limited to the `origin` account key. /// # - #[weight = SimpleDispatchInfo::FixedNormal(500)] + #[weight = SimpleDispatchInfo::FixedNormal(500_000)] fn chill(origin) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -929,7 +929,7 @@ decl_module! { /// - Contains a limited number of reads. /// - Writes are limited to the `origin` account key. /// # - #[weight = SimpleDispatchInfo::FixedNormal(500)] + #[weight = SimpleDispatchInfo::FixedNormal(500_000)] fn set_payee(origin, payee: RewardDestination) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; @@ -948,7 +948,7 @@ decl_module! { /// - Contains a limited number of reads. /// - Writes are limited to the `origin` account key. /// # - #[weight = SimpleDispatchInfo::FixedNormal(750)] + #[weight = SimpleDispatchInfo::FixedNormal(750_000)] fn set_controller(origin, controller: ::Source) { let stash = ensure_signed(origin)?; let old_controller = Self::bonded(&stash).ok_or("not a stash")?; @@ -965,7 +965,7 @@ decl_module! { } /// The ideal number of validators. - #[weight = SimpleDispatchInfo::FixedOperational(150)] + #[weight = SimpleDispatchInfo::FixedOperational(150_000)] fn set_validator_count(origin, #[compact] new: u32) { ensure_root(origin)?; ValidatorCount::put(new); @@ -981,21 +981,21 @@ decl_module! { /// - Triggers the Phragmen election. Expensive but not user-controlled. /// - Depends on state: `O(|edges| * |validators|)`. /// # - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn force_new_era(origin) { ensure_root(origin)?; Self::apply_force_new_era() } /// Set the offline slash grace period. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn set_offline_slash_grace(origin, #[compact] new: u32) { ensure_root(origin)?; OfflineSlashGrace::put(new); } /// Set the validators who cannot be slashed (if any). - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn set_invulnerables(origin, validators: Vec) { ensure_root(origin)?; >::put(validators); diff --git a/srml/sudo/src/lib.rs b/srml/sudo/src/lib.rs index 2662db7adfd6a..65a15b4abfb03 100644 --- a/srml/sudo/src/lib.rs +++ b/srml/sudo/src/lib.rs @@ -117,7 +117,7 @@ decl_module! { /// - Limited storage reads. /// - No DB writes. /// # - #[weight = SimpleDispatchInfo::FixedOperational(1_000)] + #[weight = SimpleDispatchInfo::FixedOperational(1_000_000)] fn sudo(origin, proposal: Box) { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index e85202e457715..e504726703d32 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -244,7 +244,13 @@ macro_rules! __assert_eq_uvec { #[cfg(feature = "std")] macro_rules! assert_eq_error_rate { ($x:expr, $y:expr, $error:expr) => { - assert!(($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error))); + assert!( + ($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error)), + "{:?} != {:?} (with error rate {:?})", + $x, + $y, + $error, + ); }; } diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 80e37124489e6..e98c53bf1d533 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -233,27 +233,27 @@ decl_module! { } /// Make some on-chain remark. - #[weight = SimpleDispatchInfo::FixedNormal(1_000)] + #[weight = SimpleDispatchInfo::FixedNormal(1_000_000)] fn remark(origin, _remark: Vec) { ensure_signed(origin)?; } /// Set the number of pages in the WebAssembly environment's heap. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn set_heap_pages(origin, pages: u64) { ensure_root(origin)?; storage::unhashed::put_raw(well_known_keys::HEAP_PAGES, &pages.encode()); } /// Set the new code. - #[weight = SimpleDispatchInfo::FixedOperational(200)] + #[weight = SimpleDispatchInfo::FixedOperational(200_000)] pub fn set_code(origin, new: Vec) { ensure_root(origin)?; storage::unhashed::put_raw(well_known_keys::CODE, &new); } /// Set some items of storage. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn set_storage(origin, items: Vec) { ensure_root(origin)?; for i in &items { @@ -262,7 +262,7 @@ decl_module! { } /// Kill some items from storage. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn kill_storage(origin, keys: Vec) { ensure_root(origin)?; for key in &keys { diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index ba3116f4a83ec..030f825dbab87 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -237,7 +237,7 @@ decl_module! { /// `MinimumPeriod`. /// /// The dispatch origin for this call must be `Inherent`. - #[weight = SimpleDispatchInfo::FixedOperational(10)] + #[weight = SimpleDispatchInfo::FixedOperational(10_000)] fn set(origin, #[compact] now: T::Moment) { ensure_none(origin)?; assert!(!::DidUpdate::exists(), "Timestamp must be updated only once in the block"); diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 56a4d12aa3437..f86a8271a24ba 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -154,7 +154,7 @@ decl_module! { /// - Limited storage reads. /// - One DB change, one extra DB entry. /// # - #[weight = SimpleDispatchInfo::FixedNormal(500)] + #[weight = SimpleDispatchInfo::FixedNormal(500_000)] fn propose_spend( origin, #[compact] value: BalanceOf, @@ -181,7 +181,7 @@ decl_module! { /// - Limited storage reads. /// - One DB clear. /// # - #[weight = SimpleDispatchInfo::FixedOperational(100)] + #[weight = SimpleDispatchInfo::FixedOperational(100_000)] fn reject_proposal(origin, #[compact] proposal_id: ProposalIndex) { T::RejectOrigin::ensure_origin(origin)?; let proposal = >::take(proposal_id).ok_or("No proposal at that index")?; @@ -199,7 +199,7 @@ decl_module! { /// - Limited storage reads. /// - One DB change. /// # - #[weight = SimpleDispatchInfo::FixedOperational(100)] + #[weight = SimpleDispatchInfo::FixedOperational(100_000)] fn approve_proposal(origin, #[compact] proposal_id: ProposalIndex) { T::ApproveOrigin::ensure_origin(origin)?; From a25e4be756697e5d47b5953a45e833409a335db6 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 25 Jul 2019 10:57:45 +0200 Subject: [PATCH 32/33] Bump. --- core/sr-primitives/src/weights.rs | 2 +- node/executor/src/lib.rs | 2 +- node/runtime/src/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index 10040fe72b5c0..45ac59e0d5489 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -164,7 +164,7 @@ impl ClassifyDispatch for SimpleDispatchInfo { impl Default for SimpleDispatchInfo { fn default() -> Self { // Default weight of all transactions. - SimpleDispatchInfo::FixedNormal(10) + SimpleDispatchInfo::FixedNormal(10_000) } } diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index b470c7aa7cfd6..9b9352090e066 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -1049,7 +1049,7 @@ mod tests { // This uses the exact values of substrate-node. // // weight of transfer call as of now: 1_000_000 - // if weight of cheapest weight would be 10^7, this would be 10^9, which is: + // if weight of the cheapest weight would be 10^7, this would be 10^9, which is: // - 1 MILLICENTS in substrate node. // - 1 milldot based on current polkadot runtime. // (this baed on assigning 0.1 CENT to the cheapest tx with `weight = 100`) diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 5024212054272..834635a312869 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -79,8 +79,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: 119, - impl_version: 119, + spec_version: 120, + impl_version: 120, apis: RUNTIME_API_VERSIONS, }; From 57247717e9268f3cb2a81a38b01561949d90b213 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 25 Jul 2019 11:16:00 +0200 Subject: [PATCH 33/33] Fix decl_storage test. --- srml/support/src/dispatch.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srml/support/src/dispatch.rs b/srml/support/src/dispatch.rs index f427d5f61ac32..1e0556731e1a2 100644 --- a/srml/support/src/dispatch.rs +++ b/srml/support/src/dispatch.rs @@ -1772,7 +1772,7 @@ mod tests { #[test] fn weight_should_attach_to_call_enum() { - // max weight. not dependent on input. + // operational. assert_eq!( Call::::operational().get_dispatch_info(), DispatchInfo { weight: 5, class: DispatchClass::Operational }, @@ -1780,7 +1780,7 @@ mod tests { // default weight. assert_eq!( Call::::aux_0().get_dispatch_info(), - DispatchInfo { weight: 10, class: DispatchClass::Normal }, + DispatchInfo { weight: 10_000, class: DispatchClass::Normal }, ); // custom basic assert_eq!(