diff --git a/Cargo.lock b/Cargo.lock index 7b7cdd902113b..1ad583f7fa848 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -212,6 +212,11 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitmask" +version = "0.5.0" +source = "git+https://github.com/paritytech/bitmask#c2d8d196e30b018d1385be8357fdca61b978facf" + [[package]] name = "blake2" version = "0.8.0" @@ -3052,6 +3057,7 @@ dependencies = [ "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.87 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", @@ -3343,6 +3349,7 @@ dependencies = [ name = "srml-support" version = "0.1.0" dependencies = [ + "bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)", "hex-literal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3415,7 +3422,6 @@ dependencies = [ "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", - "srml-consensus 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", "substrate-inherents 0.1.0", @@ -4608,7 +4614,7 @@ name = "twox-hash" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4954,6 +4960,7 @@ dependencies = [ "checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" "checksum bindgen 0.43.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d52d263eacd15d26cbcf215d254b410bd58212aaa2d3c453a04b2d3b3adcf41" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)" = "" "checksum blake2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91721a6330935673395a0607df4d49a9cb90ae12d259f1b3e0a3f6e1d486872e" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" diff --git a/core/executor/wasm/Cargo.lock b/core/executor/wasm/Cargo.lock index 27c80a723e879..dc1159e8d0ac2 100644 --- a/core/executor/wasm/Cargo.lock +++ b/core/executor/wasm/Cargo.lock @@ -189,7 +189,6 @@ dependencies = [ "parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "primitive-types 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", "sr-std 0.1.0", ] diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index ad42502ddc936..579264cc9a7b1 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" rstd = { package = "sr-std", path = "../sr-std", default-features = false } parity-codec = { version = "3.1", default-features = false, features = ["derive"] } rustc-hex = { version = "2.0", default-features = false } -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } twox-hash = { version = "1.1.0", optional = true } byteorder = { version = "1.1", default-features = false } @@ -46,7 +46,7 @@ std = [ "hash256-std-hasher/std", "hash-db/std", "rstd/std", - "serde/std", + "serde", "rustc-hex/std", "twox-hash", "blake2-rfc", diff --git a/core/serializer/Cargo.toml b/core/serializer/Cargo.toml index d25c8ce0742d2..8788f776e5a28 100644 --- a/core/serializer/Cargo.toml +++ b/core/serializer/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = "1.0" serde_json = "1.0" diff --git a/core/sr-io/with_std.rs b/core/sr-io/with_std.rs index 562e349ceda79..f7db1825d3713 100644 --- a/core/sr-io/with_std.rs +++ b/core/sr-io/with_std.rs @@ -17,19 +17,29 @@ #[doc(hidden)] pub use parity_codec as codec; // re-export hashing functions. -pub use primitives::{blake2_256, twox_128, twox_256, ed25519, Blake2Hasher, sr25519}; +pub use primitives::{ + blake2_256, twox_128, twox_256, ed25519, Blake2Hasher, sr25519 +}; pub use tiny_keccak::keccak256 as keccak_256; // Switch to this after PoC-3 // pub use primitives::BlakeHasher; -pub use substrate_state_machine::{Externalities, TestExternalities}; +pub use substrate_state_machine::{Externalities, BasicExternalities, TestExternalities}; use environmental::{environmental, thread_local_impl}; -use primitives::hexdisplay::HexDisplay; -use primitives::H256; +use primitives::{hexdisplay::HexDisplay, H256}; use hash_db::Hasher; +#[cfg(feature = "std")] +use std::collections::HashMap; + environmental!(ext: trait Externalities); +/// A set of key value pairs for storage. +pub type StorageOverlay = HashMap, Vec>; + +/// A set of key value pairs for children storage; +pub type ChildrenStorageOverlay = HashMap, StorageOverlay>; + /// Get `key` from storage and return a `Vec`, empty if there's a problem. pub fn storage(key: &[u8]) -> Option> { ext::with(|ext| ext.storage(key).map(|s| s.to_vec())) @@ -196,7 +206,7 @@ pub fn sr25519_verify>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> /// Verify and recover a SECP256k1 ECDSA signature. /// - `sig` is passed in RSV format. V should be either 0/1 or 27/28. -/// - returns `Err` if the signatue is bad, otherwise the 64-byte pubkey (doesn't include the 0x04 prefix). +/// - returns `Err` if the signature is bad, otherwise the 64-byte pubkey (doesn't include the 0x04 prefix). pub fn secp256k1_ecdsa_recover(sig: &[u8; 65], msg: &[u8; 32]) -> Result<[u8; 64], EcdsaVerifyError> { let rs = secp256k1::Signature::parse_slice(&sig[0..64]).map_err(|_| EcdsaVerifyError::BadRS)?; let v = secp256k1::RecoveryId::parse(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8).map_err(|_| EcdsaVerifyError::BadV)?; @@ -213,6 +223,17 @@ pub fn with_externalities R>(ext: &mut Externalities R>(storage: &mut StorageOverlay, f: F) -> R { + let mut alt_storage = Default::default(); + rstd::mem::swap(&mut alt_storage, storage); + let mut ext: BasicExternalities = alt_storage.into(); + let r = ext::using(&mut ext, f); + *storage = ext.into(); + r +} + /// Trait for things which can be printed. pub trait Printable { fn print(self); @@ -248,7 +269,7 @@ mod std_tests { #[test] fn storage_works() { - let mut t = TestExternalities::::default(); + let mut t = BasicExternalities::default(); assert!(with_externalities(&mut t, || { assert_eq!(storage(b"hello"), None); set_storage(b"hello", b"world"); @@ -258,7 +279,7 @@ mod std_tests { true })); - t = TestExternalities::new(map![b"foo".to_vec() => b"bar".to_vec()]); + t = BasicExternalities::new(map![b"foo".to_vec() => b"bar".to_vec()]); assert!(!with_externalities(&mut t, || { assert_eq!(storage(b"hello"), None); @@ -269,7 +290,7 @@ mod std_tests { #[test] fn read_storage_works() { - let mut t = TestExternalities::::new(map![ + let mut t = BasicExternalities::new(map![ b":test".to_vec() => b"\x0b\0\0\0Hello world".to_vec() ]); @@ -285,7 +306,7 @@ mod std_tests { #[test] fn clear_prefix_works() { - let mut t = TestExternalities::::new(map![ + let mut t = BasicExternalities::new(map![ b":a".to_vec() => b"\x0b\0\0\0Hello world".to_vec(), b":abcd".to_vec() => b"\x0b\0\0\0Hello world".to_vec(), b":abc".to_vec() => b"\x0b\0\0\0Hello world".to_vec(), diff --git a/core/sr-primitives/Cargo.toml b/core/sr-primitives/Cargo.toml index 2a971c39416b1..4ef85b49897a0 100644 --- a/core/sr-primitives/Cargo.toml +++ b/core/sr-primitives/Cargo.toml @@ -13,7 +13,7 @@ parity-codec = { version = "3.1", default-features = false, features = ["derive" substrate-primitives = { path = "../primitives", default-features = false } rstd = { package = "sr-std", path = "../sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../sr-io", default-features = false } -log = {version = "0.4", optional = true } +log = { version = "0.4", optional = true } [dev-dependencies] serde_json = "1.0" diff --git a/core/sr-primitives/src/lib.rs b/core/sr-primitives/src/lib.rs index 7a5739d8f122e..b2491c57a165e 100644 --- a/core/sr-primitives/src/lib.rs +++ b/core/sr-primitives/src/lib.rs @@ -27,7 +27,7 @@ pub use parity_codec as codec; pub use serde_derive; #[cfg(feature = "std")] -use std::collections::HashMap; +pub use runtime_io::{StorageOverlay, ChildrenStorageOverlay}; use rstd::prelude::*; use substrate_primitives::hash::{H256, H512}; @@ -87,17 +87,9 @@ pub use serde::{Serialize, de::DeserializeOwned}; #[cfg(feature = "std")] use serde_derive::{Serialize, Deserialize}; -/// A set of key value pairs for storage. -#[cfg(feature = "std")] -pub type StorageOverlay = HashMap, Vec>; - -/// A set of key value pairs for children storage; -#[cfg(feature = "std")] -pub type ChildrenStorageOverlay = HashMap, StorageOverlay>; - /// Complex storage builder stuff. #[cfg(feature = "std")] -pub trait BuildStorage { +pub trait BuildStorage: Sized { /// Hash given slice. /// /// Default to xx128 hashing. @@ -107,7 +99,21 @@ pub trait BuildStorage { r } /// Build the storage out of this builder. - fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String>; + fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> { + let mut storage = Default::default(); + let mut child_storage = Default::default(); + self.assimilate_storage(&mut storage, &mut child_storage)?; + Ok((storage, child_storage)) + } + /// Assimilate the storage for this module into pre-existing overlays. + fn assimilate_storage(self, storage: &mut StorageOverlay, child_storage: &mut ChildrenStorageOverlay) -> Result<(), String> { + let (s, cs) = self.build_storage()?; + storage.extend(s); + for (other_child_key, other_child_map) in cs { + child_storage.entry(other_child_key).or_default().extend(other_child_map); + } + Ok(()) + } } #[cfg(feature = "std")] @@ -115,6 +121,10 @@ impl BuildStorage for StorageOverlay { fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> { Ok((self, Default::default())) } + fn assimilate_storage(self, storage: &mut StorageOverlay, _child_storage: &mut ChildrenStorageOverlay) -> Result<(), String> { + storage.extend(self); + Ok(()) + } } /// Permill is parts-per-million (i.e. after multiplying by this, divide by 1000000). @@ -411,6 +421,14 @@ macro_rules! impl_outer_config { } #[cfg(any(feature = "std", test))] impl $crate::BuildStorage for $main { + fn assimilate_storage(self, top: &mut $crate::StorageOverlay, children: &mut $crate::ChildrenStorageOverlay) -> ::std::result::Result<(), String> { + $( + if let Some(extra) = self.$snake { + extra.assimilate_storage(top, children)?; + } + )* + Ok(()) + } fn build_storage(self) -> ::std::result::Result<($crate::StorageOverlay, $crate::ChildrenStorageOverlay), String> { let mut top = $crate::StorageOverlay::new(); let mut children = $crate::ChildrenStorageOverlay::new(); diff --git a/core/sr-primitives/src/traits.rs b/core/sr-primitives/src/traits.rs index 8050451b382cd..4ff1ad3115ada 100644 --- a/core/sr-primitives/src/traits.rs +++ b/core/sr-primitives/src/traits.rs @@ -23,8 +23,7 @@ use runtime_io; #[cfg(feature = "std")] use serde::{Serialize, de::DeserializeOwned}; #[cfg(feature = "std")] use serde_derive::{Serialize, Deserialize}; -use substrate_primitives; -use substrate_primitives::Blake2Hasher; +use substrate_primitives::{self, Hasher, Blake2Hasher}; use crate::codec::{Codec, Encode, HasCompact}; pub use integer_sqrt::IntegerSquareRoot; pub use num_traits::{ @@ -84,6 +83,8 @@ pub trait StaticLookup { type Target; /// Attempt a lookup. fn lookup(s: Self::Source) -> result::Result; + /// Convert from Target back to Source. + fn unlookup(t: Self::Target) -> Self::Source; } /// A lookup implementation returning the input value. @@ -93,6 +94,7 @@ impl StaticLookup for IdentityLookup< type Source = T; type Target = T; fn lookup(x: T) -> result::Result { Ok(x) } + fn unlookup(x: T) -> T { x } } impl Lookup for IdentityLookup { type Source = T; @@ -184,7 +186,7 @@ pub trait SimpleArithmetic: CheckedMul + CheckedDiv + Saturating + - PartialOrd + Ord + + PartialOrd + Ord + Bounded + HasCompact {} impl + Ord + + PartialOrd + Ord + Bounded + HasCompact > SimpleArithmetic for T {} @@ -298,7 +300,10 @@ tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, pub trait Hash: 'static + MaybeSerializeDebug + Clone + Eq + PartialEq { // Stupid bug in the Rust compiler believes derived // traits must be fulfilled by all type parameters. /// The hash type produced. - type Output: Member + MaybeSerializeDebug + AsRef<[u8]> + AsMut<[u8]>; + type Output: Member + MaybeSerializeDebug + rstd::hash::Hash + AsRef<[u8]> + AsMut<[u8]> + Copy + Default; + + /// The associated hash_db Hasher type. + type Hasher: Hasher; /// Produce the hash of some byte-slice. fn hash(s: &[u8]) -> Self::Output; @@ -338,6 +343,7 @@ pub struct BlakeTwo256; impl Hash for BlakeTwo256 { type Output = substrate_primitives::H256; + type Hasher = Blake2Hasher; fn hash(s: &[u8]) -> Self::Output { runtime_io::blake2_256(s).into() } @@ -480,6 +486,7 @@ pub trait MaybeHash {} #[cfg(not(feature = "std"))] impl MaybeHash for T {} + /// A type that can be used in runtime structures. pub trait Member: Send + Sync + Sized + MaybeDebug + Eq + PartialEq + Clone + 'static {} impl Member for T {} diff --git a/core/sr-version/Cargo.toml b/core/sr-version/Cargo.toml index 3ad1ac299e58d..5a1e6162f1e7c 100644 --- a/core/sr-version/Cargo.toml +++ b/core/sr-version/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] impl-serde = { version = "0.1", optional = true } -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../sr-std", default-features = false } @@ -16,7 +16,7 @@ runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", def default = ["std"] std = [ "impl-serde", - "serde/std", + "serde", "serde_derive", "parity-codec/std", "rstd/std", diff --git a/core/state-machine/src/basic.rs b/core/state-machine/src/basic.rs new file mode 100644 index 0000000000000..cb9f5d33d059b --- /dev/null +++ b/core/state-machine/src/basic.rs @@ -0,0 +1,183 @@ +// Copyright 2017-2018 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 . + +//! Basic implementation for Externalities. + +use std::collections::HashMap; +use std::iter::FromIterator; +use hash_db::Hasher; +use heapsize::HeapSizeOf; +use trie::trie_root; +use primitives::storage::well_known_keys::{CHANGES_TRIE_CONFIG, CODE, HEAP_PAGES}; +use parity_codec::Encode; +use super::{Externalities, OverlayedChanges}; + +/// Simple HashMap-based Externalities impl. +pub struct BasicExternalities { + inner: HashMap, Vec>, + changes: OverlayedChanges, + code: Option>, +} + +impl BasicExternalities { + /// Create a new instance of `BasicExternalities` + pub fn new(inner: HashMap, Vec>) -> Self { + Self::new_with_code(&[], inner) + } + + /// Create a new instance of `BasicExternalities` + pub fn new_with_code(code: &[u8], mut inner: HashMap, Vec>) -> Self { + let mut overlay = OverlayedChanges::default(); + super::set_changes_trie_config( + &mut overlay, + inner.get(&CHANGES_TRIE_CONFIG.to_vec()).cloned(), + false, + ).expect("changes trie configuration is correct in test env; qed"); + + inner.insert(HEAP_PAGES.to_vec(), 8u64.encode()); + + BasicExternalities { + inner, + changes: overlay, + code: Some(code.to_vec()), + } + } + + /// Insert key/value + pub fn insert(&mut self, k: Vec, v: Vec) -> Option> { + self.inner.insert(k, v) + } +} + +impl ::std::fmt::Debug for BasicExternalities { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{:?}", self.inner) + } +} + +impl PartialEq for BasicExternalities { + fn eq(&self, other: &BasicExternalities) -> bool { + self.inner.eq(&other.inner) + } +} + +impl FromIterator<(Vec, Vec)> for BasicExternalities { + fn from_iter, Vec)>>(iter: I) -> Self { + let mut t = Self::new(Default::default()); + t.inner.extend(iter); + t + } +} + +impl Default for BasicExternalities { + fn default() -> Self { Self::new(Default::default()) } +} + +impl From for HashMap, Vec> { + fn from(tex: BasicExternalities) -> Self { + tex.inner.into() + } +} + +impl From< HashMap, Vec> > for BasicExternalities { + fn from(hashmap: HashMap, Vec>) -> Self { + BasicExternalities { + inner: hashmap, + changes: Default::default(), + code: None, + } + } +} + +impl Externalities for BasicExternalities where H::Out: Ord + HeapSizeOf { + fn storage(&self, key: &[u8]) -> Option> { + match key { + CODE => self.code.clone(), + _ => self.inner.get(key).cloned(), + } + } + + fn child_storage(&self, _storage_key: &[u8], _key: &[u8]) -> Option> { + None + } + + fn place_storage(&mut self, key: Vec, maybe_value: Option>) { + self.changes.set_storage(key.clone(), maybe_value.clone()); + match key.as_ref() { + CODE => self.code = maybe_value, + _ => { + match maybe_value { + Some(value) => { self.inner.insert(key, value); } + None => { self.inner.remove(&key); } + } + } + } + } + + fn place_child_storage(&mut self, _storage_key: Vec, _key: Vec, _value: Option>) -> bool { + false + } + + fn kill_child_storage(&mut self, _storage_key: &[u8]) { } + + fn clear_prefix(&mut self, prefix: &[u8]) { + self.changes.clear_prefix(prefix); + self.inner.retain(|key, _| !key.starts_with(prefix)); + } + + fn chain_id(&self) -> u64 { 42 } + + fn storage_root(&mut self) -> H::Out { + trie_root::(self.inner.clone()) + } + + fn child_storage_root(&mut self, _storage_key: &[u8]) -> Option> { + None + } + + fn storage_changes_root(&mut self, _parent: H::Out, _parent_num: u64) -> Option { + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + use primitives::{Blake2Hasher, H256}; + use hex_literal::{hex, hex_impl}; + + #[test] + fn commit_should_work() { + let mut ext = BasicExternalities::default(); + let ext = &mut ext as &mut Externalities; + ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); + ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); + ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec()); + const ROOT: [u8; 32] = hex!("0b33ed94e74e0f8e92a55923bece1ed02d16cf424e124613ddebc53ac3eeeabe"); + assert_eq!(ext.storage_root(), H256::from(ROOT)); + } + + #[test] + fn set_and_retrieve_code() { + let mut ext = BasicExternalities::default(); + let ext = &mut ext as &mut Externalities; + + let code = vec![1, 2, 3]; + ext.set_storage(CODE.to_vec(), code.clone()); + + assert_eq!(&ext.storage(CODE).unwrap(), &code); + } +} diff --git a/core/state-machine/src/lib.rs b/core/state-machine/src/lib.rs index 3b9e482e8211f..6ba376d0461c3 100644 --- a/core/state-machine/src/lib.rs +++ b/core/state-machine/src/lib.rs @@ -29,6 +29,7 @@ pub mod backend; mod changes_trie; mod ext; mod testing; +mod basic; mod overlayed_changes; mod proving_backend; mod trie_backend; @@ -37,6 +38,7 @@ mod trie_backend_essence; use overlayed_changes::OverlayedChangeSet; pub use trie::{TrieMut, TrieDBMut, DBValue, MemoryDB}; pub use testing::TestExternalities; +pub use basic::BasicExternalities; pub use ext::Ext; pub use backend::Backend; pub use changes_trie::{ @@ -625,7 +627,7 @@ where /// differs from previous OR config decode has failed. pub(crate) fn set_changes_trie_config(overlay: &mut OverlayedChanges, config: Option>, final_check: bool) -> Result<(), Box> { let config = match config { - Some(v) => Some(changes_trie::Configuration::decode(&mut &v[..]) + Some(v) => Some(Decode::decode(&mut &v[..]) .ok_or_else(|| Box::new("Failed to decode changes trie configuration".to_owned()) as Box)?), None => None, }; diff --git a/core/test-runtime/wasm/Cargo.lock b/core/test-runtime/wasm/Cargo.lock index 1dae80fcbadf9..ff712a4aef09c 100644 --- a/core/test-runtime/wasm/Cargo.lock +++ b/core/test-runtime/wasm/Cargo.lock @@ -44,6 +44,11 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitmask" +version = "0.5.0" +source = "git+https://github.com/paritytech/bitmask#c2d8d196e30b018d1385be8357fdca61b978facf" + [[package]] name = "blake2-rfc" version = "0.2.18" @@ -1221,6 +1226,7 @@ dependencies = [ name = "srml-support" version = "0.1.0" dependencies = [ + "bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1863,6 +1869,7 @@ dependencies = [ "checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)" = "" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" diff --git a/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 13b55df5d1434..15ed8aabd2faf 100644 Binary files a/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/core/trie/src/node_header.rs b/core/trie/src/node_header.rs index 99b1241cab452..6324a6e3533b9 100644 --- a/core/trie/src/node_header.rs +++ b/core/trie/src/node_header.rs @@ -72,7 +72,6 @@ impl Decode for NodeHeader { BRANCH_NODE_NO_VALUE => NodeHeader::Branch(false), // 254 BRANCH_NODE_WITH_VALUE => NodeHeader::Branch(true), // 255 - _ => unreachable!(), }) } } diff --git a/node-template/runtime/Cargo.toml b/node-template/runtime/Cargo.toml index 986b12ce94929..066e9da79dc7a 100644 --- a/node-template/runtime/Cargo.toml +++ b/node-template/runtime/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false } parity-codec = { version = "3.1", default-features = false, features = ["derive"] } @@ -47,7 +47,7 @@ std = [ "sudo/std", "version/std", "serde_derive", - "serde/std", + "serde", "safe-mix/std", "consensus-aura/std", ] diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index 9caef856fd083..fd696e9500a85 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -158,8 +158,6 @@ impl balances::Trait for Runtime { type OnFreeBalanceZero = (); /// What to do if a new account is created. type OnNewAccount = Indices; - /// Restrict whether an account can transfer funds. We don't place any further restrictions. - type EnsureAccountLiquid = (); /// The uniquitous event type. type Event = Event; } diff --git a/node-template/runtime/wasm/Cargo.lock b/node-template/runtime/wasm/Cargo.lock index f1b317903e093..421d9cdcad32d 100644 --- a/node-template/runtime/wasm/Cargo.lock +++ b/node-template/runtime/wasm/Cargo.lock @@ -50,6 +50,11 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitmask" +version = "0.5.0" +source = "git+https://github.com/paritytech/bitmask#c2d8d196e30b018d1385be8357fdca61b978facf" + [[package]] name = "blake2-rfc" version = "0.2.18" @@ -1276,6 +1281,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", @@ -1401,6 +1407,7 @@ dependencies = [ "parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-consensus 0.1.0", @@ -1429,6 +1436,7 @@ dependencies = [ name = "srml-support" version = "0.1.0" dependencies = [ + "bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1499,7 +1507,6 @@ dependencies = [ "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", - "srml-consensus 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", "substrate-inherents 0.1.0", @@ -2079,6 +2086,7 @@ dependencies = [ "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)" = "" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 5b100c3a93962..8b67e98834b4c 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -318,9 +318,9 @@ mod tests { sudo: Some(Default::default()), grandpa: Some(GrandpaConfig { authorities: vec![ // set these so no GRANDPA events fire when session changes - (keyring::ed25519::Keyring::Alice.to_raw_public().into(), 1), - (keyring::ed25519::Keyring::Bob.to_raw_public().into(), 1), (keyring::ed25519::Keyring::Charlie.to_raw_public().into(), 1), + (keyring::ed25519::Keyring::Bob.to_raw_public().into(), 1), + (keyring::ed25519::Keyring::Alice.to_raw_public().into(), 1), ], }), fees: Some(FeesConfig { @@ -449,9 +449,9 @@ mod tests { let mut digest = generic::Digest::::default(); digest.push(Log::from(::grandpa::RawLog::AuthoritiesChangeSignal(0, vec![ - (Keyring::One.to_raw_public().into(), 1), - (Keyring::Two.to_raw_public().into(), 1), - ([3u8; 32].into(), 1), + (Keyring::Charlie.to_raw_public().into(), 1), + (Keyring::Alice.to_raw_public().into(), 1), + (Keyring::Bob.to_raw_public().into(), 1), ]))); assert_eq!(Header::decode(&mut &block2.0[..]).unwrap().digest, digest); @@ -592,9 +592,9 @@ mod tests { EventRecord { phase: Phase::Finalization, event: Event::grandpa(::grandpa::RawEvent::NewAuthorities(vec![ - (Keyring::One.to_raw_public().into(), 1), - (Keyring::Two.to_raw_public().into(), 1), - ([3u8; 32].into(), 1), + (Keyring::Charlie.to_raw_public().into(), 1), + (Keyring::Alice.to_raw_public().into(), 1), + (Keyring::Bob.to_raw_public().into(), 1), ])), }, EventRecord { diff --git a/node/primitives/Cargo.toml b/node/primitives/Cargo.toml index bdb1fd64cd411..724eb7d0abe46 100644 --- a/node/primitives/Cargo.toml +++ b/node/primitives/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false } parity-codec-derive = { version = "3.1", default-features = false } @@ -26,5 +26,5 @@ std = [ "rstd/std", "runtime_primitives/std", "serde_derive", - "serde/std", + "serde", ] diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index d009a544d5946..0c695f5ef1952 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -65,7 +65,7 @@ std = [ "fees/std", "version/std", "node-primitives/std", - "serde/std", + "serde", "safe-mix/std", "client/std", "consensus_aura/std", diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index d9089f6b0ad5b..16ace6f2807c2 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -60,8 +60,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node"), impl_name: create_runtime_str!("substrate-node"), authoring_version: 10, - spec_version: 33, - impl_version: 33, + spec_version: 34, + impl_version: 34, apis: RUNTIME_API_VERSIONS, }; @@ -101,9 +101,8 @@ impl indices::Trait for Runtime { impl balances::Trait for Runtime { type Balance = Balance; - type OnFreeBalanceZero = (((Staking, Contract), Democracy), Session); + type OnFreeBalanceZero = ((Staking, Contract), Session); type OnNewAccount = Indices; - type EnsureAccountLiquid = (Staking, Democracy); type Event = Event; } @@ -116,7 +115,7 @@ impl consensus::Trait for Runtime { type Log = Log; type SessionKey = SessionKey; - // the aura module handles offline-reports internally + // The Aura module handles offline-reports internally // rather than using an explicit report system. type InherentOfflineReport = (); } diff --git a/node/runtime/wasm/Cargo.lock b/node/runtime/wasm/Cargo.lock index 5bb473efb1840..0d6c80edeab42 100644 --- a/node/runtime/wasm/Cargo.lock +++ b/node/runtime/wasm/Cargo.lock @@ -44,6 +44,11 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitmask" +version = "0.5.0" +source = "git+https://github.com/paritytech/bitmask#c2d8d196e30b018d1385be8357fdca61b978facf" + [[package]] name = "blake2-rfc" version = "0.2.18" @@ -1300,7 +1305,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-session 0.1.0", @@ -1513,6 +1518,7 @@ dependencies = [ "parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 0.1.0", "sr-primitives 0.1.0", "sr-std 0.1.0", "srml-consensus 0.1.0", @@ -1541,6 +1547,7 @@ dependencies = [ name = "srml-support" version = "0.1.0" dependencies = [ + "bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1611,7 +1618,6 @@ dependencies = [ "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", "sr-std 0.1.0", - "srml-consensus 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", "substrate-inherents 0.1.0", @@ -2224,6 +2230,7 @@ dependencies = [ "checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum bitmask 0.5.0 (git+https://github.com/paritytech/bitmask)" = "" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1339a1042f5d9f295737ad4d9a6ab6bf81c84a933dba110b9200cd6d1448b814" "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" diff --git a/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index 7c6e43a51622b..da9604c4eba33 100644 Binary files a/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm and b/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm differ diff --git a/srml/assets/Cargo.toml b/srml/assets/Cargo.toml index 7dfc8fd04d02a..621d4a1ac461e 100644 --- a/srml/assets/Cargo.toml +++ b/srml/assets/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false } # Needed for various traits. In our case, `OnFinalise`. primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } @@ -23,7 +23,7 @@ runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] default = ["std"] std = [ - "serde/std", + "serde", "parity-codec/std", "primitives/std", "srml-support/std", diff --git a/srml/aura/Cargo.toml b/srml/aura/Cargo.toml index 49c371cd45446..bb8af29e8d11b 100644 --- a/srml/aura/Cargo.toml +++ b/srml/aura/Cargo.toml @@ -7,7 +7,8 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" parity-codec = { version = "3.1", default-features = false, features = ["derive"] } -serde = { version = "1.0", default-features = false } +parity-codec-derive = { version = "3.1", default-features = false } +serde = { version = "1.0", optional = true } inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } @@ -27,7 +28,7 @@ consensus = { package = "srml-consensus", path = "../consensus" } [features] default = ["std"] std = [ - "serde/std", + "serde", "parity-codec/std", "rstd/std", "srml-support/std", diff --git a/srml/balances/Cargo.toml b/srml/balances/Cargo.toml index 1cb75c94ed109..c8d5d152a3e76 100644 --- a/srml/balances/Cargo.toml +++ b/srml/balances/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} parity-codec = { version = "3.1", default-features = false, features = ["derive"] } substrate-keyring = { path = "../../core/keyring", optional = true } @@ -22,7 +22,7 @@ substrate-primitives = { path = "../../core/primitives" } [features] default = ["std"] std = [ - "serde/std", + "serde", "safe-mix/std", "substrate-keyring", "parity-codec/std", diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index f5168240a7b3e..2fe797de2dec3 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -29,7 +29,8 @@ use rstd::{cmp, result}; use parity_codec::{Codec, Encode, Decode}; use srml_support::{StorageValue, StorageMap, Parameter, decl_event, decl_storage, decl_module, ensure}; use srml_support::traits::{ - UpdateBalanceOutcome, Currency, EnsureAccountLiquid, OnFreeBalanceZero, TransferAsset, WithdrawReason, ArithmeticType + UpdateBalanceOutcome, Currency, OnFreeBalanceZero, TransferAsset, + WithdrawReason, WithdrawReasons, ArithmeticType, LockIdentifier, LockableCurrency }; use srml_support::dispatch::Result; use primitives::traits::{ @@ -53,9 +54,6 @@ pub trait Trait: system::Trait { /// Handler for when a new account is created. type OnNewAccount: OnNewAccount; - /// A function that returns true iff a given account can transfer its funds to another account. - type EnsureAccountLiquid: EnsureAccountLiquid; - /// The overarching event type. type Event: From> + Into<::Event>; } @@ -99,6 +97,15 @@ impl> VestingSchedule { } } +#[derive(Encode, Decode, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct BalanceLock { + pub id: LockIdentifier, + pub amount: Balance, + pub until: BlockNumber, + pub reasons: WithdrawReasons, +} + decl_storage! { trait Store for Module as Balances { /// The total amount of stake on the system. @@ -160,6 +167,9 @@ decl_storage! { /// `system::AccountNonce` is also deleted if `FreeBalance` is also zero (it also gets /// collapsed to zero if it ever becomes less than `ExistentialDeposit`. pub ReservedBalance get(reserved_balance): map T::AccountId => T::Balance; + + /// Any liquidity locks on some account balances. + pub Locks get(locks): map T::AccountId => Vec>; } add_extra_genesis { config(balances): Vec<(T::AccountId, T::Balance)>; @@ -285,16 +295,14 @@ impl Module { None => return Err("got overflow after adding a fee to value"), }; - let vesting_balance = Self::vesting_balance(transactor); let new_from_balance = match from_balance.checked_sub(&liability) { None => return Err("balance too low to send value"), - Some(b) if b < vesting_balance => return Err("vesting balance too high to send value"), Some(b) => b, }; if would_create && value < Self::existential_deposit() { return Err("value too low to create account"); } - T::EnsureAccountLiquid::ensure_account_can_withdraw(transactor, value, WithdrawReason::Transfer)?; + Self::ensure_account_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?; // NOTE: total stake being stored in the same type means that this could never overflow // but better to be safe than sorry. @@ -313,7 +321,6 @@ impl Module { Ok(()) } - /// Register a new account (with existential balance). fn new_account(who: &T::AccountId, balance: T::Balance) { T::OnNewAccount::on_new_account(&who); @@ -329,6 +336,7 @@ impl Module { fn on_free_too_low(who: &T::AccountId) { Self::decrease_total_stake_by(Self::free_balance(who)); >::remove(who); + >::remove(who); T::OnFreeBalanceZero::on_free_balance_zero(who); @@ -359,6 +367,35 @@ impl Module { >::put(v); } } + + /// Returns `Ok` iff the account is able to make a withdrawal of the given amount + /// for the given reason. + /// + /// `Err(...)` with the reason why not otherwise. + pub fn ensure_account_can_withdraw( + who: &T::AccountId, + _amount: T::Balance, + reason: WithdrawReason, + new_balance: T::Balance, + ) -> Result { + match reason { + WithdrawReason::Reserve | WithdrawReason::Transfer if Self::vesting_balance(who) > new_balance => + return Err("vesting balance too high to send value"), + _ => {} + } + let locks = Self::locks(who); + if locks.is_empty() { + return Ok(()) + } + let now = >::block_number(); + if Self::locks(who).into_iter() + .all(|l| now >= l.until || new_balance >= l.amount || !l.reasons.contains(reason)) + { + Ok(()) + } else { + Err("account liquidity restrictions prevent withdrawal") + } + } } impl Currency for Module @@ -376,11 +413,11 @@ where } fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { - if T::EnsureAccountLiquid::ensure_account_can_withdraw(who, value, WithdrawReason::Reserve).is_ok() { - Self::free_balance(who) >= value - } else { - false - } + Self::free_balance(who) + .checked_sub(&value) + .map_or(false, |new_balance| + Self::ensure_account_can_withdraw(who, value, WithdrawReason::Reserve, new_balance).is_ok() + ) } fn total_issuance() -> Self::Balance { @@ -429,9 +466,10 @@ where if b < value { return Err("not enough free funds") } - T::EnsureAccountLiquid::ensure_account_can_withdraw(who, value, WithdrawReason::Reserve)?; + let new_balance = b - value; + Self::ensure_account_can_withdraw(who, value, WithdrawReason::Reserve, new_balance)?; Self::set_reserved_balance(who, Self::reserved_balance(who) + value); - Self::set_free_balance(who, b - value); + Self::set_free_balance(who, new_balance); Ok(()) } @@ -479,6 +517,80 @@ where } } +impl LockableCurrency for Module +where + T::Balance: MaybeSerializeDebug +{ + type Moment = T::BlockNumber; + + fn set_lock( + id: LockIdentifier, + who: &T::AccountId, + amount: T::Balance, + until: T::BlockNumber, + reasons: WithdrawReasons, + ) { + let now = >::block_number(); + let mut new_lock = Some(BalanceLock { id, amount, until, reasons }); + let mut locks = Self::locks(who).into_iter().filter_map(|l| + if l.id == id { + new_lock.take() + } else if l.until > now { + Some(l) + } else { + None + }).collect::>(); + if let Some(lock) = new_lock { + locks.push(lock) + } + >::insert(who, locks); + } + + fn extend_lock( + id: LockIdentifier, + who: &T::AccountId, + amount: T::Balance, + until: T::BlockNumber, + reasons: WithdrawReasons, + ) { + let now = >::block_number(); + let mut new_lock = Some(BalanceLock { id, amount, until, reasons }); + let mut locks = Self::locks(who).into_iter().filter_map(|l| + if l.id == id { + new_lock.take().map(|nl| { + BalanceLock { + id: l.id, + amount: l.amount.max(nl.amount), + until: l.until.max(nl.until), + reasons: l.reasons | nl.reasons, + } + }) + } else if l.until > now { + Some(l) + } else { + None + }).collect::>(); + if let Some(lock) = new_lock { + locks.push(lock) + } + >::insert(who, locks); + } + + fn remove_lock( + id: LockIdentifier, + who: &T::AccountId, + ) { + let now = >::block_number(); + let locks = Self::locks(who).into_iter().filter_map(|l| + if l.until > now && l.id != id { + Some(l) + } else { + None + }).collect::>(); + >::insert(who, locks); + } +} + impl TransferAsset for Module { type Amount = T::Balance; @@ -487,10 +599,11 @@ impl TransferAsset for Module { } fn withdraw(who: &T::AccountId, value: T::Balance, reason: WithdrawReason) -> Result { - T::EnsureAccountLiquid::ensure_account_can_withdraw(who, value, reason)?; let b = Self::free_balance(who); ensure!(b >= value, "account has too few funds"); - Self::set_free_balance(who, b - value); + let new_balance = b - value; + Self::ensure_account_can_withdraw(who, value, reason, new_balance)?; + Self::set_free_balance(who, new_balance); Self::decrease_total_stake_by(value); Ok(()) } diff --git a/srml/balances/src/mock.rs b/srml/balances/src/mock.rs index 6dcff18c6eb49..85ae7a131e1c1 100644 --- a/srml/balances/src/mock.rs +++ b/srml/balances/src/mock.rs @@ -49,7 +49,6 @@ impl Trait for Runtime { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = (); } diff --git a/srml/balances/src/tests.rs b/srml/balances/src/tests.rs index 272e4f5f10d36..1aa76a62c7ef2 100644 --- a/srml/balances/src/tests.rs +++ b/srml/balances/src/tests.rs @@ -21,7 +21,136 @@ use super::*; use mock::{Balances, ExtBuilder, Runtime, System}; use runtime_io::with_externalities; -use srml_support::{assert_noop, assert_ok, assert_err}; +use srml_support::{ + assert_noop, assert_ok, assert_err, + traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons, Currency, TransferAsset} +}; + +const ID_1: LockIdentifier = *b"1 "; +const ID_2: LockIdentifier = *b"2 "; +const ID_3: LockIdentifier = *b"3 "; + +#[test] +fn basic_locking_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + assert_eq!(Balances::free_balance(&1), 10); + Balances::set_lock(ID_1, &1, 9, u64::max_value(), WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 5), "account liquidity restrictions prevent withdrawal"); + }); +} + +#[test] +fn partial_locking_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn lock_removal_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all()); + Balances::remove_lock(ID_1, &1); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn lock_replacement_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + Balances::set_lock(ID_1, &1, u64::max_value(), u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn double_locking_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + Balances::set_lock(ID_2, &1, 5, u64::max_value(), WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn combination_locking_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + Balances::set_lock(ID_1, &1, u64::max_value(), 0, WithdrawReasons::none()); + Balances::set_lock(ID_2, &1, 0, u64::max_value(), WithdrawReasons::none()); + Balances::set_lock(ID_3, &1, 0, 0, WithdrawReasons::all()); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn lock_value_extension_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + Balances::set_lock(ID_1, &1, 5, u64::max_value(), WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + Balances::extend_lock(ID_1, &1, 2, u64::max_value(), WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + Balances::extend_lock(ID_1, &1, 8, u64::max_value(), WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 3), "account liquidity restrictions prevent withdrawal"); + }); +} + +#[test] +fn lock_reasons_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into()); + assert_noop!(>::transfer(&1, &2, 1), "account liquidity restrictions prevent withdrawal"); + assert_ok!(>::reserve(&1, 1)); + assert_ok!(>::withdraw(&1, 1, WithdrawReason::TransactionPayment)); + + Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Reserve.into()); + assert_ok!(>::transfer(&1, &2, 1)); + assert_noop!(>::reserve(&1, 1), "account liquidity restrictions prevent withdrawal"); + assert_ok!(>::withdraw(&1, 1, WithdrawReason::TransactionPayment)); + + 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!(>::withdraw(&1, 1, WithdrawReason::TransactionPayment), "account liquidity restrictions prevent withdrawal"); + }); +} + +#[test] +fn lock_block_number_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 1), "account liquidity restrictions prevent withdrawal"); + + System::set_block_number(2); + assert_ok!(>::transfer(&1, &2, 1)); + }); +} + +#[test] +fn lock_block_number_extension_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + Balances::set_lock(ID_1, &1, 10, 2, WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + Balances::extend_lock(ID_1, &1, 10, 1, WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + System::set_block_number(2); + Balances::extend_lock(ID_1, &1, 10, 8, WithdrawReasons::all()); + assert_noop!(>::transfer(&1, &2, 3), "account liquidity restrictions prevent withdrawal"); + }); +} + +#[test] +fn lock_reasons_extension_should_work() { + with_externalities(&mut ExtBuilder::default().monied(true).build(), || { + Balances::set_lock(ID_1, &1, 10, 10, WithdrawReason::Transfer.into()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + Balances::extend_lock(ID_1, &1, 10, 10, WithdrawReasons::none()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + Balances::extend_lock(ID_1, &1, 10, 10, WithdrawReason::Reserve.into()); + assert_noop!(>::transfer(&1, &2, 6), "account liquidity restrictions prevent withdrawal"); + }); +} #[test] fn default_indexing_on_new_accounts_should_not_work2() { @@ -464,4 +593,4 @@ fn extra_balance_should_transfer() { assert_ok!(Balances::transfer(Some(1).into(), 2, 256 * 5)); // Account 1 can send extra units gained } ); -} \ No newline at end of file +} diff --git a/srml/consensus/Cargo.toml b/srml/consensus/Cargo.toml index 075980fc5f158..105f978c6371f 100644 --- a/srml/consensus/Cargo.toml +++ b/srml/consensus/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false, features = ["derive"] } substrate-primitives = { path = "../../core/primitives", default-features = false } @@ -22,7 +22,7 @@ runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "parity-codec/std", "substrate-primitives/std", diff --git a/srml/contract/Cargo.toml b/srml/contract/Cargo.toml index 05d9a8e6169a5..d0c851e26e766 100644 --- a/srml/contract/Cargo.toml +++ b/srml/contract/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } pwasm-utils = { version = "0.6.1", default-features = false } parity-codec = { version = "3.1", default-features = false, features = ["derive"] } @@ -30,7 +30,7 @@ consensus = { package = "srml-consensus", path = "../consensus" } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "parity-codec/std", "substrate-primitives/std", diff --git a/srml/contract/src/exec.rs b/srml/contract/src/exec.rs index 046d1075337aa..615fdc51e2496 100644 --- a/srml/contract/src/exec.rs +++ b/srml/contract/src/exec.rs @@ -20,8 +20,8 @@ use crate::gas::{GasMeter, Token, approx_gas_for_balance}; use rstd::prelude::*; use runtime_primitives::traits::{CheckedAdd, CheckedSub, Zero}; +use srml_support::traits::WithdrawReason; use timestamp; -use srml_support::traits::EnsureAccountLiquid; pub type BalanceOf = ::Balance; pub type AccountIdOf = ::AccountId; @@ -520,7 +520,7 @@ fn transfer<'a, T: Trait, V: Vm, L: Loader>( if would_create && value < ctx.config.existential_deposit { return Err("value too low to create account"); } - ::EnsureAccountLiquid::ensure_account_liquid(transactor)?; + >::ensure_account_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?; let new_to_balance = match to_balance.checked_add(&value) { Some(b) => b, diff --git a/srml/contract/src/tests.rs b/srml/contract/src/tests.rs index 1d1141c2f4acf..7a7137c675953 100644 --- a/srml/contract/src/tests.rs +++ b/srml/contract/src/tests.rs @@ -77,7 +77,6 @@ impl balances::Trait for Test { type Balance = u64; type OnFreeBalanceZero = Contract; type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = MetaEvent; } impl timestamp::Trait for Test { diff --git a/srml/council/Cargo.toml b/srml/council/Cargo.toml index 3e6f41d2a9977..868ec3bcff038 100644 --- a/srml/council/Cargo.toml +++ b/srml/council/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} parity-codec = { version = "3.1", default-features = false } parity-codec-derive = { version = "3.1", default-features = false } @@ -29,6 +29,7 @@ std = [ "parity-codec-derive/std", "substrate-primitives/std", "rstd/std", + "serde", "runtime_io/std", "srml-support/std", "primitives/std", diff --git a/srml/council/src/lib.rs b/srml/council/src/lib.rs index 20c95b2bd9ff4..5f5709656d0af 100644 --- a/srml/council/src/lib.rs +++ b/srml/council/src/lib.rs @@ -76,7 +76,6 @@ mod tests { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = Event; } impl democracy::Trait for Test { diff --git a/srml/democracy/Cargo.toml b/srml/democracy/Cargo.toml index 23ca4221cfb3d..29b70938f20c1 100644 --- a/srml/democracy/Cargo.toml +++ b/srml/democracy/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} parity-codec = { version = "3.1", default-features = false, features = ["derive"] } @@ -23,7 +23,7 @@ balances = { package = "srml-balances", path = "../balances" } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "safe-mix/std", "parity-codec/std", diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index e421fdeb0a8ff..1c06a43ff9c39 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -20,17 +20,19 @@ use rstd::prelude::*; use rstd::result; -use primitives::traits::{Zero, As}; +use primitives::traits::{Zero, As, Bounded}; use parity_codec::{Encode, Decode}; use srml_support::{StorageValue, StorageMap, Parameter, Dispatchable, IsSubType}; use srml_support::{decl_module, decl_storage, decl_event, ensure}; -use srml_support::traits::{Currency, OnFreeBalanceZero, EnsureAccountLiquid, WithdrawReason, ArithmeticType}; +use srml_support::traits::{Currency, LockableCurrency, WithdrawReason, ArithmeticType, LockIdentifier}; use srml_support::dispatch::Result; use system::ensure_signed; mod vote_threshold; pub use vote_threshold::{Approved, VoteThreshold}; +const DEMOCRACY_ID: LockIdentifier = *b"democrac"; + /// A proposal index. pub type PropIndex = u32; /// A referendum index. @@ -68,7 +70,7 @@ impl Vote { type BalanceOf = <::Currency as ArithmeticType>::Type; pub trait Trait: system::Trait + Sized { - type Currency: ArithmeticType + Currency<::AccountId, Balance=BalanceOf>; + type Currency: ArithmeticType + LockableCurrency<::AccountId, Moment=Self::BlockNumber, Balance=BalanceOf>; type Proposal: Parameter + Dispatchable + IsSubType>; @@ -208,9 +210,6 @@ decl_storage! { /// Queue of successful referenda to be dispatched. pub DispatchQueue get(dispatch_queue): map T::BlockNumber => Vec>; - /// The block at which the `who`'s funds become liquid. - pub Bondage get(bondage): map T::AccountId => T::BlockNumber; - /// Get the voters for the current proposal. pub VotersFor get(voters_for): map ReferendumIndex => Vec; @@ -371,7 +370,7 @@ impl Module { // lock should they win... let locked_until = now + lock_period * T::BlockNumber::sa((vote.multiplier()) as u64); // ...extend their bondage until at least then. - >::mutate(a, |b| if *b < locked_until { *b = locked_until }); + T::Currency::extend_lock(DEMOCRACY_ID, &a, Bounded::max_value(), locked_until, WithdrawReason::Transfer.into()); } Self::clear_referendum(index); @@ -409,35 +408,6 @@ impl Module { } } -impl OnFreeBalanceZero for Module { - fn on_free_balance_zero(who: &T::AccountId) { - >::remove(who); - } -} - -impl EnsureAccountLiquid> for Module { - fn ensure_account_liquid(who: &T::AccountId) -> Result { - if Self::bondage(who) > >::block_number() { - Err("stash accounts are not liquid") - } else { - Ok(()) - } - } - fn ensure_account_can_withdraw( - who: &T::AccountId, - _value: BalanceOf, - reason: WithdrawReason, - ) -> Result { - if reason == WithdrawReason::TransactionPayment - || Self::bondage(who) <= >::block_number() - { - Ok(()) - } else { - Err("cannot transfer voting funds") - } - } -} - #[cfg(test)] mod tests { use super::*; @@ -447,6 +417,7 @@ mod tests { use primitives::BuildStorage; use primitives::traits::{BlakeTwo256, IdentityLookup}; use primitives::testing::{Digest, DigestItem, Header}; + use balances::BalanceLock; const AYE: Vote = Vote(-1); const NAY: Vote = Vote(0); @@ -482,7 +453,6 @@ mod tests { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = (); } impl Trait for Test { @@ -790,12 +760,12 @@ mod tests { assert_eq!(Democracy::end_block(System::block_number()), Ok(())); - assert_eq!(Democracy::bondage(1), 0); - assert_eq!(Democracy::bondage(2), 6); - assert_eq!(Democracy::bondage(3), 5); - assert_eq!(Democracy::bondage(4), 4); - assert_eq!(Democracy::bondage(5), 3); - assert_eq!(Democracy::bondage(6), 0); + assert_eq!(Balances::locks(1), vec![]); + assert_eq!(Balances::locks(2), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), until: 6, reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Balances::locks(3), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), until: 5, reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Balances::locks(4), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), until: 4, reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Balances::locks(5), vec![BalanceLock { id: DEMOCRACY_ID, amount: u64::max_value(), until: 3, reasons: WithdrawReason::Transfer.into() }]); + assert_eq!(Balances::locks(6), vec![]); System::set_block_number(2); assert_eq!(Democracy::end_block(System::block_number()), Ok(())); diff --git a/srml/example/Cargo.toml b/srml/example/Cargo.toml index beaafbeb21529..c1cf286346402 100644 --- a/srml/example/Cargo.toml +++ b/srml/example/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false } srml-support = { path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } @@ -20,7 +20,7 @@ sr-primitives = { path = "../../core/sr-primitives" } [features] default = ["std"] std = [ - "serde/std", + "serde", "parity-codec/std", "sr-primitives/std", "srml-support/std", diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index 4f4e0b96a0b62..8ab4513296469 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -280,7 +280,6 @@ mod tests { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = (); } impl Trait for Test { diff --git a/srml/executive/Cargo.toml b/srml/executive/Cargo.toml index fe195acc21e39..04f6526666ce1 100644 --- a/srml/executive/Cargo.toml +++ b/srml/executive/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } @@ -26,7 +26,7 @@ default = ["std"] std = [ "rstd/std", "srml-support/std", - "serde/std", + "serde", "parity-codec/std", "primitives/std", "runtime_io/std", diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index c6817c25544f1..567c157f1e244 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -319,7 +319,6 @@ mod tests { type Balance = u64; type OnFreeBalanceZero = (); type OnNewAccount = (); - type EnsureAccountLiquid = (); type Event = MetaEvent; } impl fees::Trait for Runtime { diff --git a/srml/fees/Cargo.toml b/srml/fees/Cargo.toml index 7f49956167dd5..d29d77c7489ff 100644 --- a/srml/fees/Cargo.toml +++ b/srml/fees/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false } parity-codec-derive = { version = "3.1", default-features = false } primitives = { package = "substrate-primitives", path = "../../core/primitives", default-features = false } @@ -19,7 +19,7 @@ system = { package = "srml-system", path = "../system", default-features = false [features] default = ["std"] std = [ - "serde/std", + "serde", "parity-codec/std", "parity-codec-derive/std", "primitives/std", diff --git a/srml/grandpa/Cargo.toml b/srml/grandpa/Cargo.toml index e7a1b701052d3..ac4ea857de063 100644 --- a/srml/grandpa/Cargo.toml +++ b/srml/grandpa/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] #hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false, features = ["derive"] } substrate-primitives = { path = "../../core/primitives", default-features = false } @@ -24,7 +24,7 @@ runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "parity-codec/std", "substrate-primitives/std", diff --git a/srml/indices/Cargo.toml b/srml/indices/Cargo.toml index 7182514b07d5b..399c7b1bd051f 100644 --- a/srml/indices/Cargo.toml +++ b/srml/indices/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} parity-codec = { version = "3.1", default-features = false } parity-codec-derive = { version = "3.1", default-features = false } @@ -24,7 +24,7 @@ ref_thread_local = "0.0" [features] default = ["std"] std = [ - "serde/std", + "serde", "safe-mix/std", "substrate-keyring", "parity-codec/std", diff --git a/srml/indices/src/lib.rs b/srml/indices/src/lib.rs index c63f819d35d3f..fc9f6a66dd01e 100644 --- a/srml/indices/src/lib.rs +++ b/srml/indices/src/lib.rs @@ -198,4 +198,7 @@ impl StaticLookup for Module { fn lookup(a: Self::Source) -> result::Result { Self::lookup_address(a).ok_or("invalid account index") } + fn unlookup(a: Self::Target) -> Self::Source { + address::Address::Id(a) + } } diff --git a/srml/session/Cargo.toml b/srml/session/Cargo.toml index 8fdd08f1ae652..8412505d32965 100644 --- a/srml/session/Cargo.toml +++ b/srml/session/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} parity-codec = { version = "3.1", default-features = false } parity-codec-derive = { version = "3.1", default-features = false } @@ -24,7 +24,7 @@ runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] default = ["std"] std = [ - "serde/std", + "serde", "safe-mix/std", "parity-codec/std", "parity-codec-derive/std", diff --git a/srml/session/src/lib.rs b/srml/session/src/lib.rs index 13f2a4cd0ae00..63188d5bf6cb7 100644 --- a/srml/session/src/lib.rs +++ b/srml/session/src/lib.rs @@ -50,7 +50,7 @@ macro_rules! impl_session_change { for_each_tuple!(impl_session_change); -pub trait Trait: timestamp::Trait { +pub trait Trait: timestamp::Trait + consensus::Trait { type ConvertAccountIdToSessionKey: Convert; type OnSessionChange: OnSessionChange; type Event: From> + Into<::Event>; diff --git a/srml/staking/Cargo.toml b/srml/staking/Cargo.toml index 5fc70e27ea688..c548b3a2ef117 100644 --- a/srml/staking/Cargo.toml +++ b/srml/staking/Cargo.toml @@ -6,11 +6,12 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} parity-codec = { version = "3.1", default-features = false, features = ["derive"] } substrate-keyring = { path = "../../core/keyring", optional = true } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } +runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } srml-support = { path = "../support", default-features = false } consensus = { package = "srml-consensus", path = "../consensus", default-features = false } @@ -19,18 +20,18 @@ session = { package = "srml-session", path = "../session", default-features = fa [dev-dependencies] substrate-primitives = { path = "../../core/primitives" } -runtime_io = { package = "sr-io", path = "../../core/sr-io" } timestamp = { package = "srml-timestamp", path = "../timestamp" } balances = { package = "srml-balances", path = "../balances" } [features] default = ["std"] std = [ - "serde/std", + "serde", "safe-mix/std", "substrate-keyring", "parity-codec/std", "rstd/std", + "runtime_io/std", "srml-support/std", "primitives/std", "session/std", diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index 71a7f27ce1612..fb2076af81de1 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -20,18 +20,20 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "std")] +use runtime_io::with_storage; use rstd::{prelude::*, result}; use parity_codec::{HasCompact, Encode, Decode}; use srml_support::{StorageValue, StorageMap, EnumerableStorageMap, dispatch::Result}; use srml_support::{decl_module, decl_event, decl_storage, ensure}; use srml_support::traits::{ - Currency, OnDilution, EnsureAccountLiquid, OnFreeBalanceZero, WithdrawReason, ArithmeticType + Currency, OnDilution, OnFreeBalanceZero, ArithmeticType, + LockIdentifier, LockableCurrency, WithdrawReasons }; use session::OnSessionChange; use primitives::Perbill; -use primitives::traits::{Zero, One, As, StaticLookup, Saturating}; +use primitives::traits::{Zero, One, As, StaticLookup, Saturating, Bounded}; use system::ensure_signed; - mod mock; mod tests; @@ -111,7 +113,11 @@ pub struct StakingLedger>, } -impl StakingLedger { +impl< + AccountId, + Balance: HasCompact + Copy + Saturating, + BlockNumber: HasCompact + PartialOrd +> StakingLedger { /// Remove entries from `unlocking` that are sufficiently old and reduce the /// total by the sum of their balances. fn consolidate_unlocked(self, current_era: BlockNumber) -> Self { @@ -157,7 +163,10 @@ type BalanceOf = <::Currency as ArithmeticType>::Type; pub trait Trait: system::Trait + session::Trait { /// The staking balance. - type Currency: ArithmeticType + Currency>; + type Currency: + ArithmeticType + + Currency> + + LockableCurrency; /// Some tokens minted. type OnRewardMinted: OnDilution>; @@ -166,6 +175,8 @@ pub trait Trait: system::Trait + session::Trait { type Event: From> + Into<::Event>; } +const STAKING_ID: LockIdentifier = *b"staking "; + decl_storage! { trait Store for Module as Staking { @@ -192,21 +203,9 @@ decl_storage! { pub Invulnerables get(invulnerables) config(): Vec; /// Map from all locked "stash" accounts to the controller account. - pub Bonded get(bonded) build(|config: &GenesisConfig| { - config.stakers.iter().map(|(stash, controller, _)| (stash.clone(), controller.clone())).collect::>() - }): map T::AccountId => Option; + pub Bonded get(bonded): map T::AccountId => Option; /// Map from all (unlocked) "controller" accounts to the info regarding the staking. - pub Ledger get(ledger) build(|config: &GenesisConfig| { - config.stakers.iter().map(|(stash, controller, value)| ( - controller.clone(), - StakingLedger { - stash: stash.clone(), - total: *value, - active: *value, - unlocking: Vec::, T::BlockNumber>>::new(), - }, - )).collect::>() - }): map T::AccountId => Option, T::BlockNumber>>; + pub Ledger get(ledger): map T::AccountId => Option, T::BlockNumber>>; /// Where the reward payment should be made. pub Payee get(payee): map T::AccountId => RewardDestination; @@ -214,12 +213,7 @@ decl_storage! { /// The set of keys are all controllers that want to validate. /// /// The values are the preferences that a validator has. - pub Validators get(validators) build(|config: &GenesisConfig| { - config.stakers.iter().map(|(_stash, controller, _value)| ( - controller.clone(), - ValidatorPrefs::>::default(), - )).collect::>() - }): linked_map T::AccountId => ValidatorPrefs>; + pub Validators get(validators): linked_map T::AccountId => ValidatorPrefs>; /// The set of keys are all controllers that want to nominate. /// @@ -228,16 +222,7 @@ decl_storage! { /// Nominators for a particular account that is in action right now. You can't iterate through validators here, /// but you can find them in the `sessions` module. - pub Stakers get(stakers) build(|config: &GenesisConfig| { - config.stakers.iter().map(|(_stash, controller, value)| ( - controller.clone(), - Exposure { - total: *value, - own: *value, - others: Vec::>::new(), - }, - )).collect::>() - }): map T::AccountId => Exposure>; + pub Stakers get(stakers): map T::AccountId => Exposure>; // The historical validators and their nominations for a given era. Stored as a trie root of the mapping // `T::AccountId` => `Exposure>`, which is just the contents of `Stakers`, @@ -282,7 +267,16 @@ decl_storage! { } add_extra_genesis { config(stakers): Vec<(T::AccountId, T::AccountId, BalanceOf)>; - } + build(|storage: &mut primitives::StorageOverlay, _: &mut primitives::ChildrenStorageOverlay, config: &GenesisConfig| { + with_storage(storage, || { + for &(ref stash, ref controller, balance) in &config.stakers { + let _ = >::bond(T::Origin::from(Some(stash.clone()).into()), T::Lookup::unlookup(controller.clone()), balance, RewardDestination::Staked); + let _ = >::validate(T::Origin::from(Some(controller.clone()).into()), Default::default()); + } + >::select_validators(); + }); + }); + } } decl_module! { @@ -307,7 +301,7 @@ decl_module! { let stash_balance = T::Currency::free_balance(&stash); let value = value.min(stash_balance); - >::insert(&controller, StakingLedger { stash, total: value, active: value, unlocking: vec![] }); + Self::update_ledger(&controller, StakingLedger { stash, total: value, active: value, unlocking: vec![] }); >::insert(&controller, payee); } @@ -326,7 +320,7 @@ decl_module! { let extra = (stash_balance - ledger.total).min(max_additional); ledger.total += extra; ledger.active += extra; - >::insert(&controller, ledger); + Self::update_ledger(&controller, ledger); } } @@ -358,7 +352,7 @@ decl_module! { let era = Self::current_era() + Self::bonding_duration(); ledger.unlocking.push(UnlockChunk { value, era }); - >::insert(&controller, ledger); + Self::update_ledger(&controller, ledger); } } @@ -373,7 +367,8 @@ decl_module! { fn withdraw_unbonded(origin) { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or("not a controller")?; - >::insert(&controller, ledger.consolidate_unlocked(Self::current_era())); + let ledger = ledger.consolidate_unlocked(Self::current_era()); + Self::update_ledger(&controller, ledger); } /// Declare the desire to validate for the origin controller. @@ -503,8 +498,14 @@ impl Module { Self::stakers(who).total } - // PUBLIC MUTABLES (DANGEROUS) - + // MUTABLES (DANGEROUS) + + /// Update the ledger for a controller. This will also update the stash lock. + fn update_ledger(controller: &T::AccountId, ledger: StakingLedger, T::BlockNumber>) { + T::Currency::set_lock(STAKING_ID, &ledger.stash, ledger.total, T::BlockNumber::max_value(), WithdrawReasons::all()); + >::insert(controller, ledger); + } + /// Slash a given validator by a specific amount. Removes the slash from their balance by preference, /// and reduces the nominators' balance if needed. fn slash_validator(v: &T::AccountId, slash: BalanceOf) { @@ -540,13 +541,13 @@ impl Module { RewardDestination::Stash => { let _ = Self::ledger(who).map(|l| T::Currency::reward(&l.stash, amount)); } - RewardDestination::Staked => >::mutate(who, |ml| { - if let Some(l) = ml.as_mut() { + RewardDestination::Staked => + if let Some(mut l) = Self::ledger(who) { l.active += amount; l.total += amount; let _ = T::Currency::reward(&l.stash, amount); - } - }), + Self::update_ledger(who, l); + }, } } @@ -626,7 +627,17 @@ impl Module { } // Reassign all Stakers. + let slot_stake = Self::select_validators(); + + // Update the balances for slashing/rewarding according to the stakes. + >::put(Self::offline_slash() * slot_stake); + >::put(Self::session_reward() * slot_stake); + } + /// Select a new validator set from the assembled stakers and their role preferences. + /// + /// @returns the new SlotStake value. + fn select_validators() -> BalanceOf { // Map of (would-be) validator account to amount of stake backing it. // First, we pull all validators, together with their stash balance into a Vec (cpu=O(V), mem=O(V)) @@ -658,6 +669,7 @@ impl Module { // cpu=O(V.log(s)) average, O(V.s) worst. let count = Self::validator_count() as usize; let candidates = if candidates.len() <= count { + candidates.sort_unstable_by(|a, b| b.1.total.cmp(&a.1.total)); candidates } else { candidates.into_iter().fold(vec![], |mut winners: Vec<(T::AccountId, Exposure>)>, entry| { @@ -700,9 +712,7 @@ impl Module { &candidates.into_iter().map(|i| i.0).collect::>() ); - // Update the balances for slashing/rewarding according to the stakes. - >::put(Self::offline_slash() * slot_stake); - >::put(Self::session_reward() * slot_stake); + slot_stake } /// Call when a validator is determined to be offline. `count` is the @@ -769,29 +779,6 @@ impl OnSessionChange for Module { } } -impl EnsureAccountLiquid> for Module { - fn ensure_account_liquid(who: &T::AccountId) -> Result { - if >::exists(who) { - Err("stash accounts are not liquid") - } else { - Ok(()) - } - } - fn ensure_account_can_withdraw( - who: &T::AccountId, - amount: BalanceOf, - _reason: WithdrawReason, - ) -> Result { - if let Some(controller) = Self::bonded(who) { - let ledger = Self::ledger(&controller).ok_or("stash without controller")?; - let free_balance = T::Currency::free_balance(&who); - ensure!(free_balance.saturating_sub(ledger.total) > amount, - "stash with too much under management"); - } - Ok(()) - } -} - impl OnFreeBalanceZero for Module { fn on_free_balance_zero(who: &T::AccountId) { if let Some(controller) = >::take(who) { diff --git a/srml/staking/src/mock.rs b/srml/staking/src/mock.rs index 244c3c18c22ce..3ac827ecf8407 100644 --- a/srml/staking/src/mock.rs +++ b/srml/staking/src/mock.rs @@ -54,7 +54,6 @@ impl balances::Trait for Test { type Balance = u64; type OnFreeBalanceZero = Staking; type OnNewAccount = (); - type EnsureAccountLiquid = Staking; type Event = (); } impl session::Trait for Test { @@ -120,22 +119,22 @@ impl ExtBuilder { self } pub fn build(self) -> runtime_io::TestExternalities { - let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; + let (mut t, mut c) = system::GenesisConfig::::default().build_storage().unwrap(); let balance_factor = if self.existential_deposit > 0 { 256 } else { 1 }; - t.extend(consensus::GenesisConfig::{ + let _ = consensus::GenesisConfig::{ code: vec![], authorities: vec![], - }.build_storage().unwrap().0); - t.extend(session::GenesisConfig::{ + }.assimilate_storage(&mut t, &mut c); + let _ = session::GenesisConfig::{ session_length: self.session_length, validators: vec![10, 20], keys: vec![], - }.build_storage().unwrap().0); - t.extend(balances::GenesisConfig::{ + }.assimilate_storage(&mut t, &mut c); + let _ = balances::GenesisConfig::{ balances: if self.monied { if self.reward > 0 { vec![(1, 10 * balance_factor), (2, 20 * balance_factor), (3, 300 * balance_factor), (4, 400 * balance_factor), (10, balance_factor), (11, balance_factor * 1000), (20, balance_factor), (21, balance_factor * 2000)] @@ -149,8 +148,8 @@ impl ExtBuilder { transfer_fee: 0, creation_fee: 0, vesting: vec![], - }.build_storage().unwrap().0); - t.extend(GenesisConfig::{ + }.assimilate_storage(&mut t, &mut c); + let _ = GenesisConfig::{ sessions_per_era: self.sessions_per_era, current_era: self.current_era, stakers: vec![(11, 10, balance_factor * 1000), (21, 20, balance_factor * 2000)], @@ -163,10 +162,10 @@ impl ExtBuilder { current_offline_slash: 20, offline_slash_grace: 0, invulnerables: vec![], - }.build_storage().unwrap().0); - t.extend(timestamp::GenesisConfig::{ + }.assimilate_storage(&mut t, &mut c); + let _ = timestamp::GenesisConfig::{ period: 5, - }.build_storage().unwrap().0); + }.assimilate_storage(&mut t, &mut c); t.into() } } diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index 5ca7a46801e9a..4deaee08d5c30 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -332,7 +332,7 @@ fn staking_should_work() { assert_eq!(Staking::era_length(), 3); assert_eq!(Staking::validator_count(), 2); // remember + compare this along with the test. - assert_eq!(Session::validators(), vec![10, 20]); + assert_eq!(Session::validators(), vec![20, 10]); assert_ok!(Staking::set_bonding_duration(2)); assert_eq!(Staking::bonding_duration(), 2); @@ -347,7 +347,7 @@ fn staking_should_work() { Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); // No effects will be seen so far.s - assert_eq!(Session::validators(), vec![10, 20]); + assert_eq!(Session::validators(), vec![20, 10]); // --- Block 2: @@ -359,7 +359,7 @@ fn staking_should_work() { Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); // No effects will be seen so far. Era has not been yet triggered. - assert_eq!(Session::validators(), vec![10, 20]); + assert_eq!(Session::validators(), vec![20, 10]); // --- Block 3: the validators will now change. @@ -413,7 +413,7 @@ fn nominating_and_rewards_should_work() { assert_eq!(Staking::era_length(), 1); assert_eq!(Staking::validator_count(), 2); assert_eq!(Staking::bonding_duration(), 3); - assert_eq!(Session::validators(), vec![10, 20]); + assert_eq!(Session::validators(), vec![20, 10]); // Set payee to controller assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); @@ -447,7 +447,7 @@ fn nominating_and_rewards_should_work() { Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 1); // validators will not change, since selection currently is actually not dependent on nomination and votes, only stake. - assert_eq!(Session::validators(), vec![10, 20]); + assert_eq!(Session::validators(), vec![20, 10]); // avalidators must have already received some rewards. assert_eq!(Balances::total_balance(&10), initial_balance + session_reward); assert_eq!(Balances::total_balance(&20), initial_balance + session_reward); @@ -487,7 +487,7 @@ fn nominators_also_get_slashed() { // Account 10 has not been reported offline assert_eq!(Staking::slash_count(&10), 0); // initial validators - assert_eq!(Session::validators(), vec![10, 20]); + assert_eq!(Session::validators(), vec![20, 10]); // Set payee to controller assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); @@ -500,7 +500,7 @@ fn nominators_also_get_slashed() { // 2 will nominate for 10 let nominator_stake = 500; assert_ok!(Staking::bond(Origin::signed(1), 2, nominator_stake, RewardDestination::default())); - assert_ok!(Staking::nominate(Origin::signed(2), vec![10, 20])); + assert_ok!(Staking::nominate(Origin::signed(2), vec![20, 10])); // new era, pay rewards, System::set_block_number(2); @@ -628,7 +628,7 @@ fn cannot_transfer_staked_balance() { // Confirm account 11 (via controller 10) is totally staked assert_eq!(Staking::stakers(&10).total, 1000); // Confirm account 11 cannot transfer as a result - assert_noop!(Balances::transfer(Origin::signed(11), 20, 1), "stash with too much under management"); + assert_noop!(Balances::transfer(Origin::signed(11), 20, 1), "account liquidity restrictions prevent withdrawal"); // Give account 11 extra free balance Balances::set_free_balance(&11, 10000); @@ -637,8 +637,6 @@ fn cannot_transfer_staked_balance() { }); } - - #[test] fn cannot_reserve_staked_balance() { // Checks that a bonded account cannot reserve balance from free balance @@ -650,7 +648,7 @@ fn cannot_reserve_staked_balance() { // Confirm account 11 (via controller 10) is totally staked assert_eq!(Staking::stakers(&10).total, 1000); // Confirm account 11 cannot transfer as a result - assert_noop!(Balances::reserve(&11, 1), "stash with too much under management"); + assert_noop!(Balances::reserve(&11, 1), "account liquidity restrictions prevent withdrawal"); // Give account 11 extra free balance Balances::set_free_balance(&11, 10000); diff --git a/srml/sudo/Cargo.toml b/srml/sudo/Cargo.toml index f607385131ce9..8473d2fb44fe3 100644 --- a/srml/sudo/Cargo.toml +++ b/srml/sudo/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false } parity-codec-derive = { version = "3.1", default-features = false } sr-std = { path = "../../core/sr-std", default-features = false } @@ -22,7 +22,7 @@ substrate-primitives = { path = "../../core/primitives" } [features] default = ["std"] std = [ - "serde/std", + "serde", "parity-codec/std", "parity-codec-derive/std", "sr-std/std", diff --git a/srml/support/Cargo.toml b/srml/support/Cargo.toml index cda9aaa904d70..2cc4cfa0c8327 100644 --- a/srml/support/Cargo.toml +++ b/srml/support/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = { version = "0.1.0", optional = true } -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false, features = ["derive"] } srml-metadata = { path = "../metadata", default-features = false } @@ -17,6 +17,7 @@ inherents = { package = "substrate-inherents", path = "../../core/inherents", de srml-support-procedural = { path = "./procedural" } paste = "0.1" once_cell = { version = "0.1.6", default-features = false, optional = true } +bitmask = { git = "https://github.com/paritytech/bitmask", default-features = false } [dev-dependencies] pretty_assertions = "0.5.1" @@ -26,7 +27,8 @@ default = ["std"] std = [ "hex-literal", "once_cell", - "serde/std", + "bitmask/std", + "serde", "serde_derive", "runtime_io/std", "parity-codec/std", diff --git a/srml/support/procedural/src/storage/transformation.rs b/srml/support/procedural/src/storage/transformation.rs index 017a217f1c342..6bc15ea2f6d05 100644 --- a/srml/support/procedural/src/storage/transformation.rs +++ b/srml/support/procedural/src/storage/transformation.rs @@ -232,9 +232,9 @@ fn decl_store_extra_genesis( use #scrate::rstd::{cell::RefCell, marker::PhantomData}; use #scrate::codec::{Encode, Decode}; - let storage = (RefCell::new(&mut r), PhantomData::::default()); let v = (#builder)(&self); <#name<#traitinstance> as #scrate::storage::generator::StorageValue<#typ>>::put(&v, &storage); + }} }, DeclStorageTypeInfosKind::Map { key_type, .. } => { @@ -242,7 +242,6 @@ fn decl_store_extra_genesis( use #scrate::rstd::{cell::RefCell, marker::PhantomData}; use #scrate::codec::{Encode, Decode}; - let storage = (RefCell::new(&mut r), PhantomData::::default()); let data = (#builder)(&self); for (k, v) in data.into_iter() { <#name<#traitinstance> as #scrate::storage::generator::StorageMap<#key_type, #typ>>::insert(&k, &v, &storage); @@ -382,12 +381,28 @@ fn decl_store_extra_genesis( let mut r: #scrate::runtime_primitives::StorageOverlay = Default::default(); let mut c: #scrate::runtime_primitives::ChildrenStorageOverlay = Default::default(); - #builders + { + use #scrate::rstd::{cell::RefCell, marker::PhantomData}; + let storage = (RefCell::new(&mut r), PhantomData::::default()); + #builders + } #scall(&mut r, &mut c, &self); Ok((r, c)) } + fn assimilate_storage(self, r: &mut #scrate::runtime_primitives::StorageOverlay, c: &mut #scrate::runtime_primitives::ChildrenStorageOverlay) -> ::std::result::Result<(), String> { + use #scrate::rstd::{cell::RefCell, marker::PhantomData}; + let storage = (RefCell::new(r), PhantomData::::default()); + + #builders + + let r = storage.0.into_inner(); + + #scall(r, c, &self); + + Ok(()) + } } } } else { diff --git a/srml/support/src/lib.rs b/srml/support/src/lib.rs index a7bbf329381e6..ccfa2603a0297 100644 --- a/srml/support/src/lib.rs +++ b/srml/support/src/lib.rs @@ -19,6 +19,9 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc))] +#[macro_use] +extern crate bitmask; + #[cfg(feature = "std")] pub use serde; #[doc(hidden)] diff --git a/srml/support/src/traits.rs b/srml/support/src/traits.rs index 81d0239e5cdc0..37290d4ef14a0 100644 --- a/srml/support/src/traits.rs +++ b/srml/support/src/traits.rs @@ -17,7 +17,7 @@ //! Traits for SRML use crate::rstd::result; -use crate::codec::Codec; +use crate::codec::{Codec, Encode, Decode}; use crate::runtime_primitives::traits::{ MaybeSerializeDebug, SimpleArithmetic, As }; @@ -53,61 +53,6 @@ impl OnDilution for () { fn on_dilution(_minted: Balance, _portion: Balance) {} } -/// Determinator for whether a given account is able to use its **free** balance. -/// -/// By convention, `ensure_account_liquid` overrules `ensure_account_can_withdraw`. If a -/// caller gets `Ok` from the former, then they do not need to call the latter. -/// -/// This implies that if you define the latter away from its default of replicating the -/// former, then ensure you also redefine the former to return an `Err` in corresponding -/// situations, otherwise you'll end up giving inconsistent information. -// TODO: Remove in favour of explicit functionality in balances module: #1896 -pub trait EnsureAccountLiquid { - /// Ensures that the account is completely unencumbered. If this is `Ok` then there's no need to - /// check any other items. If it's an `Err`, then you must use one pair of the other items. - fn ensure_account_liquid(who: &AccountId) -> result::Result<(), &'static str>; - - /// Returns `Ok` iff the account is able to make a withdrawal of the given amount - /// for the given reason. - /// - /// `Err(...)` with the reason why not otherwise. - /// - /// By default this just reflects the results of `ensure_account_liquid`. - /// - /// @warning If you redefine this away from the default, ensure that you define - /// `ensure_account_liquid` in accordance. - fn ensure_account_can_withdraw( - who: &AccountId, - _amount: Balance, - _reason: WithdrawReason - ) -> result::Result<(), &'static str> { - Self::ensure_account_liquid(who) - } -} -impl< - AccountId, - Balance: Copy, - X: EnsureAccountLiquid, - Y: EnsureAccountLiquid, -> EnsureAccountLiquid for (X, Y) { - fn ensure_account_liquid(who: &AccountId) -> result::Result<(), &'static str> { - X::ensure_account_liquid(who)?; - Y::ensure_account_liquid(who) - } - - fn ensure_account_can_withdraw( - who: &AccountId, - amount: Balance, - reason: WithdrawReason - ) -> result::Result<(), &'static str> { - X::ensure_account_can_withdraw(who, amount, reason)?; - Y::ensure_account_can_withdraw(who, amount, reason) - } -} -impl EnsureAccountLiquid for () { - fn ensure_account_liquid(_who: &AccountId) -> result::Result<(), &'static str> { Ok(()) } -} - /// Outcome of a balance update. pub enum UpdateBalanceOutcome { /// Account balance was simply updated. @@ -227,6 +172,41 @@ pub trait Currency { ) -> result::Result, &'static str>; } +/// An identifier for a lock. Used for disambiguating different locks so that +/// they can be individually replaced or removed. +pub type LockIdentifier = [u8; 8]; + +/// A currency whose accounts can have liquidity restructions. +pub trait LockableCurrency: Currency { + /// The quantity used to denote time; usually just a `BlockNumber`. + type Moment; + + /// Introduce a new lock or change an existing one. + fn set_lock( + id: LockIdentifier, + who: &AccountId, + amount: Self::Balance, + until: Self::Moment, + reasons: WithdrawReasons, + ); + + /// Change any existing lock so that it becomes strictly less liquid in all + /// respects to the given parameters. + fn extend_lock( + id: LockIdentifier, + who: &AccountId, + amount: Self::Balance, + until: Self::Moment, + reasons: WithdrawReasons, + ); + + /// Remove an existing lock. + fn remove_lock( + id: LockIdentifier, + who: &AccountId, + ); +} + /// Charge bytes fee trait pub trait ChargeBytesFee { /// Charge fees from `transactor` for an extrinsic (transaction) of encoded length @@ -246,16 +226,21 @@ pub trait ChargeFee: ChargeBytesFee { fn refund_fee(transactor: &AccountId, amount: Self::Amount) -> Result<(), &'static str>; } -/// Reason for moving funds out of an account. -#[derive(Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "std", derive(Debug))] -pub enum WithdrawReason { - /// In order to pay for (system) transaction costs. - TransactionPayment, - /// In order to transfer ownership. - Transfer, - /// In order to reserve some funds for a later return or repatriation - Reserve, +bitmask! { + /// Reasons for moving funds out of an account. + #[derive(Encode, Decode)] + pub mask WithdrawReasons: i8 where + + /// Reason for moving funds out of an account. + #[derive(Encode, Decode)] + flags WithdrawReason { + /// In order to pay for (system) transaction costs. + TransactionPayment = 0b00000001, + /// In order to transfer ownership. + Transfer = 0b00000010, + /// In order to reserve some funds for a later return or repatriation + Reserve = 0b00000100, + } } /// Transfer fungible asset trait diff --git a/srml/system/Cargo.toml b/srml/system/Cargo.toml index f1f3692aa35f6..ea2628a3a24cd 100644 --- a/srml/system/Cargo.toml +++ b/srml/system/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } safe-mix = { version = "1.0", default-features = false} parity-codec = { version = "3.1", default-features = false, features = ["derive"] } @@ -19,7 +19,7 @@ srml-support = { path = "../support", default-features = false } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "safe-mix/std", "parity-codec/std", diff --git a/srml/timestamp/Cargo.toml b/srml/timestamp/Cargo.toml index d2133daebbda0..0c089b60e6515 100644 --- a/srml/timestamp/Cargo.toml +++ b/srml/timestamp/Cargo.toml @@ -6,14 +6,13 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } runtime_primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } inherents = { package = "substrate-inherents", path = "../../core/inherents", default-features = false } srml-support = { path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } -consensus = { package = "srml-consensus", path = "../consensus", default-features = false } [dev-dependencies] runtime_io = { package = "sr-io", path = "../../core/sr-io" } @@ -25,8 +24,7 @@ std = [ "rstd/std", "srml-support/std", "runtime_primitives/std", - "consensus/std", - "serde/std", + "serde", "parity-codec/std", "system/std", "inherents/std", diff --git a/srml/timestamp/src/lib.rs b/srml/timestamp/src/lib.rs index a7fa9e9663e33..a1414f94de2c9 100644 --- a/srml/timestamp/src/lib.rs +++ b/srml/timestamp/src/lib.rs @@ -32,17 +32,17 @@ #![cfg_attr(not(feature = "std"), no_std)] +use parity_codec::Encode; #[cfg(feature = "std")] use parity_codec::Decode; -use parity_codec::Encode; +#[cfg(feature = "std")] +use inherents::ProvideInherentData; use srml_support::{StorageValue, Parameter, decl_storage, decl_module}; use srml_support::for_each_tuple; use runtime_primitives::traits::{As, SimpleArithmetic, Zero}; use system::ensure_inherent; use rstd::{result, ops::{Mul, Div}, cmp}; use inherents::{RuntimeString, InherentIdentifier, ProvideInherent, IsFatalError, InherentData}; -#[cfg(feature = "std")] -use inherents::ProvideInherentData; /// The identifier for the `timestamp` inherent. pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"timstap0"; @@ -144,7 +144,7 @@ macro_rules! impl_timestamp_set { for_each_tuple!(impl_timestamp_set); -pub trait Trait: consensus::Trait + system::Trait { +pub trait Trait: system::Trait { /// Type used for expressing timestamp. type Moment: Parameter + Default + SimpleArithmetic + Mul @@ -259,7 +259,7 @@ mod tests { use substrate_primitives::H256; use runtime_primitives::BuildStorage; use runtime_primitives::traits::{BlakeTwo256, IdentityLookup}; - use runtime_primitives::testing::{Digest, DigestItem, Header, UintAuthorityId}; + use runtime_primitives::testing::{Digest, DigestItem, Header}; impl_outer_origin! { pub enum Origin for Test {} @@ -280,11 +280,6 @@ mod tests { type Event = (); type Log = DigestItem; } - impl consensus::Trait for Test { - type Log = DigestItem; - type SessionKey = UintAuthorityId; - type InherentOfflineReport = (); - } impl Trait for Test { type Moment = u64; type OnTimestampSet = (); diff --git a/srml/treasury/Cargo.toml b/srml/treasury/Cargo.toml index d417a0e7e2077..9bfb4b1725e71 100644 --- a/srml/treasury/Cargo.toml +++ b/srml/treasury/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] hex-literal = "0.1.0" -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false, features = ["derive"] } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } @@ -22,7 +22,7 @@ substrate-primitives = { path = "../../core/primitives" } [features] default = ["std"] std = [ - "serde/std", + "serde", "serde_derive", "parity-codec/std", "rstd/std", diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 2087846233a79..429bd24ecb5f4 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -287,7 +287,6 @@ mod tests { type Balance = u64; type OnNewAccount = (); type OnFreeBalanceZero = (); - type EnsureAccountLiquid = (); type Event = (); } impl Trait for Test { diff --git a/srml/upgrade-key/Cargo.toml b/srml/upgrade-key/Cargo.toml index 14f4bc4de541b..c548798dec96c 100644 --- a/srml/upgrade-key/Cargo.toml +++ b/srml/upgrade-key/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -serde = { version = "1.0", default-features = false } +serde = { version = "1.0", optional = true } parity-codec = { version = "3.1", default-features = false } sr-std = { path = "../../core/sr-std", default-features = false } sr-primitives = { path = "../../core/sr-primitives", default-features = false } @@ -16,7 +16,7 @@ consensus = { package = "srml-consensus", path = "../consensus", default-feature [features] default = ["std"] std = [ - "serde/std", + "serde", "parity-codec/std", "sr-std/std", "sr-primitives/std",