diff --git a/substrate/demo/executor/src/lib.rs b/substrate/demo/executor/src/lib.rs index 6e07f3c5fbf0216066a1602816cffb5adab4c1c1..5c6b2748d7a769eb5df74a29afaade15d8e656bb 100644 --- a/substrate/demo/executor/src/lib.rs +++ b/substrate/demo/executor/src/lib.rs @@ -38,15 +38,15 @@ mod tests { use runtime_io; use super::Executor; use substrate_executor::WasmExecutor; - use codec::{KeyedVec, Slicable, Joiner}; + use codec::{Slicable, Joiner}; use keyring::Keyring::{self, Alice, Bob}; - use runtime_support::Hashable; + use runtime_support::{Hashable, StorageValue, StorageMap}; use state_machine::{CodeExecutor, TestExternalities}; use primitives::twox_128; use demo_primitives::{Hash, Header, BlockNumber, Digest}; use demo_runtime::transaction::{Transaction, UncheckedTransaction}; use demo_runtime::block::Block; - use demo_runtime::runtime::staking::{self, balance, BALANCE_OF}; + use demo_runtime::runtime::staking::{self, FreeBalanceOf, balance}; use demo_runtime::dispatch; use ed25519::{Public, Pair}; @@ -75,8 +75,8 @@ mod tests { #[test] fn panic_execution_with_foreign_code_gives_error() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] + twox_128(&FreeBalanceOf::key_for(*Alice)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TransactionFee::key()).to_vec() => vec![0u8; 8] ]; let r = Executor::new().call(&mut t, BLOATY_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx())); @@ -86,8 +86,8 @@ mod tests { #[test] fn panic_execution_with_native_equivalent_code_gives_error() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] + twox_128(&FreeBalanceOf::key_for(*Alice)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TransactionFee::key()).to_vec() => vec![0u8; 8] ]; let r = Executor::new().call(&mut t, COMPACT_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx())); @@ -97,8 +97,8 @@ mod tests { #[test] fn successful_execution_with_native_equivalent_code_gives_ok() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] + twox_128(&FreeBalanceOf::key_for(*Alice)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TransactionFee::key()).to_vec() => vec![0u8; 8] ]; let r = Executor::new().call(&mut t, COMPACT_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx())); @@ -113,8 +113,8 @@ mod tests { #[test] fn successful_execution_with_foreign_code_gives_ok() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] + twox_128(&FreeBalanceOf::key_for(*Alice)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TransactionFee::key()).to_vec() => vec![0u8; 8] ]; let r = Executor::new().call(&mut t, BLOATY_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx())); @@ -158,7 +158,7 @@ mod tests { construct_block( 1, [69u8; 32].into(), - hex!("cfb76a83e40aa6a0d3f92255e6229e74808cae31d9f46053f31129b797540d03").into(), + hex!("7a388ce5b4eeadbb9268ae96e8822b223f4fd1841327d99f4e1c21fad81f97f2").into(), vec![Transaction { signed: Alice.into(), nonce: 0, @@ -171,7 +171,7 @@ mod tests { construct_block( 2, block1().1, - hex!("c713bd003e303648e8d904bcfa44084865c9b70c398547e678028cc7cf60907f").into(), + hex!("e4eb71be8b816f2061f32f284e9b429562cdc1b82f11725e5f965ff23439f5e9").into(), vec![ Transaction { signed: Bob.into(), @@ -228,8 +228,8 @@ mod tests { #[test] fn panic_execution_gives_error() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] + twox_128(&FreeBalanceOf::key_for(*Alice)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TransactionFee::key()).to_vec() => vec![0u8; 8] ]; let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm"); @@ -240,8 +240,8 @@ mod tests { #[test] fn successful_execution_gives_ok() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] + twox_128(&FreeBalanceOf::key_for(*Alice)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TransactionFee::key()).to_vec() => vec![0u8; 8] ]; let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm"); diff --git a/substrate/demo/runtime/src/genesismap.rs b/substrate/demo/runtime/src/genesismap.rs index c3b7da1b7d8c2f4e2ffe84f6b63d6a727af1270a..5fa83499b335a4f51a99819bacba784c6c232c77 100644 --- a/substrate/demo/runtime/src/genesismap.rs +++ b/substrate/demo/runtime/src/genesismap.rs @@ -19,7 +19,7 @@ use codec::{KeyedVec, Joiner}; use std::collections::HashMap; use runtime_io::twox_128; -use runtime_support::Hashable; +use runtime_support::{Hashable, StorageMap, StorageList, StorageValue}; use primitives::Block; use demo_primitives::{BlockNumber, AccountId}; use runtime::staking::Balance; @@ -80,40 +80,37 @@ impl GenesisConfig { pub fn genesis_map(&self) -> HashMap<Vec<u8>, Vec<u8>> { let wasm_runtime = include_bytes!("../wasm/genesis.wasm").to_vec(); vec![ - (&session::SESSION_LENGTH[..], vec![].and(&self.session_length)), - (&session::VALIDATOR_COUNT[..], vec![].and(&(self.validators.len() as u32))), + (session::SessionLength::key(), vec![].and(&self.session_length)), + (session::Validators::key(), vec![].and(&self.validators)), - (&staking::INTENTION_COUNT[..], vec![].and(&0u32)), - (&staking::SESSIONS_PER_ERA[..], vec![].and(&self.sessions_per_era)), - (&staking::CURRENT_ERA[..], vec![].and(&0u64)), + (&staking::Intention::len_key()[..], vec![].and(&0u32)), + (&staking::SessionsPerEra::key()[..], vec![].and(&self.sessions_per_era)), + (&staking::CurrentEra::key()[..], vec![].and(&0u64)), - (&democracy::LAUNCH_PERIOD[..], vec![].and(&self.launch_period)), - (&democracy::VOTING_PERIOD[..], vec![].and(&self.voting_period)), - (&democracy::MINIMUM_DEPOSIT[..], vec![].and(&self.minimum_deposit)), + (democracy::LaunchPeriod::key(), vec![].and(&self.launch_period)), + (democracy::VotingPeriod::key(), vec![].and(&self.voting_period)), + (democracy::MinimumDeposit::key(), vec![].and(&self.minimum_deposit)), - (&council::CANDIDACY_BOND[..], vec![].and(&self.candidacy_bond)), - (&council::VOTING_BOND[..], vec![].and(&self.voter_bond)), - (&council::PRESENT_SLASH_PER_VOTER[..], vec![].and(&self.present_slash_per_voter)), - (&council::CARRY_COUNT[..], vec![].and(&self.carry_count)), - (&council::PRESENTATION_DURATION[..], vec![].and(&self.presentation_duration)), - (&council::VOTING_PERIOD[..], vec![].and(&self.council_election_voting_period)), - (&council::TERM_DURATION[..], vec![].and(&self.council_term_duration)), - (&council::DESIRED_SEATS[..], vec![].and(&self.desired_seats)), - (&council::INACTIVE_GRACE_PERIOD[..], vec![].and(&self.inactive_grace_period)), + (council::CandidacyBond::key(), vec![].and(&self.candidacy_bond)), + (council::VotingBond::key(), vec![].and(&self.voter_bond)), + (council::PresentSlashPerVoter::key(), vec![].and(&self.present_slash_per_voter)), + (council::CarryCount::key(), vec![].and(&self.carry_count)), + (council::PresentationDuration::key(), vec![].and(&self.presentation_duration)), + (council::VotingPeriod::key(), vec![].and(&self.council_election_voting_period)), + (council::TermDuration::key(), vec![].and(&self.council_term_duration)), + (council::DesiredSeats::key(), vec![].and(&self.desired_seats)), + (council::InactiveGracePeriod::key(), vec![].and(&self.inactive_grace_period)), - (&council_vote::COOLOFF_PERIOD[..], vec![].and(&self.cooloff_period)), - (&council_vote::VOTING_PERIOD[..], vec![].and(&self.council_proposal_voting_period)) + (council_vote::CooloffPeriod::key(), vec![].and(&self.cooloff_period)), + (council_vote::VotingPeriod::key(), vec![].and(&self.council_proposal_voting_period)) ].into_iter() .map(|(k, v)| (k.into(), v)) - .chain(self.validators.iter() - .enumerate() - .map(|(i, account)| ((i as u32).to_keyed_vec(session::VALIDATOR_AT), vec![].and(account))) - ).chain(self.balances.iter() - .map(|&(account, balance)| (account.to_keyed_vec(staking::BALANCE_OF), vec![].and(&balance))) + .chain(self.balances.iter() + .map(|&(account, balance)| (staking::FreeBalanceOf::key_for(&account), vec![].and(&balance))) ) .map(|(k, v)| (twox_128(&k[..])[..].to_vec(), v.to_vec())) .chain(vec![ - (system::CODE[..].into(), wasm_runtime), + (system::CODE.to_vec(), wasm_runtime), (consensus::AUTHORITY_COUNT[..].into(), vec![].and(&(self.authorities.len() as u32))), ].into_iter()) .chain(self.authorities.iter() @@ -127,6 +124,6 @@ impl GenesisConfig { pub fn additional_storage_with_genesis(genesis_block: &Block) -> HashMap<Vec<u8>, Vec<u8>> { use codec::Slicable; map![ - twox_128(&0u64.to_keyed_vec(system::BLOCK_HASH_AT)).to_vec() => genesis_block.header.blake2_256().encode() + system::BlockHashAt::key_for(&0) => genesis_block.header.blake2_256().encode() ] } diff --git a/substrate/demo/runtime/src/lib.rs b/substrate/demo/runtime/src/lib.rs index 1df77cc8cb925331be6373624fc11e262c859cf4..b9769af20924881cf2451b8c813acc63a35054e9 100644 --- a/substrate/demo/runtime/src/lib.rs +++ b/substrate/demo/runtime/src/lib.rs @@ -20,7 +20,7 @@ #[allow(unused_imports)] #[macro_use] extern crate substrate_runtime_std as rstd; #[macro_use] extern crate substrate_runtime_io as runtime_io; -extern crate substrate_runtime_support as runtime_support; +#[macro_use] extern crate substrate_runtime_support as runtime_support; #[cfg(any(feature = "std", test))] extern crate substrate_keyring as keyring; #[cfg(feature = "std")] #[macro_use] extern crate serde_derive; diff --git a/substrate/demo/runtime/src/runtime/council.rs b/substrate/demo/runtime/src/runtime/council.rs index 504461cf19add715291b29b741b03fc814be02a5..3e64e231d8b351dfd7d733ce15250479a7b738f9 100644 --- a/substrate/demo/runtime/src/runtime/council.rs +++ b/substrate/demo/runtime/src/runtime/council.rs @@ -18,7 +18,7 @@ use rstd::prelude::*; use codec::KeyedVec; -use runtime_support::storage; +use runtime_support::{StorageMap, StorageValue}; use demo_primitives::{AccountId, Hash, BlockNumber}; use runtime::{staking, system, session}; use runtime::democracy::PrivPass; @@ -80,103 +80,66 @@ use runtime::staking::{PublicPass, Balance}; pub type VoteIndex = u32; -// parameters -pub const CANDIDACY_BOND: &[u8] = b"cou:cbo"; -pub const VOTING_BOND: &[u8] = b"cou:vbo"; -pub const PRESENT_SLASH_PER_VOTER: &[u8] = b"cou:pss"; -pub const CARRY_COUNT: &[u8] = b"cou:cco"; -pub const PRESENTATION_DURATION: &[u8] = b"cou:pdu"; -pub const INACTIVE_GRACE_PERIOD: &[u8] = b"cou:vgp"; -pub const VOTING_PERIOD: &[u8] = b"cou:per"; -pub const TERM_DURATION: &[u8] = b"cou:trm"; -pub const DESIRED_SEATS: &[u8] = b"cou:sts"; - -// permanent state (always relevant, changes only at the finalisation of voting) -pub const ACTIVE_COUNCIL: &[u8] = b"cou:act"; // Vec<(AccountId, expiry: BlockNumber)> -pub const VOTE_COUNT: &[u8] = b"cou:vco"; // VoteIndex - -// persistent state (always relevant, changes constantly) -pub const APPROVALS_OF: &[u8] = b"cou:apr:"; // Vec<bool> -pub const REGISTER_INFO_OF: &[u8] = b"cou:reg:"; // Candidate -> (VoteIndex, u32) -pub const LAST_ACTIVE_OF: &[u8] = b"cou:lac:"; // Voter -> VoteIndex -pub const VOTERS: &[u8] = b"cou:vrs"; // Vec<AccountId> -pub const CANDIDATES: &[u8] = b"cou:can"; // Vec<AccountId>, has holes -pub const CANDIDATE_COUNT: &[u8] = b"cou:cnc"; // u32 - -// temporary state (only relevant during finalisation/presentation) -pub const NEXT_FINALISE: &[u8] = b"cou:nxt"; -pub const SNAPSHOTED_STAKES: &[u8] = b"cou:sss"; // Vec<Balance> -pub const LEADERBOARD: &[u8] = b"cou:win"; // Vec<(Balance, AccountId)> ORDERED low -> high - -/// How much should be locked up in order to submit one's candidacy. -pub fn candidacy_bond() -> Balance { - storage::get(CANDIDACY_BOND) - .expect("all core parameters of council module must be in place") -} - -/// How much should be locked up in order to be able to submit votes. -pub fn voting_bond() -> Balance { - storage::get(VOTING_BOND) - .expect("all core parameters of council module must be in place") -} - -/// How long to give each top candidate to present themselves after the vote ends. -pub fn presentation_duration() -> BlockNumber { - storage::get(PRESENTATION_DURATION) - .expect("all core parameters of council module must be in place") -} - -/// How often (in blocks) to check for new votes. -pub fn voting_period() -> BlockNumber { - storage::get(VOTING_PERIOD) - .expect("all core parameters of council module must be in place") -} - -/// How many votes need to go by after a voter's last vote before they can be reaped if their -/// approvals are moot. -pub fn inactivity_grace_period() -> VoteIndex { - storage::get(INACTIVE_GRACE_PERIOD) - .expect("all core parameters of council module must be in place") -} - -/// How long each position is active for. -pub fn term_duration() -> BlockNumber { - storage::get(TERM_DURATION) - .expect("all core parameters of council module must be in place") -} - -/// The punishment, per voter, if you provide an invalid presentation. -pub fn present_slash_per_voter() -> Balance { - storage::get(PRESENT_SLASH_PER_VOTER) - .expect("all core parameters of council module must be in place") -} - -/// Number of accounts that should be sitting on the council. -pub fn desired_seats() -> u32 { - storage::get(DESIRED_SEATS) - .expect("all core parameters of council module must be in place") -} - -/// How many runners-up should have their approvals persist until the next vote. -pub fn carry_count() -> u32 { - storage::get(CARRY_COUNT) - .expect("all core parameters of council module must be in place") +storage_items! { + // parameters + // How much should be locked up in order to submit one's candidacy. + pub CandidacyBond get(candidacy_bond): b"cou:cbo" => required Balance; + // How much should be locked up in order to be able to submit votes. + pub VotingBond get(voting_bond): b"cou:vbo" => required Balance; + // The punishment, per voter, if you provide an invalid presentation. + pub PresentSlashPerVoter get(present_slash_per_voter): b"cou:pss" => required Balance; + // How many runners-up should have their approvals persist until the next vote. + pub CarryCount get(carry_count): b"cou:cco" => required u32; + // How long to give each top candidate to present themselves after the vote ends. + pub PresentationDuration get(presentation_duration): b"cou:pdu" => required BlockNumber; + // How many votes need to go by after a voter's last vote before they can be reaped if their + // approvals are moot. + pub InactiveGracePeriod get(inactivity_grace_period): b"cou:vgp" => required VoteIndex; + // How often (in blocks) to check for new votes. + pub VotingPeriod get(voting_period): b"cou:per" => required BlockNumber; + // How long each position is active for. + pub TermDuration get(term_duration): b"cou:trm" => required BlockNumber; + // Number of accounts that should be sitting on the council. + pub DesiredSeats get(desired_seats): b"cou:sts" => required u32; + + // permanent state (always relevant, changes only at the finalisation of voting) + // The current council. When there's a vote going on, this should still be used for executive + // matters. + pub ActiveCouncil get(active_council): b"cou:act" => default Vec<(AccountId, BlockNumber)>; + // The total number of votes that have happened or are in progress. + pub VoteCount get(vote_index): b"cou:vco" => default VoteIndex; + + // persistent state (always relevant, changes constantly) + // The last cleared vote index that this voter was last active at. + pub ApprovalsOf get(approvals_of): b"cou:apr" => default map [ AccountId => Vec<bool> ]; + // The vote index and list slot that the candidate `who` was registered or `None` if they are not + // currently registered. + pub RegisterInfoOf get(candidate_reg_info): b"cou:reg" => map [ AccountId => (VoteIndex, u32) ]; + // The last cleared vote index that this voter was last active at. + pub LastActiveOf get(voter_last_active): b"cou:lac" => map [ AccountId => VoteIndex ]; + // The present voter list. + pub Voters get(voters): b"cou:vrs" => default Vec<AccountId>; + // The present candidate list. + pub Candidates get(candidates): b"cou:can" => default Vec<AccountId>; // has holes + pub CandidateCount get(candidate_count): b"cou:cnc" => default u32; + + // temporary state (only relevant during finalisation/presentation) + // The accounts holding the seats that will become free on the next tally. + pub NextFinalise get(next_finalise): b"cou:nxt" => (BlockNumber, u32, Vec<AccountId>); + // The stakes as they were at the point that the vote ended. + pub SnapshotedStakes get(snapshoted_stakes): b"cou:sss" => required Vec<Balance>; + // Get the leaderboard if we;re in the presentation phase. + pub Leaderboard get(leaderboard): b"cou:win" => Vec<(Balance, AccountId)>; // ORDERED low -> high } /// True if we're currently in a presentation period. pub fn presentation_active() -> bool { - storage::exists(NEXT_FINALISE) -} - -/// The current council. When there's a vote going on, this should still be used for executive -/// matters. -pub fn active_council() -> Vec<(AccountId, BlockNumber)> { - storage::get_or_default(ACTIVE_COUNCIL) + NextFinalise::exists() } /// If `who` a candidate at the moment? pub fn is_a_candidate(who: &AccountId) -> bool { - storage::exists(&who.to_keyed_vec(REGISTER_INFO_OF)) + RegisterInfoOf::exists(who) } /// Determine the block that a vote can happen on which is no less than `n`. @@ -215,47 +178,6 @@ pub fn next_tally() -> Option<BlockNumber> { } } -/// The accounts holding the seats that will become free on the next tally. -pub fn next_finalise() -> Option<(BlockNumber, u32, Vec<AccountId>)> { - storage::get(NEXT_FINALISE) -} - -/// The total number of votes that have happened or are in progress. -pub fn vote_index() -> VoteIndex { - storage::get_or_default(VOTE_COUNT) -} - -/// The present candidate list. -pub fn candidates() -> Vec<AccountId> { - storage::get_or_default(CANDIDATES) -} - -/// The present voter list. -pub fn voters() -> Vec<AccountId> { - storage::get_or_default(VOTERS) -} - -/// The vote index and list slot that the candidate `who` was registered or `None` if they are not -/// currently registered. -pub fn candidate_reg_info(who: &AccountId) -> Option<(VoteIndex, u32)> { - storage::get(&who.to_keyed_vec(REGISTER_INFO_OF)) -} - -/// The last cleared vote index that this voter was last active at. -pub fn voter_last_active(voter: &AccountId) -> Option<VoteIndex> { - storage::get(&voter.to_keyed_vec(LAST_ACTIVE_OF)) -} - -/// The last cleared vote index that this voter was last active at. -pub fn approvals_of(voter: &AccountId) -> Vec<bool> { - storage::get_or_default(&voter.to_keyed_vec(APPROVALS_OF)) -} - -/// Get the leaderboard if we;re in the presentation phase. -pub fn leaderboard() -> Option<Vec<(Balance, AccountId)>> { - storage::get(LEADERBOARD) -} - impl_dispatch! { pub mod public; fn set_approvals(votes: Vec<bool>, index: VoteIndex) = 0; @@ -271,17 +193,17 @@ impl<'a> public::Dispatch for PublicPass<'a> { fn set_approvals(self, votes: Vec<bool>, index: VoteIndex) { assert!(!presentation_active()); assert_eq!(index, vote_index()); - if !storage::exists(&self.to_keyed_vec(LAST_ACTIVE_OF)) { + if !LastActiveOf::exists(*self) { // not yet a voter - deduct bond. staking::internal::reserve_balance(&self, voting_bond()); - storage::put(VOTERS, &{ - let mut v: Vec<AccountId> = storage::get_or_default(VOTERS); + Voters::put({ + let mut v = Voters::get(); v.push(self.clone()); v }); } - storage::put(&self.to_keyed_vec(APPROVALS_OF), &votes); - storage::put(&self.to_keyed_vec(LAST_ACTIVE_OF), &index); + ApprovalsOf::insert(*self, votes); + LastActiveOf::insert(*self, index); } /// Remove a voter. For it not to be a bond-consuming no-op, all approved candidate indices @@ -291,7 +213,7 @@ impl<'a> public::Dispatch for PublicPass<'a> { /// May be called by anyone. Returns the voter deposit to `signed`. fn reap_inactive_voter(self, signed_index: u32, who: AccountId, who_index: u32, assumed_vote_index: VoteIndex) { assert!(!presentation_active(), "cannot reap during presentation period"); - assert!(voter_last_active(&self).is_some(), "reaper must be a voter"); + assert!(voter_last_active(*self).is_some(), "reaper must be a voter"); let last_active = voter_last_active(&who).expect("target for inactivity cleanup must be active"); assert!(assumed_vote_index == vote_index(), "vote index not current"); assert!(last_active < assumed_vote_index - inactivity_grace_period(), "cannot reap during grace perid"); @@ -326,7 +248,7 @@ impl<'a> public::Dispatch for PublicPass<'a> { /// Remove a voter. All votes are cancelled and the voter deposit is returned. fn retract_voter(self, index: u32) { assert!(!presentation_active(), "cannot retract when presenting"); - assert!(storage::exists(&self.to_keyed_vec(LAST_ACTIVE_OF)), "cannot retract non-voter"); + assert!(LastActiveOf::exists(*self), "cannot retract non-voter"); let voters = voters(); let index = index as usize; assert!(index < voters.len(), "retraction index invalid"); @@ -343,8 +265,8 @@ impl<'a> public::Dispatch for PublicPass<'a> { assert!(staking::internal::deduct_unbonded(&self, candidacy_bond()), "candidate has not enough funds"); let slot = slot as usize; - let count = storage::get_or_default::<u32>(CANDIDATE_COUNT) as usize; - let candidates: Vec<AccountId> = storage::get_or_default(CANDIDATES); + let count = CandidateCount::get() as usize; + let candidates = Candidates::get(); assert!( (slot == count && count == candidates.len()) || (slot < candidates.len() && candidates[slot] == AccountId::default()), @@ -357,20 +279,20 @@ impl<'a> public::Dispatch for PublicPass<'a> { } else { candidates[slot] = self.clone(); } - storage::put(CANDIDATES, &candidates); - storage::put(CANDIDATE_COUNT, &(count as u32 + 1)); - storage::put(&self.to_keyed_vec(REGISTER_INFO_OF), &(vote_index(), slot)); + Candidates::put(candidates); + CandidateCount::put(count as u32 + 1); + RegisterInfoOf::insert(*self, (vote_index(), slot as u32)); } /// Claim that `signed` is one of the top carry_count() + current_vote().1 candidates. - /// Only works if the block number >= current_vote().0 and < current_vote().0 + presentation_duration() + /// Only works if the `block_number >= current_vote().0` and `< current_vote().0 + presentation_duration()`` /// `signed` should have at least fn present_winner(self, candidate: AccountId, total: Balance, index: VoteIndex) { assert_eq!(index, vote_index(), "index not current"); - let (_, _, expiring): (BlockNumber, u32, Vec<AccountId>) = storage::get(NEXT_FINALISE) + let (_, _, expiring) = NextFinalise::get() .expect("cannot present outside of presentation period"); - let stakes: Vec<Balance> = storage::get_or_default(SNAPSHOTED_STAKES); - let voters: Vec<AccountId> = storage::get_or_default(VOTERS); + let stakes = SnapshotedStakes::get(); + let voters = Voters::get(); let bad_presentation_punishment = present_slash_per_voter() * voters.len() as Balance; assert!(staking::can_slash(&self, bad_presentation_punishment), "presenter must have sufficient slashable funds"); @@ -382,14 +304,14 @@ impl<'a> public::Dispatch for PublicPass<'a> { } let (registered_since, candidate_index): (VoteIndex, u32) = - storage::get(&candidate.to_keyed_vec(REGISTER_INFO_OF)).expect("presented candidate must be current"); + RegisterInfoOf::get(candidate).expect("presented candidate must be current"); let actual_total = voters.iter() .zip(stakes.iter()) .filter_map(|(voter, stake)| match voter_last_active(voter) { Some(b) if b >= registered_since => approvals_of(voter).get(candidate_index as usize) - .and_then(|approved| if *approved { Some(stake) } else { None }), + .and_then(|approved| if *approved { Some(*stake) } else { None }), _ => None, }) .sum(); @@ -398,7 +320,7 @@ impl<'a> public::Dispatch for PublicPass<'a> { // insert into leaderboard leaderboard[0] = (total, candidate.clone()); leaderboard.sort_by_key(|&(t, _)| t); - storage::put(LEADERBOARD, &leaderboard); + Leaderboard::put(leaderboard); } else { staking::internal::slash(&self, bad_presentation_punishment); } @@ -418,7 +340,7 @@ impl privileged::Dispatch for PrivPass { /// election when they expire. If more, then a new vote will be started if one is not already /// in progress. fn set_desired_seats(self, count: u32) { - storage::put(DESIRED_SEATS, &count); + DesiredSeats::put(count); } /// Remove a particular member. A tally will happen instantly (if not already in a presentation @@ -429,19 +351,19 @@ impl privileged::Dispatch for PrivPass { .into_iter() .filter(|i| i.0 != who) .collect(); - storage::put(ACTIVE_COUNCIL, &new_council); + ActiveCouncil::put(new_council); } /// Set the presentation duration. If there is current a vote being presented for, will /// invoke `finalise_vote`. fn set_presentation_duration(self, count: BlockNumber) { - storage::put(PRESENTATION_DURATION, &count); + PresentationDuration::put(count); } /// Set the presentation duration. If there is current a vote being presented for, will /// invoke `finalise_vote`. fn set_term_duration(self, count: BlockNumber) { - storage::put(TERM_DURATION, &count); + TermDuration::put(count); } } @@ -468,9 +390,9 @@ pub mod internal { /// Remove a voter from the system. Trusts that voters()[index] != voter. fn remove_voter(voter: &AccountId, index: usize, mut voters: Vec<AccountId>) { - storage::put(VOTERS, &{ voters.swap_remove(index); voters }); - storage::kill(&voter.to_keyed_vec(APPROVALS_OF)); - storage::kill(&voter.to_keyed_vec(LAST_ACTIVE_OF)); + Voters::put({ voters.swap_remove(index); voters }); + ApprovalsOf::remove(voter); + LastActiveOf::remove(voter); } /// Close the voting, snapshot the staking and the number of seats that are actually up for grabs. @@ -478,18 +400,18 @@ fn start_tally() { let active_council = active_council(); let desired_seats = desired_seats() as usize; let number = system::block_number(); - let expiring = active_council.iter().take_while(|i| i.1 == number).cloned().collect::<Vec<_>>(); + let expiring = active_council.iter().take_while(|i| i.1 == number).map(|i| i.0).collect::<Vec<_>>(); if active_council.len() - expiring.len() < desired_seats { let empty_seats = desired_seats - (active_council.len() - expiring.len()); - storage::put(NEXT_FINALISE, &(number + presentation_duration(), empty_seats as u32, expiring)); + NextFinalise::put((number + presentation_duration(), empty_seats as u32, expiring)); - let voters: Vec<AccountId> = storage::get_or_default(VOTERS); - let votes: Vec<Balance> = voters.iter().map(staking::balance).collect(); - storage::put(SNAPSHOTED_STAKES, &votes); + let voters = Voters::get(); + let votes = voters.iter().map(staking::balance).collect::<Vec<_>>(); + SnapshotedStakes::put(votes); // initialise leaderboard. let leaderboard_size = empty_seats + carry_count() as usize; - storage::put(LEADERBOARD, &vec![(0 as Balance, AccountId::default()); leaderboard_size]); + Leaderboard::put(vec![(0 as Balance, AccountId::default()); leaderboard_size]); } } @@ -498,10 +420,10 @@ fn start_tally() { /// a new vote is started. /// Clears all presented candidates, returning the bond of the elected ones. fn finalise_tally() { - storage::kill(SNAPSHOTED_STAKES); - let (_, coming, expiring): (BlockNumber, u32, Vec<AccountId>) = storage::take(NEXT_FINALISE) + SnapshotedStakes::kill(); + let (_, coming, expiring): (BlockNumber, u32, Vec<AccountId>) = NextFinalise::take() .expect("finalise can only be called after a tally is started."); - let leaderboard: Vec<(Balance, AccountId)> = storage::take(LEADERBOARD).unwrap_or_default(); + let leaderboard: Vec<(Balance, AccountId)> = Leaderboard::take().unwrap_or_default(); let new_expiry = system::block_number() + term_duration(); // return bond to winners. @@ -526,10 +448,10 @@ fn finalise_tally() { .map(|(_, a)| (a, new_expiry))) .collect(); new_council.sort_by_key(|&(_, expiry)| expiry); - storage::put(ACTIVE_COUNCIL, &new_council); + ActiveCouncil::put(new_council); // clear all except runners-up from candidate list. - let candidates: Vec<AccountId> = storage::get_or_default(CANDIDATES); + let candidates = Candidates::get(); let mut new_candidates = vec![AccountId::default(); candidates.len()]; // shrink later. let runners_up = leaderboard.into_iter() .rev() @@ -544,16 +466,16 @@ fn finalise_tally() { for (old, new) in candidates.iter().zip(new_candidates.iter()) { if old != new { // removed - kill it - storage::kill(&old.to_keyed_vec(REGISTER_INFO_OF)); + RegisterInfoOf::remove(old); } } // discard any superfluous slots. if let Some(last_index) = new_candidates.iter().rposition(|c| *c != AccountId::default()) { new_candidates.truncate(last_index + 1); } - storage::put(CANDIDATES, &(new_candidates)); - storage::put(CANDIDATE_COUNT, &count); - storage::put(VOTE_COUNT, &(vote_index() + 1)); + Candidates::put(new_candidates); + CandidateCount::put(count); + VoteCount::put(vote_index() + 1); } #[cfg(test)] @@ -565,15 +487,15 @@ pub mod testing { pub fn externalities() -> TestExternalities { let extras: TestExternalities = map![ - twox_128(CANDIDACY_BOND).to_vec() => vec![].and(&9u64), - twox_128(VOTING_BOND).to_vec() => vec![].and(&3u64), - twox_128(PRESENT_SLASH_PER_VOTER).to_vec() => vec![].and(&1u64), - twox_128(CARRY_COUNT).to_vec() => vec![].and(&2u32), - twox_128(PRESENTATION_DURATION).to_vec() => vec![].and(&2u64), - twox_128(VOTING_PERIOD).to_vec() => vec![].and(&4u64), - twox_128(TERM_DURATION).to_vec() => vec![].and(&5u64), - twox_128(DESIRED_SEATS).to_vec() => vec![].and(&2u32), - twox_128(INACTIVE_GRACE_PERIOD).to_vec() => vec![].and(&1u32) + twox_128(CandidacyBond::key()).to_vec() => vec![].and(&9u64), + twox_128(VotingBond::key()).to_vec() => vec![].and(&3u64), + twox_128(PresentSlashPerVoter::key()).to_vec() => vec![].and(&1u64), + twox_128(CarryCount::key()).to_vec() => vec![].and(&2u32), + twox_128(PresentationDuration::key()).to_vec() => vec![].and(&2u64), + twox_128(VotingPeriod::key()).to_vec() => vec![].and(&4u64), + twox_128(TermDuration::key()).to_vec() => vec![].and(&5u64), + twox_128(DesiredSeats::key()).to_vec() => vec![].and(&2u32), + twox_128(InactiveGracePeriod::key()).to_vec() => vec![].and(&1u32) ]; democracy::testing::externalities() .into_iter().chain(extras.into_iter()).collect() @@ -621,11 +543,11 @@ mod tests { assert_eq!(candidates(), Vec::<AccountId>::new()); assert_eq!(is_a_candidate(&Alice), false); - assert_eq!(candidate_reg_info(&Alice), None); + assert_eq!(candidate_reg_info(*Alice), None); assert_eq!(voters(), Vec::<AccountId>::new()); - assert_eq!(voter_last_active(&Alice), None); - assert_eq!(approvals_of(&Alice), vec![]); + assert_eq!(voter_last_active(*Alice), None); + assert_eq!(approvals_of(*Alice), vec![]); }); } @@ -634,22 +556,22 @@ mod tests { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); assert_eq!(candidates(), Vec::<AccountId>::new()); - assert_eq!(candidate_reg_info(&Alice), None); - assert_eq!(candidate_reg_info(&Bob), None); + assert_eq!(candidate_reg_info(*Alice), None); + assert_eq!(candidate_reg_info(*Bob), None); assert_eq!(is_a_candidate(&Alice), false); assert_eq!(is_a_candidate(&Bob), false); PublicPass::test(&Alice).submit_candidacy(0); assert_eq!(candidates(), vec![Alice.to_raw_public()]); - assert_eq!(candidate_reg_info(&Alice), Some((0 as VoteIndex, 0u32))); - assert_eq!(candidate_reg_info(&Bob), None); + assert_eq!(candidate_reg_info(*Alice), Some((0 as VoteIndex, 0u32))); + assert_eq!(candidate_reg_info(*Bob), None); assert_eq!(is_a_candidate(&Alice), true); assert_eq!(is_a_candidate(&Bob), false); PublicPass::test(&Bob).submit_candidacy(1); assert_eq!(candidates(), vec![Alice.to_raw_public(), Bob.into()]); - assert_eq!(candidate_reg_info(&Alice), Some((0 as VoteIndex, 0u32))); - assert_eq!(candidate_reg_info(&Bob), Some((0 as VoteIndex, 1u32))); + assert_eq!(candidate_reg_info(*Alice), Some((0 as VoteIndex, 0u32))); + assert_eq!(candidate_reg_info(*Bob), Some((0 as VoteIndex, 1u32))); assert_eq!(is_a_candidate(&Alice), true); assert_eq!(is_a_candidate(&Bob), true); }); @@ -657,9 +579,9 @@ mod tests { fn new_test_ext_with_candidate_holes() -> TestExternalities { let mut t = new_test_ext(); - t.insert(twox_128(CANDIDATES).to_vec(), vec![].and(&vec![AccountId::default(), AccountId::default(), Alice.to_raw_public()])); - t.insert(twox_128(CANDIDATE_COUNT).to_vec(), vec![].and(&1u32)); - t.insert(twox_128(&Alice.to_raw_public().to_keyed_vec(REGISTER_INFO_OF)).to_vec(), vec![].and(&(0 as VoteIndex, 2u32))); + t.insert(twox_128(Candidates::key()).to_vec(), vec![].and(&vec![AccountId::default(), AccountId::default(), Alice.to_raw_public()])); + t.insert(twox_128(CandidateCount::key()).to_vec(), vec![].and(&1u32)); + t.insert(twox_128(&RegisterInfoOf::key_for(*Alice)).to_vec(), vec![].and(&(0 as VoteIndex, 2u32))); t } @@ -758,8 +680,8 @@ mod tests { PublicPass::test(&Alice).set_approvals(vec![true], 0); PublicPass::test(&Dave).set_approvals(vec![true], 0); - assert_eq!(approvals_of(&Alice), vec![true]); - assert_eq!(approvals_of(&Dave), vec![true]); + assert_eq!(approvals_of(*Alice), vec![true]); + assert_eq!(approvals_of(*Dave), vec![true]); assert_eq!(voters(), vec![Alice.to_raw_public(), Dave.into()]); PublicPass::test(&Bob).submit_candidacy(1); @@ -768,10 +690,10 @@ mod tests { PublicPass::test(&Bob).set_approvals(vec![false, true, true], 0); PublicPass::test(&Charlie).set_approvals(vec![false, true, true], 0); - assert_eq!(approvals_of(&Alice), vec![true]); - assert_eq!(approvals_of(&Dave), vec![true]); - assert_eq!(approvals_of(&Bob), vec![false, true, true]); - assert_eq!(approvals_of(&Charlie), vec![false, true, true]); + assert_eq!(approvals_of(*Alice), vec![true]); + assert_eq!(approvals_of(*Dave), vec![true]); + assert_eq!(approvals_of(*Bob), vec![false, true, true]); + assert_eq!(approvals_of(*Charlie), vec![false, true, true]); assert_eq!(voters(), vec![Alice.to_raw_public(), Dave.into(), Bob.into(), Charlie.into()]); }); @@ -785,13 +707,13 @@ mod tests { PublicPass::test(&Eve).submit_candidacy(0); PublicPass::test(&Dave).set_approvals(vec![true], 0); - assert_eq!(approvals_of(&Dave), vec![true]); + assert_eq!(approvals_of(*Dave), vec![true]); PublicPass::test(&Bob).submit_candidacy(1); PublicPass::test(&Charlie).submit_candidacy(2); PublicPass::test(&Dave).set_approvals(vec![true, false, true], 0); - assert_eq!(approvals_of(&Dave), vec![true, false, true]); + assert_eq!(approvals_of(*Dave), vec![true, false, true]); }); } @@ -810,34 +732,34 @@ mod tests { PublicPass::test(&Dave).set_approvals(vec![true, false, true], 0); assert_eq!(voters(), vec![Alice.to_raw_public(), Bob.into(), Charlie.into(), Dave.into()]); - assert_eq!(approvals_of(&Alice), vec![true]); - assert_eq!(approvals_of(&Bob), vec![false, true, true]); - assert_eq!(approvals_of(&Charlie), vec![false, true, true]); - assert_eq!(approvals_of(&Dave), vec![true, false, true]); + assert_eq!(approvals_of(*Alice), vec![true]); + assert_eq!(approvals_of(*Bob), vec![false, true, true]); + assert_eq!(approvals_of(*Charlie), vec![false, true, true]); + assert_eq!(approvals_of(*Dave), vec![true, false, true]); PublicPass::test(&Alice).retract_voter(0); assert_eq!(voters(), vec![Dave.to_raw_public(), Bob.into(), Charlie.into()]); - assert_eq!(approvals_of(&Alice), Vec::<bool>::new()); - assert_eq!(approvals_of(&Bob), vec![false, true, true]); - assert_eq!(approvals_of(&Charlie), vec![false, true, true]); - assert_eq!(approvals_of(&Dave), vec![true, false, true]); + assert_eq!(approvals_of(*Alice), Vec::<bool>::new()); + assert_eq!(approvals_of(*Bob), vec![false, true, true]); + assert_eq!(approvals_of(*Charlie), vec![false, true, true]); + assert_eq!(approvals_of(*Dave), vec![true, false, true]); PublicPass::test(&Bob).retract_voter(1); assert_eq!(voters(), vec![Dave.to_raw_public(), Charlie.into()]); - assert_eq!(approvals_of(&Alice), Vec::<bool>::new()); - assert_eq!(approvals_of(&Bob), Vec::<bool>::new()); - assert_eq!(approvals_of(&Charlie), vec![false, true, true]); - assert_eq!(approvals_of(&Dave), vec![true, false, true]); + assert_eq!(approvals_of(*Alice), Vec::<bool>::new()); + assert_eq!(approvals_of(*Bob), Vec::<bool>::new()); + assert_eq!(approvals_of(*Charlie), vec![false, true, true]); + assert_eq!(approvals_of(*Dave), vec![true, false, true]); PublicPass::test(&Charlie).retract_voter(1); assert_eq!(voters(), vec![Dave.to_raw_public()]); - assert_eq!(approvals_of(&Alice), Vec::<bool>::new()); - assert_eq!(approvals_of(&Bob), Vec::<bool>::new()); - assert_eq!(approvals_of(&Charlie), Vec::<bool>::new()); - assert_eq!(approvals_of(&Dave), vec![true, false, true]); + assert_eq!(approvals_of(*Alice), Vec::<bool>::new()); + assert_eq!(approvals_of(*Bob), Vec::<bool>::new()); + assert_eq!(approvals_of(*Charlie), Vec::<bool>::new()); + assert_eq!(approvals_of(*Dave), vec![true, false, true]); }); } @@ -901,8 +823,8 @@ mod tests { assert!(!is_a_candidate(&Bob)); assert!(!is_a_candidate(&Eve)); assert_eq!(vote_index(), 1); - assert_eq!(voter_last_active(&Bob), Some(0)); - assert_eq!(voter_last_active(&Eve), Some(0)); + assert_eq!(voter_last_active(*Bob), Some(0)); + assert_eq!(voter_last_active(*Eve), Some(0)); }); } @@ -957,7 +879,7 @@ mod tests { ); assert_eq!(voters(), vec![Eve.to_raw_public()]); - assert_eq!(approvals_of(&Bob).len(), 0); + assert_eq!(approvals_of(*Bob).len(), 0); assert_eq!(staking::balance(&Bob), 17); assert_eq!(staking::balance(&Eve), 53); }); @@ -1017,7 +939,7 @@ mod tests { ); assert_eq!(voters(), vec![Eve.to_raw_public()]); - assert_eq!(approvals_of(&Bob).len(), 0); + assert_eq!(approvals_of(*Bob).len(), 0); assert_eq!(staking::balance(&Bob), 17); assert_eq!(staking::balance(&Eve), 53); }); @@ -1120,7 +1042,7 @@ mod tests { ); assert_eq!(voters(), vec![Bob.to_raw_public(), Charlie.into(), Eve.into()]); - assert_eq!(approvals_of(&Dave).len(), 0); + assert_eq!(approvals_of(*Dave).len(), 0); assert_eq!(staking::balance(&Dave), 37); }); } @@ -1327,13 +1249,13 @@ mod tests { assert!(is_a_candidate(&Charlie)); assert!(is_a_candidate(&Dave)); assert_eq!(vote_index(), 1); - assert_eq!(voter_last_active(&Bob), Some(0)); - assert_eq!(voter_last_active(&Charlie), Some(0)); - assert_eq!(voter_last_active(&Dave), Some(0)); - assert_eq!(voter_last_active(&Eve), Some(0)); - assert_eq!(voter_last_active(&Ferdie), Some(0)); - assert_eq!(candidate_reg_info(&Charlie), Some((0, 2))); - assert_eq!(candidate_reg_info(&Dave), Some((0, 3))); + assert_eq!(voter_last_active(*Bob), Some(0)); + assert_eq!(voter_last_active(*Charlie), Some(0)); + assert_eq!(voter_last_active(*Dave), Some(0)); + assert_eq!(voter_last_active(*Eve), Some(0)); + assert_eq!(voter_last_active(*Ferdie), Some(0)); + assert_eq!(candidate_reg_info(*Charlie), Some((0, 2))); + assert_eq!(candidate_reg_info(*Dave), Some((0, 3))); }); } @@ -1379,13 +1301,13 @@ mod tests { assert!(!is_a_candidate(&Eve)); assert!(is_a_candidate(&Dave)); assert_eq!(vote_index(), 2); - assert_eq!(voter_last_active(&Bob), Some(0)); - assert_eq!(voter_last_active(&Charlie), Some(0)); - assert_eq!(voter_last_active(&Dave), Some(0)); - assert_eq!(voter_last_active(&Eve), Some(0)); - assert_eq!(voter_last_active(&Ferdie), Some(1)); + assert_eq!(voter_last_active(*Bob), Some(0)); + assert_eq!(voter_last_active(*Charlie), Some(0)); + assert_eq!(voter_last_active(*Dave), Some(0)); + assert_eq!(voter_last_active(*Eve), Some(0)); + assert_eq!(voter_last_active(*Ferdie), Some(1)); - assert_eq!(candidate_reg_info(&Dave), Some((0, 3))); + assert_eq!(candidate_reg_info(*Dave), Some((0, 3))); }); } } diff --git a/substrate/demo/runtime/src/runtime/council_vote.rs b/substrate/demo/runtime/src/runtime/council_vote.rs index 9b58c7eeb4f9a502df69d39b56620fbdfcdcecca..763a35f1d26838905c21da1ec2e56ec3d9784a90 100644 --- a/substrate/demo/runtime/src/runtime/council_vote.rs +++ b/substrate/demo/runtime/src/runtime/council_vote.rs @@ -17,9 +17,10 @@ //! Council voting system. use rstd::prelude::*; +use rstd::borrow::Borrow; use codec::{KeyedVec, Slicable, Input, NonTrivialSlicable}; use runtime_support::Hashable; -use runtime_support::storage; +use runtime_support::{StorageValue, StorageMap}; use demo_primitives::{AccountId, Hash, BlockNumber}; use runtime::{system, democracy, council}; use runtime::staking::{PublicPass, Balance}; @@ -28,43 +29,28 @@ use dispatch::PrivCall as Proposal; type ProposalHash = [u8; 32]; -pub const COOLOFF_PERIOD: &[u8] = b"cov:cooloff"; // BlockNumber -pub const VOTING_PERIOD: &[u8] = b"cov:period"; // BlockNumber - -pub const PROPOSALS: &[u8] = b"cov:prs"; // Vec<(expiry: BlockNumber, ProposalHash)> ordered by expiry. -pub const PROPOSAL_OF: &[u8] = b"cov:pro"; // ProposalHash -> Proposal -pub const PROPOSAL_VOTERS: &[u8] = b"cov:voters:"; // ProposalHash -> Vec<AccountId> -pub const COUNCIL_VOTE_OF: &[u8] = b"cov:vote:"; // (ProposalHash, AccountId) -> bool -pub const VETOED_PROPOSAL: &[u8] = b"cov:veto:"; // ProposalHash -> (BlockNumber, sorted_vetoers: Vec<AccountId>) - -pub fn cooloff_period() -> BlockNumber { - storage::get(COOLOFF_PERIOD).expect("all parameters must be defined") -} - -pub fn voting_period() -> BlockNumber { - storage::get(VOTING_PERIOD).expect("all parameters must be defined") -} - -pub fn proposals() -> Vec<(BlockNumber, ProposalHash)> { - storage::get_or_default(PROPOSALS) +storage_items! { + pub CooloffPeriod get(cooloff_period): b"cov:cooloff" => required BlockNumber; + pub VotingPeriod get(voting_period): b"cov:period" => required BlockNumber; + pub Proposals get(proposals): b"cov:prs" => default Vec<(BlockNumber, ProposalHash)>; // ordered by expiry. + pub ProposalOf get(proposal_of): b"cov:pro" => map [ ProposalHash => Proposal ]; + pub ProposalVoters get(proposal_voters): b"cov:voters:" => default map [ ProposalHash => Vec<AccountId> ]; + pub CouncilVoteOf get(vote_of): b"cov:vote:" => map [ (ProposalHash, AccountId) => bool ]; + pub VetoedProposal get(veto_of): b"cov:veto:" => map [ ProposalHash => (BlockNumber, Vec<AccountId>) ]; } -pub fn is_vetoed(proposal: &ProposalHash) -> bool { - storage::get(&proposal.to_keyed_vec(VETOED_PROPOSAL)) +pub fn is_vetoed<B: Borrow<ProposalHash>>(proposal: B) -> bool { + VetoedProposal::get(proposal.borrow()) .map(|(expiry, _): (BlockNumber, Vec<AccountId>)| system::block_number() < expiry) .unwrap_or(false) } -pub fn veto_of(proposal: &ProposalHash) -> Option<(BlockNumber, Vec<AccountId>)> { - storage::get(&proposal.to_keyed_vec(VETOED_PROPOSAL)) -} - fn set_veto_of(proposal: &ProposalHash, expiry: BlockNumber, vetoers: Vec<AccountId>) { - storage::put(&proposal.to_keyed_vec(VETOED_PROPOSAL), &(expiry, vetoers)) + VetoedProposal::insert(proposal, (expiry, vetoers)); } fn kill_veto_of(proposal: &ProposalHash) { - storage::kill(&proposal.to_keyed_vec(VETOED_PROPOSAL)) + VetoedProposal::remove(proposal); } pub fn will_still_be_councillor_at(who: &AccountId, n: BlockNumber) -> bool { @@ -79,20 +65,12 @@ pub fn is_councillor(who: &AccountId) -> bool { .any(|&(ref a, _)| a == who) } -pub fn vote_of(who: &AccountId, proposal: &ProposalHash) -> Option<bool> { - storage::get(&(*proposal, *who).to_keyed_vec(COUNCIL_VOTE_OF)) -} - -pub fn proposal_voters(proposal: &ProposalHash) -> Vec<AccountId> { - storage::get_or_default(&proposal.to_keyed_vec(PROPOSAL_VOTERS)) -} - pub fn tally(proposal_hash: &ProposalHash) -> (u32, u32, u32) { - generic_tally(proposal_hash, |w: &AccountId, p: &ProposalHash| storage::get(&(*p, *w).to_keyed_vec(COUNCIL_VOTE_OF))) + generic_tally(proposal_hash, |w: &AccountId, p: &ProposalHash| CouncilVoteOf::get((*p, *w))) } fn take_tally(proposal_hash: &ProposalHash) -> (u32, u32, u32) { - generic_tally(proposal_hash, |w: &AccountId, p: &ProposalHash| storage::get(&(*p, *w).to_keyed_vec(COUNCIL_VOTE_OF))) + generic_tally(proposal_hash, |w: &AccountId, p: &ProposalHash| CouncilVoteOf::take((*p, *w))) } fn generic_tally<F: Fn(&AccountId, &ProposalHash) -> Option<bool>>(proposal_hash: &ProposalHash, vote_of: F) -> (u32, u32, u32) { @@ -105,7 +83,7 @@ fn generic_tally<F: Fn(&AccountId, &ProposalHash) -> Option<bool>>(proposal_hash } fn set_proposals(p: &Vec<(BlockNumber, ProposalHash)>) { - storage::put(PROPOSALS, p) + Proposals::put(p); } fn take_proposal_if_expiring_at(n: BlockNumber) -> Option<(Proposal, ProposalHash)> { @@ -114,7 +92,7 @@ fn take_proposal_if_expiring_at(n: BlockNumber) -> Option<(Proposal, ProposalHas Some(&(expiry, hash)) if expiry == n => { // yes this is horrible, but fixing it will need substantial work in storage. set_proposals(&proposals[1..].to_vec()); - let proposal = storage::take(&hash.to_keyed_vec(PROPOSAL_OF)).expect("all queued proposal hashes must have associated proposals"); + let proposal = ProposalOf::take(hash).expect("all queued proposal hashes must have associated proposals"); Some((proposal, hash)) } _ => None, @@ -142,23 +120,23 @@ impl<'a> public::Dispatch for PublicPass<'a> { proposals.sort_by_key(|&(expiry, _)| expiry); set_proposals(&proposals); - storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_OF), &proposal); - storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS), &vec![*self]); - storage::put(&(proposal_hash, *self).to_keyed_vec(COUNCIL_VOTE_OF), &true); + ProposalOf::insert(proposal_hash, *proposal); + ProposalVoters::insert(proposal_hash, vec![*self]); + CouncilVoteOf::insert((proposal_hash, *self), true); } fn vote(self, proposal: ProposalHash, approve: bool) { - if vote_of(&self, &proposal).is_none() { + if vote_of((*self, proposal)).is_none() { let mut voters = proposal_voters(&proposal); voters.push(*self); - storage::put(&proposal.to_keyed_vec(PROPOSAL_VOTERS), &voters); + ProposalVoters::insert(proposal, voters); } - storage::put(&(proposal, *self).to_keyed_vec(COUNCIL_VOTE_OF), &approve); + CouncilVoteOf::insert((proposal, *self), approve); } fn veto(self, proposal_hash: ProposalHash) { assert!(is_councillor(&self), "only councillors may veto council proposals"); - assert!(storage::exists(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS)), "proposal must exist to be vetoed"); + assert!(ProposalVoters::exists(&proposal_hash), "proposal must exist to be vetoed"); let mut existing_vetoers = veto_of(&proposal_hash) .map(|pair| pair.1) @@ -169,10 +147,10 @@ impl<'a> public::Dispatch for PublicPass<'a> { set_veto_of(&proposal_hash, system::block_number() + cooloff_period(), existing_vetoers); set_proposals(&proposals().into_iter().filter(|&(_, h)| h != proposal_hash).collect::<Vec<_>>()); - storage::kill(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS)); - storage::kill(&proposal_hash.to_keyed_vec(PROPOSAL_OF)); + ProposalVoters::remove(proposal_hash); + ProposalOf::remove(proposal_hash); for (c, _) in council::active_council() { - storage::kill(&(proposal_hash, c).to_keyed_vec(COUNCIL_VOTE_OF)); + CouncilVoteOf::remove((proposal_hash, c)); } } } @@ -185,11 +163,11 @@ impl_dispatch! { impl privileged::Dispatch for PrivPass { fn set_cooloff_period(self, blocks: BlockNumber) { - storage::put(COOLOFF_PERIOD, &blocks); + CooloffPeriod::put(blocks); } fn set_voting_period(self, blocks: BlockNumber) { - storage::put(VOTING_PERIOD, &blocks); + VotingPeriod::put(blocks); } } @@ -230,14 +208,14 @@ pub mod testing { pub fn externalities() -> TestExternalities { let expiry: BlockNumber = 10; let extras: TestExternalities = map![ - twox_128(council::ACTIVE_COUNCIL).to_vec() => vec![].and(&vec![ + twox_128(council::ActiveCouncil::key()).to_vec() => vec![].and(&vec![ (Alice.to_raw_public(), expiry), (Bob.into(), expiry), (Charlie.into(), expiry) ]), - twox_128(COOLOFF_PERIOD).to_vec() => vec![].and(&2u64), - twox_128(VOTING_PERIOD).to_vec() => vec![].and(&1u64), - twox_128(democracy::VOTING_PERIOD).to_vec() => vec![].and(&3u64) + twox_128(CooloffPeriod::key()).to_vec() => vec![].and(&2u64), + twox_128(VotingPeriod::key()).to_vec() => vec![].and(&1u64), + twox_128(democracy::VotingPeriod::key()).to_vec() => vec![].and(&3u64) ]; council::testing::externalities() .into_iter().chain(extras.into_iter()).collect() @@ -274,9 +252,9 @@ mod tests { assert_eq!(is_councillor(&Alice), true); assert_eq!(is_councillor(&Dave), false); assert_eq!(proposals(), Vec::<(BlockNumber, ProposalHash)>::new()); - assert_eq!(proposal_voters(&ProposalHash::default()), Vec::<AccountId>::new()); + assert_eq!(proposal_voters(ProposalHash::default()), Vec::<AccountId>::new()); assert_eq!(is_vetoed(&ProposalHash::default()), false); - assert_eq!(vote_of(&Alice, &ProposalHash::default()), None); + assert_eq!(vote_of((*Alice, ProposalHash::default())), None); assert_eq!(tally(&ProposalHash::default()), (0, 0, 3)); }); } @@ -447,7 +425,7 @@ mod tests { PublicPass::new(&Alice).propose(Box::new(proposal.clone())); assert_eq!(proposals().len(), 1); assert_eq!(proposal_voters(&hash), vec![Alice.to_raw_public()]); - assert_eq!(vote_of(&Alice, &hash), Some(true)); + assert_eq!(vote_of((hash, *Alice)), Some(true)); assert_eq!(tally(&hash), (1, 0, 2)); }); } diff --git a/substrate/demo/runtime/src/runtime/democracy.rs b/substrate/demo/runtime/src/runtime/democracy.rs index ea945245e70e454a5e7e45413c56ed57f0e023c1..7146a05833901380b19b60d20c3e9fafe20169d3 100644 --- a/substrate/demo/runtime/src/runtime/democracy.rs +++ b/substrate/demo/runtime/src/runtime/democracy.rs @@ -19,7 +19,7 @@ use rstd::prelude::*; use integer_sqrt::IntegerSquareRoot; use codec::{KeyedVec, Slicable, Input, NonTrivialSlicable}; -use runtime_support::storage; +use runtime_support::{StorageValue, StorageMap}; use demo_primitives::{AccountId, Hash, BlockNumber}; use dispatch::PrivCall as Proposal; use runtime::{staking, system, session}; @@ -95,48 +95,36 @@ impl Approved for VoteThreshold { } } -// public proposals -pub const PUBLIC_PROP_COUNT: &[u8] = b"dem:ppc"; // PropIndex -pub const PUBLIC_PROPS: &[u8] = b"dem:pub"; // Vec<(PropIndex, Proposal)> -pub const DEPOSIT_OF: &[u8] = b"dem:dep:"; // PropIndex -> (Balance, Vec<AccountId>) -pub const LAUNCH_PERIOD: &[u8] = b"dem:lau"; // BlockNumber -pub const MINIMUM_DEPOSIT: &[u8] = b"dem:min"; // Balance - -// referenda -pub const VOTING_PERIOD: &[u8] = b"dem:per"; // BlockNumber -pub const REFERENDUM_COUNT: &[u8] = b"dem:rco"; // ReferendumIndex -pub const NEXT_TALLY: &[u8] = b"dem:nxt"; // ReferendumIndex -pub const REFERENDUM_INFO_OF: &[u8] = b"dem:pro:"; // ReferendumIndex -> (BlockNumber, Proposal, VoteThreshold) -pub const VOTERS_FOR: &[u8] = b"dem:vtr:"; // ReferendumIndex -> Vec<AccountId> -pub const VOTE_OF: &[u8] = b"dem:vot:"; // (ReferendumIndex, AccountId) -> bool - -/// The minimum amount to be used as a deposit for a public referendum proposal. -pub fn minimum_deposit() -> Balance { - storage::get(MINIMUM_DEPOSIT) - .expect("all core parameters of council module must be in place") -} - -/// How often (in blocks) to check for new votes. -pub fn voting_period() -> BlockNumber { - storage::get(VOTING_PERIOD) - .expect("all core parameters of council module must be in place") -} - -/// How often (in blocks) new public referenda are launched. -pub fn launch_period() -> BlockNumber { - storage::get(LAUNCH_PERIOD) - .expect("all core parameters of council module must be in place") +storage_items! { + // The number of (public) proposals that have been made so far. + pub PublicPropCount get(public_prop_count): b"dem:ppc" => default PropIndex; + // The public proposals. Unsorted. + pub PublicProps get(public_props): b"dem:pub" => default Vec<(PropIndex, Proposal, AccountId)>; + // Those who have locked a deposit. + pub DepositOf get(deposit_lockers): b"dem:dep:" => map [ PropIndex => (Balance, Vec<AccountId>) ]; + // How often (in blocks) new public referenda are launched. + pub LaunchPeriod get(launch_period): b"dem:lau" => required BlockNumber; + // The minimum amount to be used as a deposit for a public referendum proposal. + pub MinimumDeposit get(minimum_deposit): b"dem:min" => required Balance; + + // How often (in blocks) to check for new votes. + pub VotingPeriod get(voting_period): b"dem:per" => required BlockNumber; + + // The next free referendum index, aka the number of referendums started so far. + pub ReferendumCount get(next_free_ref_index): b"dem:rco" => default ReferendumIndex; + // The next referendum index that should be tallied. + pub NextTally get(next_tally): b"dem:nxt" => default ReferendumIndex; + // Information concerning any given referendum. + pub ReferendumInfoOf get(referendum_info): b"dem:pro:" => map [ ReferendumIndex => (BlockNumber, Proposal, VoteThreshold) ]; + + // Get the voters for the current proposal. + pub VotersFor get(voters_for): b"dem:vtr:" => default map [ ReferendumIndex => Vec<AccountId> ]; + + // Get the vote, if Some, of `who`. + pub VoteOf get(vote_of): b"dem:vot:" => map [ (ReferendumIndex, AccountId) => bool ]; } -/// The public proposals. Unsorted. -pub fn public_props() -> Vec<(PropIndex, Proposal, AccountId)> { - storage::get_or_default(PUBLIC_PROPS) -} - -/// Those who have locked a deposit. -pub fn deposit_lockers(proposal: PropIndex) -> Option<(Balance, Vec<AccountId>)> { - storage::get(&proposal.to_keyed_vec(DEPOSIT_OF)) -} +// public proposals /// Get the amount locked in support of `proposal`; false if proposal isn't a valid proposal /// index. @@ -146,28 +134,13 @@ pub fn locked_for(proposal: PropIndex) -> Option<Balance> { /// Return true if `ref_index` is an on-going referendum. pub fn is_active_referendum(ref_index: ReferendumIndex) -> bool { - storage::exists(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF)) -} - -/// Get the voters for the current proposal. -pub fn voters_for(ref_index: ReferendumIndex) -> Vec<AccountId> { - storage::get_or_default(&ref_index.to_keyed_vec(VOTERS_FOR)) -} - -/// Get the vote, if Some, of `who`. -pub fn vote_of(who: &AccountId, ref_index: ReferendumIndex) -> Option<bool> { - storage::get(&(*who, ref_index).to_keyed_vec(VOTE_OF)) -} - -/// Get the info concerning the next referendum. -pub fn referendum_info(ref_index: ReferendumIndex) -> Option<(BlockNumber, Proposal, VoteThreshold)> { - storage::get(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF)) + ReferendumInfoOf::exists(ref_index) } /// Get all referendums currently active. pub fn active_referendums() -> Vec<(ReferendumIndex, BlockNumber, Proposal, VoteThreshold)> { - let next: ReferendumIndex = storage::get_or_default(NEXT_TALLY); - let last: ReferendumIndex = storage::get_or_default(REFERENDUM_COUNT); + let next = NextTally::get(); + let last = ReferendumCount::get(); (next..last).into_iter() .filter_map(|i| referendum_info(i).map(|(n, p, t)| (i, n, p, t))) .collect() @@ -175,8 +148,8 @@ pub fn active_referendums() -> Vec<(ReferendumIndex, BlockNumber, Proposal, Vote /// Get all referendums ready for tally at block `n`. pub fn maturing_referendums_at(n: BlockNumber) -> Vec<(ReferendumIndex, BlockNumber, Proposal, VoteThreshold)> { - let next: ReferendumIndex = storage::get_or_default(NEXT_TALLY); - let last: ReferendumIndex = storage::get_or_default(REFERENDUM_COUNT); + let next = NextTally::get(); + let last = ReferendumCount::get(); (next..last).into_iter() .filter_map(|i| referendum_info(i).map(|(n, p, t)| (i, n, p, t))) .take_while(|&(_, block_number, _, _)| block_number == n) @@ -186,16 +159,11 @@ pub fn maturing_referendums_at(n: BlockNumber) -> Vec<(ReferendumIndex, BlockNum /// Get the voters for the current proposal. pub fn tally(ref_index: ReferendumIndex) -> (staking::Balance, staking::Balance) { voters_for(ref_index).iter() - .map(|a| (staking::balance(a), vote_of(a, ref_index).expect("all items come from `voters`; for an item to be in `voters` there must be a vote registered; qed"))) + .map(|a| (staking::balance(a), vote_of((ref_index, *a)).expect("all items come from `voters`; for an item to be in `voters` there must be a vote registered; qed"))) .map(|(bal, vote)| if vote { (bal, 0) } else { (0, bal) }) .fold((0, 0), |(a, b), (c, d)| (a + c, b + d)) } -/// Get the next free referendum index, aka the number of referendums started so far. -pub fn next_free_ref_index() -> ReferendumIndex { - storage::get_or_default(REFERENDUM_COUNT) -} - impl_dispatch! { pub mod public; fn propose(proposal: Box<Proposal>, value: Balance) = 0; @@ -209,24 +177,22 @@ impl<'a> public::Dispatch for PublicPass<'a> { assert!(value >= minimum_deposit()); assert!(staking::internal::deduct_unbonded(&self, value)); - let index: PropIndex = storage::get_or_default(PUBLIC_PROP_COUNT); - storage::put(PUBLIC_PROP_COUNT, &(index + 1)); - storage::put(&index.to_keyed_vec(DEPOSIT_OF), &(value, vec![*self])); + let index = PublicPropCount::get(); + PublicPropCount::put(index + 1); + DepositOf::insert(index, (value, vec![*self])); let mut props = public_props(); props.push((index, (*proposal).clone(), *self)); - storage::put(PUBLIC_PROPS, &props); + PublicProps::put(props); } /// Propose a sensitive action to be taken. fn second(self, proposal: PropIndex) { - let key = proposal.to_keyed_vec(DEPOSIT_OF); - let mut deposit: (Balance, Vec<AccountId>) = - storage::get(&key).expect("can only second an existing proposal"); + let mut deposit = DepositOf::get(proposal).expect("can only second an existing proposal"); assert!(staking::internal::deduct_unbonded(&self, deposit.0)); deposit.1.push(*self); - storage::put(&key, &deposit); + DepositOf::insert(proposal, deposit); } /// Vote in a referendum. If `approve_proposal` is true, the vote is to enact the proposal; @@ -238,13 +204,12 @@ impl<'a> public::Dispatch for PublicPass<'a> { if staking::balance(&self) == 0 { panic!("transactor must have balance to signal approval."); } - let key = (*self, ref_index).to_keyed_vec(VOTE_OF); - if !storage::exists(&key) { + if !VoteOf::exists(&(ref_index, *self)) { let mut voters = voters_for(ref_index); voters.push(self.clone()); - storage::put(&ref_index.to_keyed_vec(VOTERS_FOR), &voters); + VotersFor::insert(ref_index, voters); } - storage::put(&key, &approve_proposal); + VoteOf::insert(&(ref_index, *self), approve_proposal); } } @@ -291,13 +256,12 @@ pub mod internal { { let (prop_index, proposal, _) = public_props.swap_remove(winner_index); let (deposit, depositors): (Balance, Vec<AccountId>) = - storage::take(&prop_index.to_keyed_vec(DEPOSIT_OF)) - .expect("depositors always exist for current proposals"); + DepositOf::take(prop_index).expect("depositors always exist for current proposals"); // refund depositors for d in &depositors { staking::internal::refund(d, deposit); } - storage::put(PUBLIC_PROPS, &public_props); + PublicProps::put(public_props); inject_referendum(now + voting_period(), proposal, VoteThreshold::SuperMajorityApprove); } } @@ -310,7 +274,7 @@ pub mod internal { if vote_threshold.approved(approve, against, total_stake) { proposal.dispatch(PrivPass::new()); } - storage::put(NEXT_TALLY, &(index + 1)); + NextTally::put(index + 1); } } } @@ -326,17 +290,17 @@ fn inject_referendum( panic!("Cannot inject a referendum that ends earlier than preceeding referendum"); } - storage::put(REFERENDUM_COUNT, &(ref_index + 1)); - storage::put(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF), &(end, proposal, vote_threshold)); + ReferendumCount::put(ref_index + 1); + ReferendumInfoOf::insert(ref_index, (end, proposal, vote_threshold)); ref_index } /// Remove all info on a referendum. fn clear_referendum(ref_index: ReferendumIndex) { - storage::kill(&ref_index.to_keyed_vec(REFERENDUM_INFO_OF)); - storage::kill(&ref_index.to_keyed_vec(VOTERS_FOR)); + ReferendumInfoOf::remove(ref_index); + VotersFor::remove(ref_index); for v in voters_for(ref_index) { - storage::kill(&(v, ref_index).to_keyed_vec(VOTE_OF)); + VoteOf::remove((ref_index, v)); } } @@ -344,37 +308,36 @@ fn clear_referendum(ref_index: ReferendumIndex) { pub mod testing { use super::*; use runtime_io::{twox_128, TestExternalities}; + use runtime_support::{StorageList, StorageValue, StorageMap}; use codec::Joiner; use keyring::Keyring::*; use runtime::{session, staking}; pub fn externalities() -> TestExternalities { map![ - twox_128(session::SESSION_LENGTH).to_vec() => vec![].and(&1u64), - twox_128(session::VALIDATOR_COUNT).to_vec() => vec![].and(&3u32), - twox_128(&0u32.to_keyed_vec(session::VALIDATOR_AT)).to_vec() => Alice.to_raw_public_vec(), - twox_128(&1u32.to_keyed_vec(session::VALIDATOR_AT)).to_vec() => Bob.to_raw_public_vec(), - twox_128(&2u32.to_keyed_vec(session::VALIDATOR_AT)).to_vec() => Charlie.to_raw_public_vec(), - twox_128(staking::INTENTION_COUNT).to_vec() => vec![].and(&3u32), - twox_128(&0u32.to_keyed_vec(staking::INTENTION_AT)).to_vec() => Alice.to_raw_public_vec(), - twox_128(&1u32.to_keyed_vec(staking::INTENTION_AT)).to_vec() => Bob.to_raw_public_vec(), - twox_128(&2u32.to_keyed_vec(staking::INTENTION_AT)).to_vec() => Charlie.to_raw_public_vec(), - twox_128(&Alice.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&10u64), - twox_128(&Bob.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&20u64), - twox_128(&Charlie.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&30u64), - twox_128(&Dave.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&40u64), - twox_128(&Eve.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&50u64), - twox_128(&Ferdie.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&60u64), - twox_128(&One.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![].and(&1u64), - twox_128(staking::TOTAL_STAKE).to_vec() => vec![].and(&210u64), - twox_128(staking::SESSIONS_PER_ERA).to_vec() => vec![].and(&1u64), - twox_128(staking::VALIDATOR_COUNT).to_vec() => vec![].and(&3u64), - twox_128(staking::CURRENT_ERA).to_vec() => vec![].and(&1u64), - twox_128(staking::TRANSACTION_FEE).to_vec() => vec![].and(&1u64), - - twox_128(LAUNCH_PERIOD).to_vec() => vec![].and(&1u64), - twox_128(VOTING_PERIOD).to_vec() => vec![].and(&1u64), - twox_128(MINIMUM_DEPOSIT).to_vec() => vec![].and(&1u64) + twox_128(session::SessionLength::key()).to_vec() => vec![].and(&1u64), + twox_128(session::Validators::key()).to_vec() => vec![].and(&vec![Alice.to_raw_public(), Bob.into(), Charlie.into()]), + twox_128(&staking::Intention::len_key()).to_vec() => vec![].and(&3u32), + twox_128(&staking::Intention::key_for(0)).to_vec() => Alice.to_raw_public_vec(), + twox_128(&staking::Intention::key_for(1)).to_vec() => Bob.to_raw_public_vec(), + twox_128(&staking::Intention::key_for(2)).to_vec() => Charlie.to_raw_public_vec(), + twox_128(&staking::FreeBalanceOf::key_for(*Alice)).to_vec() => vec![].and(&10u64), + twox_128(&staking::FreeBalanceOf::key_for(*Bob)).to_vec() => vec![].and(&20u64), + twox_128(&staking::FreeBalanceOf::key_for(*Charlie)).to_vec() => vec![].and(&30u64), + twox_128(&staking::FreeBalanceOf::key_for(*Dave)).to_vec() => vec![].and(&40u64), + twox_128(&staking::FreeBalanceOf::key_for(*Eve)).to_vec() => vec![].and(&50u64), + twox_128(&staking::FreeBalanceOf::key_for(*Ferdie)).to_vec() => vec![].and(&60u64), + twox_128(&staking::FreeBalanceOf::key_for(*One)).to_vec() => vec![].and(&1u64), + twox_128(staking::TotalStake::key()).to_vec() => vec![].and(&210u64), + twox_128(staking::SessionsPerEra::key()).to_vec() => vec![].and(&1u64), + twox_128(staking::ValidatorCount::key()).to_vec() => vec![].and(&3u64), + twox_128(staking::CurrentEra::key()).to_vec() => vec![].and(&1u64), + twox_128(staking::TransactionFee::key()).to_vec() => vec![].and(&1u64), + twox_128(staking::BondingDuration::key()).to_vec() => vec![].and(&0u64), + + twox_128(LaunchPeriod::key()).to_vec() => vec![].and(&1u64), + twox_128(VotingPeriod::key()).to_vec() => vec![].and(&1u64), + twox_128(MinimumDeposit::key()).to_vec() => vec![].and(&1u64) ] } } @@ -442,7 +405,7 @@ mod tests { assert_eq!(next_free_ref_index(), 1); assert_eq!(voters_for(r), vec![Alice.to_raw_public()]); - assert_eq!(vote_of(&Alice, r), Some(true)); + assert_eq!(vote_of((r, *Alice)), Some(true)); assert_eq!(tally(r), (10, 0)); democracy::internal::end_block(system::block_number()); @@ -557,7 +520,7 @@ mod tests { PublicPass::test(&Alice).vote(r, true); assert_eq!(voters_for(r), vec![Alice.to_raw_public()]); - assert_eq!(vote_of(&Alice, r), Some(true)); + assert_eq!(vote_of((r, *Alice)), Some(true)); assert_eq!(tally(r), (10, 0)); democracy::internal::end_block(system::block_number()); @@ -590,7 +553,7 @@ mod tests { PublicPass::test(&Alice).vote(r, false); assert_eq!(voters_for(r), vec![Alice.to_raw_public()]); - assert_eq!(vote_of(&Alice, r), Some(false)); + assert_eq!(vote_of((r, *Alice)), Some(false)); assert_eq!(tally(r), (0, 10)); democracy::internal::end_block(system::block_number()); diff --git a/substrate/demo/runtime/src/runtime/session.rs b/substrate/demo/runtime/src/runtime/session.rs index a0983c160801b1cb9f38dbc976f3406c8676b3be..f7fc68f83c6908e765163068d998b944f2c02727 100644 --- a/substrate/demo/runtime/src/runtime/session.rs +++ b/substrate/demo/runtime/src/runtime/session.rs @@ -19,49 +19,31 @@ use rstd::prelude::*; use codec::KeyedVec; -use runtime_support::{storage, StorageVec}; +use runtime_support::{storage, StorageValue, StorageMap}; use demo_primitives::{AccountId, SessionKey, BlockNumber}; use runtime::{system, staking, consensus}; use runtime::democracy::PrivPass; use runtime::staking::PublicPass; -pub const SESSION_LENGTH: &[u8] = b"ses:len"; -pub const CURRENT_INDEX: &[u8] = b"ses:ind"; -pub const LAST_LENGTH_CHANGE: &[u8] = b"ses:llc"; -pub const NEXT_KEY_FOR: &[u8] = b"ses:nxt:"; -pub const NEXT_SESSION_LENGTH: &[u8] = b"ses:nln"; -pub const VALIDATOR_AT: &[u8] = b"ses:val:"; -pub const VALIDATOR_COUNT: &[u8] = b"ses:val:len"; - -struct ValidatorStorageVec {} -impl StorageVec for ValidatorStorageVec { - type Item = AccountId; - const PREFIX: &'static[u8] = VALIDATOR_AT; -} - -/// Get the current set of validators. -pub fn validators() -> Vec<AccountId> { - ValidatorStorageVec::items() -} - -/// The number of blocks in each session. -pub fn length() -> BlockNumber { - storage::get_or(SESSION_LENGTH, 0) +storage_items!{ + // The current set of validators. + pub Validators get(validators): b"ses:val" => required Vec<AccountId>; + // Current length of the session. + pub SessionLength get(length): b"ses:len" => required BlockNumber; + // Current index of the session. + pub CurrentIndex get(current_index): b"ses:ind" => required BlockNumber; + + // Block at which the session length last changed. + LastLengthChange: b"ses:llc" => default BlockNumber; + // The next key for a given validator. + NextKeyFor: b"ses:nxt:" => map [ AccountId => SessionKey ]; + // The next session length. + NextSessionLength: b"ses:nln" => BlockNumber; } /// The number of validators currently. pub fn validator_count() -> u32 { - ValidatorStorageVec::count() as u32 -} - -/// The current era index. -pub fn current_index() -> BlockNumber { - storage::get_or(CURRENT_INDEX, 0) -} - -/// The block number at which the era length last changed. -pub fn last_length_change() -> BlockNumber { - storage::get_or(LAST_LENGTH_CHANGE, 0) + Validators::get().len() as u32 // TODO: can probably optimised } impl_dispatch! { @@ -74,7 +56,7 @@ impl<'a> public::Dispatch for PublicPass<'a> { /// session. fn set_key(self, key: SessionKey) { // set new value for next session - storage::put(&self.to_keyed_vec(NEXT_KEY_FOR), &key); + NextKeyFor::insert(*self, key) } } @@ -87,7 +69,7 @@ impl_dispatch! { impl privileged::Dispatch for PrivPass { /// Set a new era length. Won't kick in until the next era change (at current length). fn set_length(self, new: BlockNumber) { - storage::put(NEXT_SESSION_LENGTH, &new); + NextSessionLength::put(new); } /// Forces a new session. @@ -103,10 +85,10 @@ pub mod internal { /// Set the current set of validators. /// - /// Called by staking::next_era() only. `next_session` should be called after this in order to + /// Called by `staking::next_era()` only. `next_session` should be called after this in order to /// update the session keys to the next validator set. pub fn set_validators(new: &[AccountId]) { - ValidatorStorageVec::set_items(new); + Validators::put(&new.to_vec()); // TODO: optimise. consensus::internal::set_authorities(new); } @@ -115,7 +97,7 @@ pub mod internal { // do this last, after the staking system has had chance to switch out the authorities for the // new set. // check block number and call next_session if necessary. - if (system::block_number() - last_length_change()) % length() == 0 { + if (system::block_number() - LastLengthChange::get()) % length() == 0 { rotate_session(); } } @@ -123,19 +105,17 @@ pub mod internal { /// Move onto next session: register the new authority set. pub fn rotate_session() { // Increment current session index. - storage::put(CURRENT_INDEX, &(current_index() + 1)); + CurrentIndex::put(CurrentIndex::get() + 1); // Enact era length change. - if let Some(next_len) = storage::get::<u64>(NEXT_SESSION_LENGTH) { - storage::put(SESSION_LENGTH, &next_len); - storage::put(LAST_LENGTH_CHANGE, &system::block_number()); - storage::kill(NEXT_SESSION_LENGTH); + if let Some(next_len) = NextSessionLength::take() { + SessionLength::put(next_len); + LastLengthChange::put(system::block_number()); } // Update any changes in session keys. validators().iter().enumerate().for_each(|(i, v)| { - let k = v.to_keyed_vec(NEXT_KEY_FOR); - if let Some(n) = storage::take(&k) { + if let Some(n) = NextKeyFor::take(v) { consensus::internal::set_authority(i as u32, &n); } }); @@ -147,20 +127,16 @@ pub mod testing { use super::*; use runtime_io::{twox_128, TestExternalities}; use codec::{Joiner, KeyedVec}; - use keyring::Keyring; + use keyring::Keyring::*; use runtime::system; pub fn externalities(session_length: u64) -> TestExternalities { - let one = Keyring::One.to_raw_public(); - let two = Keyring::Two.to_raw_public(); let three = [3u8; 32]; let extras: TestExternalities = map![ - twox_128(SESSION_LENGTH).to_vec() => vec![].and(&session_length), - twox_128(VALIDATOR_COUNT).to_vec() => vec![].and(&3u32), - twox_128(&0u32.to_keyed_vec(VALIDATOR_AT)).to_vec() => one.to_vec(), - twox_128(&1u32.to_keyed_vec(VALIDATOR_AT)).to_vec() => two.to_vec(), - twox_128(&2u32.to_keyed_vec(VALIDATOR_AT)).to_vec() => three.to_vec() + twox_128(SessionLength::key()).to_vec() => vec![].and(&session_length), + twox_128(CurrentIndex::key()).to_vec() => vec![].and(&0u64), + twox_128(Validators::key()).to_vec() => vec![].and(&vec![One.into(), Two.into(), three]) ]; system::testing::externalities().into_iter().chain(extras.into_iter()).collect() } @@ -181,11 +157,10 @@ mod tests { fn simple_setup() -> TestExternalities { map![ - twox_128(SESSION_LENGTH).to_vec() => vec![].and(&2u64), + twox_128(SessionLength::key()).to_vec() => vec![].and(&2u64), + twox_128(CurrentIndex::key()).to_vec() => vec![].and(&0u64), // the validators (10, 20, ...) - twox_128(b"ses:val:len").to_vec() => vec![].and(&2u32), - twox_128(&0u32.to_keyed_vec(ValidatorStorageVec::PREFIX)).to_vec() => vec![10; 32], - twox_128(&1u32.to_keyed_vec(ValidatorStorageVec::PREFIX)).to_vec() => vec![20; 32], + twox_128(Validators::key()).to_vec() => vec![].and(&vec![[10u8; 32], [20; 32]]), // initial session keys (11, 21, ...) b":auth:len".to_vec() => vec![].and(&2u32), 0u32.to_keyed_vec(b":auth:") => vec![11; 32], diff --git a/substrate/demo/runtime/src/runtime/staking.rs b/substrate/demo/runtime/src/runtime/staking.rs index 629700503f9933f2b16960481241a689bbdd438a..f863e8d4242685de2a1710037d4e98700d6397a1 100644 --- a/substrate/demo/runtime/src/runtime/staking.rs +++ b/substrate/demo/runtime/src/runtime/staking.rs @@ -22,7 +22,7 @@ use rstd::cell::RefCell; use rstd::collections::btree_map::{BTreeMap, Entry}; use runtime_io::{print, blake2_256}; use codec::{Slicable, Input, KeyedVec}; -use runtime_support::{storage, StorageVec}; +use runtime_support::{storage, StorageValue, StorageList, StorageMap}; use demo_primitives::{BlockNumber, AccountId}; use runtime::{system, session, democracy}; @@ -32,78 +32,52 @@ pub type Balance = u64; /// The amount of bonding period left in an account. Measured in eras. pub type Bondage = u64; -pub const BONDING_DURATION: &[u8] = b"sta:loc"; -pub const VALIDATOR_COUNT: &[u8] = b"sta:vac"; -pub const SESSIONS_PER_ERA: &[u8] = b"sta:spe"; -pub const NEXT_SESSIONS_PER_ERA: &[u8] = b"sta:nse"; -pub const CURRENT_ERA: &[u8] = b"sta:era"; -pub const LAST_ERA_LENGTH_CHANGE: &[u8] = b"sta:lec"; -pub const TOTAL_STAKE: &[u8] = b"sta:tot"; -pub const INTENTION_AT: &[u8] = b"sta:wil:"; -pub const INTENTION_COUNT: &[u8] = b"sta:wil:len"; -pub const TRANSACTION_FEE: &[u8] = b"sta:fee"; - -pub const BALANCE_OF: &[u8] = b"sta:bal:"; -pub const RESERVED_BALANCE_OF: &[u8] = b"sta:lbo:"; -pub const BONDAGE_OF: &[u8] = b"sta:bon:"; -pub const CODE_OF: &[u8] = b"sta:cod:"; -pub const STORAGE_OF: &[u8] = b"sta:sto:"; - -pub struct IntentionStorageVec {} -impl StorageVec for IntentionStorageVec { - type Item = AccountId; - const PREFIX: &'static[u8] = INTENTION_AT; -} - -/// The fee to be paid for making a transaction. -pub fn transaction_fee() -> Balance { - storage::get(TRANSACTION_FEE).expect("All basic parameters should be defined") -} - -/// The length of the bonding duration in eras. -pub fn bonding_duration() -> BlockNumber { - storage::get_or_default(BONDING_DURATION) -} - -/// The length of a staking era in sessions. -pub fn validator_count() -> usize { - storage::get_or_default::<u32>(VALIDATOR_COUNT) as usize +storage_items! { + // The length of the bonding duration in eras. + pub BondingDuration get(bonding_duration): b"sta:loc" => required BlockNumber; + // The length of a staking era in sessions. + pub ValidatorCount get(validator_count): b"sta:vac" => required u32; + // The length of a staking era in sessions. + pub SessionsPerEra get(sessions_per_era): b"sta:spe" => required BlockNumber; + // The total amount of stake on the system. + pub TotalStake get(total_stake): b"sta:tot" => required Balance; + // The fee to be paid for making a transaction. + pub TransactionFee get(transaction_fee): b"sta:fee" => required Balance; + + // The current era index. + pub CurrentEra get(current_era): b"sta:era" => required BlockNumber; + // All the accounts with a desire to stake. + pub Intention: b"sta:wil:" => list [ AccountId ]; + // The next value of sessions per era. + pub NextSessionsPerEra get(next_sessions_per_era): b"sta:nse" => BlockNumber; + // The block number at which the era length last changed. + pub LastEraLengthChange get(last_era_length_change): b"sta:lec" => default BlockNumber; + + // The balance of a given account. + pub FreeBalanceOf get(free_balance_of): b"sta:bal:" => default map [ AccountId => Balance ]; + + // The amount of the balance of a given account that is exterally reserved; this can still get + // slashed, but gets slashed last of all. + pub ReservedBalanceOf get(reserved_balance_of): b"sta:lbo:" => default map [ AccountId => Balance ]; + + // The block at which the `who`'s funds become entirely liquid. + pub BondageOf get(bondage_of): b"sta:bon:" => default map [ AccountId => Bondage ]; + + // The code associated with an account. + pub CodeOf: b"sta:cod:" => default map [ AccountId => Vec<u8> ]; // TODO Vec<u8> values should be optimised to not do a length prefix. + + // The storage items associated with an account/key. + pub StorageOf: b"sta:sto:" => map [ (AccountId, Vec<u8>) => Vec<u8> ]; // TODO: keys should also be able to take AsRef<KeyType> to ensure Vec<u8>s can be passed as &[u8] } /// The length of a staking era in blocks. pub fn era_length() -> BlockNumber { - sessions_per_era() * session::length() + SessionsPerEra::get() * session::length() } -/// The length of a staking era in sessions. -pub fn sessions_per_era() -> BlockNumber { - storage::get_or_default(SESSIONS_PER_ERA) -} - -/// The current era index. -pub fn current_era() -> BlockNumber { - storage::get_or_default(CURRENT_ERA) -} - -/// The block number at which the era length last changed. -pub fn last_era_length_change() -> BlockNumber { - storage::get_or_default(LAST_ERA_LENGTH_CHANGE) -} - -/// The balance of a given account. +/// The combined balance of `who`. pub fn balance(who: &AccountId) -> Balance { - free_balance(who) + reserved_balance(who) -} - -/// The balance of a given account. -pub fn free_balance(who: &AccountId) -> Balance { - storage::get_or_default(&who.to_keyed_vec(BALANCE_OF)) -} - -/// The amount of the balance of a given account that is exterally reserved; this can still get -/// slashed, but gets slashed last of all. -pub fn reserved_balance(who: &AccountId) -> Balance { - storage::get_or_default(&who.to_keyed_vec(RESERVED_BALANCE_OF)) + FreeBalanceOf::get(who) + ReservedBalanceOf::get(who) } /// Some result as `slash(who, value)` (but without the side-effects) asuming there are no @@ -112,11 +86,6 @@ pub fn can_slash(who: &AccountId, value: Balance) -> bool { balance(who) >= value } -/// The block at which the `who`'s funds become entirely liquid. -pub fn bondage(who: &AccountId) -> Bondage { - storage::get_or_default(&who.to_keyed_vec(BONDAGE_OF)) -} - #[derive(PartialEq, Copy, Clone)] #[cfg_attr(test, derive(Debug))] pub enum LockStatus { @@ -127,28 +96,23 @@ pub enum LockStatus { /// The block at which the `who`'s funds become entirely liquid. pub fn unlock_block(who: &AccountId) -> LockStatus { - match bondage(who) { + match BondageOf::get(who) { i if i == Bondage::max_value() => LockStatus::Staked, i if i <= system::block_number() => LockStatus::Liquid, i => LockStatus::LockedUntil(i), } } -/// The total amount of stake on the system. -pub fn total_stake() -> Balance { - storage::get_or(TOTAL_STAKE, 0) -} - pub struct PublicPass<'a> (&'a AccountId); const NOBODY: AccountId = [0u8; 32]; impl<'a> PublicPass<'a> { pub fn new(transactor: &AccountId) -> PublicPass { - let b = free_balance(&transactor); - let transaction_fee = transaction_fee(); + let b = FreeBalanceOf::get(transactor); + let transaction_fee = TransactionFee::get(); assert!(b >= transaction_fee, "attempt to transact without enough funds to pay fee"); - internal::set_free_balance(&transactor, b - transaction_fee); + FreeBalanceOf::insert(transactor, b - transaction_fee); PublicPass(transactor) } @@ -199,26 +163,26 @@ impl<'a> public::Dispatch for PublicPass<'a> { /// /// Effects will be felt at the beginning of the next era. fn stake(self) { - let mut intentions = IntentionStorageVec::items(); + let mut intentions = Intention::items(); // can't be in the list twice. assert!(intentions.iter().find(|&t| *t == *self).is_none(), "Cannot stake if already staked."); intentions.push(self.clone()); - IntentionStorageVec::set_items(&intentions); - storage::put(&self.to_keyed_vec(BONDAGE_OF), &u64::max_value()); + Intention::set_items(&intentions); + BondageOf::insert(*self, u64::max_value()); } /// Retract the desire to stake for the transactor. /// /// Effects will be felt at the beginning of the next era. fn unstake(self) { - let mut intentions = IntentionStorageVec::items(); + let mut intentions = Intention::items(); if let Some(position) = intentions.iter().position(|&t| t == *self) { intentions.swap_remove(position); } else { panic!("Cannot unstake if not already staked."); } - IntentionStorageVec::set_items(&intentions); - storage::put(&self.to_keyed_vec(BONDAGE_OF), &(current_era() + bonding_duration())); + Intention::set_items(&intentions); + BondageOf::insert(*self, CurrentEra::get() + BondingDuration::get()); } } @@ -233,17 +197,17 @@ impl_dispatch! { impl privileged::Dispatch for democracy::PrivPass { /// Set the number of sessions in an era. fn set_sessions_per_era(self, new: BlockNumber) { - storage::put(NEXT_SESSIONS_PER_ERA, &new); + NextSessionsPerEra::put(&new); } /// The length of the bonding duration in eras. fn set_bonding_duration(self, new: BlockNumber) { - storage::put(BONDING_DURATION, &new); + BondingDuration::put(&new); } /// The length of a staking era in sessions. fn set_validator_count(self, new: u32) { - storage::put(VALIDATOR_COUNT, &new); + ValidatorCount::put(&new); } /// Force there to be a new era. This also forces a new session immediately after. @@ -254,9 +218,9 @@ impl privileged::Dispatch for democracy::PrivPass { } // Each identity's stake may be in one of three bondage states, given by an integer: -// - n | n <= current_era(): inactive: free to be transferred. +// - n | n <= CurrentEra::get(): inactive: free to be transferred. // - ~0: active: currently representing a validator. -// - n | n > current_era(): deactivating: recently representing a validator and not yet +// - n | n > CurrentEra::get(): deactivating: recently representing a validator and not yet // ready for transfer. mod private { @@ -296,15 +260,13 @@ mod private { pub struct DirectExt; impl Externalities for DirectExt { fn get_storage(&self, account: &AccountId, location: &[u8]) -> Option<Vec<u8>> { - let mut v = account.to_keyed_vec(STORAGE_OF); - v.extend(location); - storage::get_raw(&v) + StorageOf::get(&(*account, location.to_vec())) } fn get_code(&self, account: &AccountId) -> Vec<u8> { - storage::get_raw(&account.to_keyed_vec(CODE_OF)).unwrap_or_default() + CodeOf::get(account) } fn get_balance(&self, account: &AccountId) -> Balance { - storage::get_or_default::<Balance>(&account.to_keyed_vec(BALANCE_OF)) + FreeBalanceOf::get(account) } } @@ -327,19 +289,16 @@ mod private { pub fn commit_state(s: State) { for (address, changed) in s.into_iter() { if let Some(balance) = changed.balance { - storage::put(&address.to_keyed_vec(BALANCE_OF), &balance); + FreeBalanceOf::insert(address, balance); } if let Some(code) = changed.code { - storage::put(&address.to_keyed_vec(CODE_OF), &code); + CodeOf::insert(&address, &code); } - let storage_key = address.to_keyed_vec(STORAGE_OF); for (k, v) in changed.storage.into_iter() { - let mut key = storage_key.clone(); - key.extend(k); if let Some(value) = v { - storage::put_raw(&key, &value); + StorageOf::insert(&(address, k), &value); } else { - storage::kill(&key); + StorageOf::remove(&(address, k)); } } } @@ -404,7 +363,7 @@ mod private { assert!(from_balance >= value); let to_balance = ext.get_balance(dest); - assert!(bondage(transactor) <= bondage(dest)); + assert!(BondageOf::get(transactor) <= BondageOf::get(dest)); assert!(to_balance + value > to_balance); // no overflow // TODO: a fee, based upon gaslimit/gasprice. @@ -470,17 +429,10 @@ mod private { pub mod internal { use super::*; - /// Set the balance of an account. - /// Needless to say, this is super low-level and accordingly dangerous. Ensure any modules that - /// use it are auditted to the hilt. - pub fn set_free_balance(who: &AccountId, value: Balance) { - storage::put(&who.to_keyed_vec(BALANCE_OF), &value); - } - /// Hook to be called after to transaction processing. pub fn check_new_era() { // check block number and call new_era if necessary. - if (system::block_number() - last_era_length_change()) % era_length() == 0 { + if (system::block_number() - LastEraLengthChange::get()) % era_length() == 0 { new_era(); } } @@ -488,9 +440,9 @@ pub mod internal { /// Deduct from an unbonded balance. true if it happened. pub fn deduct_unbonded(who: &AccountId, value: Balance) -> bool { if let LockStatus::Liquid = unlock_block(who) { - let b = free_balance(who); + let b = FreeBalanceOf::get(who); if b >= value { - set_free_balance(who, b - value); + FreeBalanceOf::insert(who, &(b - value)); return true; } } @@ -499,14 +451,14 @@ pub mod internal { /// Refund some balance. pub fn refund(who: &AccountId, value: Balance) { - set_free_balance(who, free_balance(who) + value) + FreeBalanceOf::insert(who, &(FreeBalanceOf::get(who) + value)) } /// Will slash any balance, but prefer free over reserved. pub fn slash(who: &AccountId, value: Balance) -> bool { - let free_balance = free_balance(who); + let free_balance = FreeBalanceOf::get(who); let free_slash = cmp::min(free_balance, value); - set_free_balance(who, free_balance - free_slash); + FreeBalanceOf::insert(who, &(free_balance - free_slash)); if free_slash < value { slash_reserved(who, value - free_slash) } else { @@ -516,63 +468,59 @@ pub mod internal { /// Moves `value` from balance to reserved balance. pub fn reserve_balance(who: &AccountId, value: Balance) { - let b = free_balance(who); + let b = FreeBalanceOf::get(who); assert!(b >= value); - set_free_balance(who, b - value); - set_reserved_balance(who, reserved_balance(who) + value); + FreeBalanceOf::insert(who, &(b - value)); + ReservedBalanceOf::insert(who, &(ReservedBalanceOf::get(who) + value)); } /// Moves `value` from reserved balance to balance. pub fn unreserve_balance(who: &AccountId, value: Balance) { - let b = reserved_balance(who); + let b = ReservedBalanceOf::get(who); let value = cmp::min(b, value); - set_reserved_balance(who, b - value); - set_free_balance(who, free_balance(who) + value); + ReservedBalanceOf::insert(who, &(b - value)); + FreeBalanceOf::insert(who, &(FreeBalanceOf::get(who) + value)); } /// Moves `value` from reserved balance to balance. pub fn slash_reserved(who: &AccountId, value: Balance) -> bool { - let b = reserved_balance(who); + let b = ReservedBalanceOf::get(who); let slash = cmp::min(b, value); - set_reserved_balance(who, b - slash); + ReservedBalanceOf::insert(who, &(b - slash)); value == slash } /// Moves `value` from reserved balance to balance. pub fn transfer_reserved_balance(slashed: &AccountId, beneficiary: &AccountId, value: Balance) -> bool { - let b = reserved_balance(slashed); + let b = ReservedBalanceOf::get(slashed); let slash = cmp::min(b, value); - set_reserved_balance(slashed, b - slash); - set_free_balance(beneficiary, free_balance(beneficiary) + slash); + ReservedBalanceOf::insert(slashed, &(b - slash)); + FreeBalanceOf::insert(beneficiary, &(FreeBalanceOf::get(beneficiary) + slash)); slash == value } } -/// Set the reserved portion of `who`'s balance. -fn set_reserved_balance(who: &AccountId, value: Balance) { - storage::put(&who.to_keyed_vec(RESERVED_BALANCE_OF), &value); -} - /// The era has changed - enact new staking set. /// /// NOTE: This always happens immediately before a session change to ensure that new validators /// get a chance to set their session keys. fn new_era() { // Increment current era. - storage::put(CURRENT_ERA, &(current_era() + 1)); + CurrentEra::put(&(CurrentEra::get() + 1)); // Enact era length change. - let next_spe: u64 = storage::get_or_default(NEXT_SESSIONS_PER_ERA); - if next_spe > 0 && next_spe != sessions_per_era() { - storage::put(SESSIONS_PER_ERA, &next_spe); - storage::put(LAST_ERA_LENGTH_CHANGE, &system::block_number()); + if let Some(next_spe) = NextSessionsPerEra::get() { + if next_spe != SessionsPerEra::get() { + SessionsPerEra::put(&next_spe); + LastEraLengthChange::put(&system::block_number()); + } } // evaluate desired staking amounts and nominations and optimise to find the best // combination of validators, then use session::internal::set_validators(). // for now, this just orders would-be stakers by their balances and chooses the top-most - // validator_count() of them. - let mut intentions = IntentionStorageVec::items() + // ValidatorCount::get() of them. + let mut intentions = Intention::items() .into_iter() .map(|v| (balance(&v), v)) .collect::<Vec<_>>(); @@ -580,7 +528,7 @@ fn new_era() { session::internal::set_validators( &intentions.into_iter() .map(|(_, v)| v) - .take(validator_count()) + .take(ValidatorCount::get() as usize) .collect::<Vec<_>>() ); } @@ -597,15 +545,16 @@ pub mod testing { pub fn externalities(session_length: u64, sessions_per_era: u64, current_era: u64) -> TestExternalities { let extras: TestExternalities = map![ - twox_128(INTENTION_COUNT).to_vec() => vec![].and(&3u32), - twox_128(&0u32.to_keyed_vec(INTENTION_AT)).to_vec() => Alice.to_raw_public_vec(), - twox_128(&1u32.to_keyed_vec(INTENTION_AT)).to_vec() => Bob.to_raw_public_vec(), - twox_128(&2u32.to_keyed_vec(INTENTION_AT)).to_vec() => Charlie.to_raw_public_vec(), - twox_128(SESSIONS_PER_ERA).to_vec() => vec![].and(&sessions_per_era), - twox_128(VALIDATOR_COUNT).to_vec() => vec![].and(&3u64), - twox_128(TRANSACTION_FEE).to_vec() => vec![].and(&1u64), - twox_128(CURRENT_ERA).to_vec() => vec![].and(¤t_era), - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] + twox_128(&Intention::len_key()).to_vec() => vec![].and(&3u32), + twox_128(&Intention::key_for(0)).to_vec() => Alice.to_raw_public_vec(), + twox_128(&Intention::key_for(1)).to_vec() => Bob.to_raw_public_vec(), + twox_128(&Intention::key_for(2)).to_vec() => Charlie.to_raw_public_vec(), + twox_128(SessionsPerEra::key()).to_vec() => vec![].and(&sessions_per_era), + twox_128(ValidatorCount::key()).to_vec() => vec![].and(&3u64), + twox_128(BondingDuration::key()).to_vec() => vec![].and(&0u64), + twox_128(TransactionFee::key()).to_vec() => vec![].and(&1u64), + twox_128(CurrentEra::key()).to_vec() => vec![].and(¤t_era), + twox_128(&FreeBalanceOf::key_for(*Alice)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] ]; session::testing::externalities(session_length).into_iter().chain(extras.into_iter()).collect() } @@ -630,25 +579,24 @@ mod tests { #[test] fn staking_should_work() { let mut t: TestExternalities = map![ - twox_128(session::SESSION_LENGTH).to_vec() => vec![].and(&1u64), - twox_128(session::VALIDATOR_COUNT).to_vec() => vec![].and(&2u32), - twox_128(&0u32.to_keyed_vec(session::VALIDATOR_AT)).to_vec() => vec![10; 32], - twox_128(&1u32.to_keyed_vec(session::VALIDATOR_AT)).to_vec() => vec![20; 32], - twox_128(SESSIONS_PER_ERA).to_vec() => vec![].and(&2u64), - twox_128(VALIDATOR_COUNT).to_vec() => vec![].and(&2u32), - twox_128(BONDING_DURATION).to_vec() => vec![].and(&3u64), - twox_128(TOTAL_STAKE).to_vec() => vec![].and(&100u64), - twox_128(TRANSACTION_FEE).to_vec() => vec![].and(&0u64), - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&10u64), - twox_128(&Bob.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&20u64), - twox_128(&Charlie.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&30u64), - twox_128(&Dave.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&40u64) + twox_128(session::SessionLength::key()).to_vec() => vec![].and(&1u64), + twox_128(session::Validators::key()).to_vec() => vec![].and(&vec![[10u8; 32], [20; 32]]), + twox_128(CurrentEra::key()).to_vec() => vec![].and(&0u64), + twox_128(SessionsPerEra::key()).to_vec() => vec![].and(&2u64), + twox_128(ValidatorCount::key()).to_vec() => vec![].and(&2u32), + twox_128(BondingDuration::key()).to_vec() => vec![].and(&3u64), + twox_128(TotalStake::key()).to_vec() => vec![].and(&100u64), + twox_128(TransactionFee::key()).to_vec() => vec![].and(&0u64), + twox_128(&FreeBalanceOf::key_for(*Alice)).to_vec() => vec![].and(&10u64), + twox_128(&FreeBalanceOf::key_for(*Bob)).to_vec() => vec![].and(&20u64), + twox_128(&FreeBalanceOf::key_for(*Charlie)).to_vec() => vec![].and(&30u64), + twox_128(&FreeBalanceOf::key_for(*Dave)).to_vec() => vec![].and(&40u64) ]; with_externalities(&mut t, || { assert_eq!(era_length(), 2u64); - assert_eq!(validator_count(), 2usize); - assert_eq!(bonding_duration(), 3u64); + assert_eq!(ValidatorCount::get(), 2); + assert_eq!(BondingDuration::get(), 3); assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]); // Block 1: Add three validators. No obvious change. @@ -701,76 +649,78 @@ mod tests { #[test] fn staking_eras_work() { let mut t: TestExternalities = map![ - twox_128(session::SESSION_LENGTH).to_vec() => vec![].and(&1u64), - twox_128(SESSIONS_PER_ERA).to_vec() => vec![].and(&2u64) + twox_128(session::SessionLength::key()).to_vec() => vec![].and(&1u64), + twox_128(SessionsPerEra::key()).to_vec() => vec![].and(&2u64), + twox_128(ValidatorCount::key()).to_vec() => vec![].and(&2u32), + twox_128(CurrentEra::key()).to_vec() => vec![].and(&0u64) ]; with_externalities(&mut t, || { assert_eq!(era_length(), 2u64); - assert_eq!(sessions_per_era(), 2u64); - assert_eq!(last_era_length_change(), 0u64); - assert_eq!(current_era(), 0u64); + assert_eq!(SessionsPerEra::get(), 2u64); + assert_eq!(LastEraLengthChange::get(), 0u64); + assert_eq!(CurrentEra::get(), 0u64); // Block 1: No change. with_env(|e| e.block_number = 1); check_new_era(); - assert_eq!(sessions_per_era(), 2u64); - assert_eq!(last_era_length_change(), 0u64); - assert_eq!(current_era(), 0u64); + assert_eq!(SessionsPerEra::get(), 2u64); + assert_eq!(LastEraLengthChange::get(), 0u64); + assert_eq!(CurrentEra::get(), 0u64); // Block 2: Simple era change. with_env(|e| e.block_number = 2); check_new_era(); - assert_eq!(sessions_per_era(), 2u64); - assert_eq!(last_era_length_change(), 0u64); - assert_eq!(current_era(), 1u64); + assert_eq!(SessionsPerEra::get(), 2u64); + assert_eq!(LastEraLengthChange::get(), 0u64); + assert_eq!(CurrentEra::get(), 1u64); // Block 3: Schedule an era length change; no visible changes. with_env(|e| e.block_number = 3); PrivPass::test().set_sessions_per_era(3); check_new_era(); - assert_eq!(sessions_per_era(), 2u64); - assert_eq!(last_era_length_change(), 0u64); - assert_eq!(current_era(), 1u64); + assert_eq!(SessionsPerEra::get(), 2u64); + assert_eq!(LastEraLengthChange::get(), 0u64); + assert_eq!(CurrentEra::get(), 1u64); // Block 4: Era change kicks in. with_env(|e| e.block_number = 4); check_new_era(); - assert_eq!(sessions_per_era(), 3u64); - assert_eq!(last_era_length_change(), 4u64); - assert_eq!(current_era(), 2u64); + assert_eq!(SessionsPerEra::get(), 3u64); + assert_eq!(LastEraLengthChange::get(), 4u64); + assert_eq!(CurrentEra::get(), 2u64); // Block 5: No change. with_env(|e| e.block_number = 5); check_new_era(); - assert_eq!(sessions_per_era(), 3u64); - assert_eq!(last_era_length_change(), 4u64); - assert_eq!(current_era(), 2u64); + assert_eq!(SessionsPerEra::get(), 3u64); + assert_eq!(LastEraLengthChange::get(), 4u64); + assert_eq!(CurrentEra::get(), 2u64); // Block 6: No change. with_env(|e| e.block_number = 6); check_new_era(); - assert_eq!(sessions_per_era(), 3u64); - assert_eq!(last_era_length_change(), 4u64); - assert_eq!(current_era(), 2u64); + assert_eq!(SessionsPerEra::get(), 3u64); + assert_eq!(LastEraLengthChange::get(), 4u64); + assert_eq!(CurrentEra::get(), 2u64); // Block 7: Era increment. with_env(|e| e.block_number = 7); check_new_era(); - assert_eq!(sessions_per_era(), 3u64); - assert_eq!(last_era_length_change(), 4u64); - assert_eq!(current_era(), 3u64); + assert_eq!(SessionsPerEra::get(), 3u64); + assert_eq!(LastEraLengthChange::get(), 4u64); + assert_eq!(CurrentEra::get(), 3u64); }); } #[test] fn staking_balance_works() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 42); - assert_eq!(free_balance(&Alice), 42); - assert_eq!(reserved_balance(&Alice), 0); + FreeBalanceOf::insert(*Alice, 42); + assert_eq!(FreeBalanceOf::get(*Alice), 42); + assert_eq!(ReservedBalanceOf::get(*Alice), 0); assert_eq!(balance(&Alice), 42); - assert_eq!(free_balance(&Bob), 0); - assert_eq!(reserved_balance(&Bob), 0); + assert_eq!(FreeBalanceOf::get(*Bob), 0); + assert_eq!(ReservedBalanceOf::get(*Bob), 0); assert_eq!(balance(&Bob), 0); }); } @@ -778,7 +728,7 @@ mod tests { #[test] fn staking_balance_transfer_works() { with_externalities(&mut testing::externalities(1, 3, 1), || { - set_free_balance(&Alice, 112); + FreeBalanceOf::insert(*Alice, 112); PublicPass::new(&Alice).transfer(Bob.to_raw_public(), 69); assert_eq!(balance(&Alice), 42); assert_eq!(balance(&Bob), 69); @@ -789,7 +739,7 @@ mod tests { #[should_panic] fn staking_balance_transfer_when_bonded_panics() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + FreeBalanceOf::insert(*Alice, 111); PublicPass::new(&Alice).stake(); PublicPass::new(&Alice).transfer(Bob.to_raw_public(), 69); }); @@ -798,17 +748,17 @@ mod tests { #[test] fn reserving_balance_should_work() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + FreeBalanceOf::insert(*Alice, 111); assert_eq!(balance(&Alice), 111); - assert_eq!(free_balance(&Alice), 111); - assert_eq!(reserved_balance(&Alice), 0); + assert_eq!(FreeBalanceOf::get(*Alice), 111); + assert_eq!(ReservedBalanceOf::get(*Alice), 0); reserve_balance(&Alice, 69); assert_eq!(balance(&Alice), 111); - assert_eq!(free_balance(&Alice), 42); - assert_eq!(reserved_balance(&Alice), 69); + assert_eq!(FreeBalanceOf::get(*Alice), 42); + assert_eq!(ReservedBalanceOf::get(*Alice), 69); }); } @@ -816,7 +766,7 @@ mod tests { #[should_panic] fn staking_balance_transfer_when_reserved_panics() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + FreeBalanceOf::insert(*Alice, 111); reserve_balance(&Alice, 69); PublicPass::new(&Alice).transfer(Bob.to_raw_public(), 69); }); @@ -825,17 +775,17 @@ mod tests { #[test] fn deducting_balance_should_work() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + FreeBalanceOf::insert(*Alice, 111); assert!(deduct_unbonded(&Alice, 69)); - assert_eq!(free_balance(&Alice), 42); + assert_eq!(FreeBalanceOf::get(*Alice), 42); }); } #[test] fn deducting_balance_should_fail_when_bonded() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&111u64), - twox_128(&Alice.to_raw_public().to_keyed_vec(BONDAGE_OF)).to_vec() => vec![].and(&2u64) + twox_128(&FreeBalanceOf::key_for(*Alice)).to_vec() => vec![].and(&111u64), + twox_128(&BondageOf::key_for(*Alice)).to_vec() => vec![].and(&2u64) ]; with_externalities(&mut t, || { with_env(|e| e.block_number = 1); @@ -847,90 +797,90 @@ mod tests { #[test] fn refunding_balance_should_work() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 42); + FreeBalanceOf::insert(*Alice, 42); refund(&Alice, 69); - assert_eq!(free_balance(&Alice), 111); + assert_eq!(FreeBalanceOf::get(*Alice), 111); }); } #[test] fn slashing_balance_should_work() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + FreeBalanceOf::insert(*Alice, 111); reserve_balance(&Alice, 69); assert!(slash(&Alice, 69)); - assert_eq!(free_balance(&Alice), 0); - assert_eq!(reserved_balance(&Alice), 42); + assert_eq!(FreeBalanceOf::get(*Alice), 0); + assert_eq!(ReservedBalanceOf::get(*Alice), 42); }); } #[test] fn slashing_incomplete_balance_should_work() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 42); + FreeBalanceOf::insert(*Alice, 42); reserve_balance(&Alice, 21); assert!(!slash(&Alice, 69)); - assert_eq!(free_balance(&Alice), 0); - assert_eq!(reserved_balance(&Alice), 0); + assert_eq!(FreeBalanceOf::get(*Alice), 0); + assert_eq!(ReservedBalanceOf::get(*Alice), 0); }); } #[test] fn unreserving_balance_should_work() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + FreeBalanceOf::insert(*Alice, 111); reserve_balance(&Alice, 111); unreserve_balance(&Alice, 42); - assert_eq!(reserved_balance(&Alice), 69); - assert_eq!(free_balance(&Alice), 42); + assert_eq!(ReservedBalanceOf::get(*Alice), 69); + assert_eq!(FreeBalanceOf::get(*Alice), 42); }); } #[test] fn slashing_reserved_balance_should_work() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + FreeBalanceOf::insert(*Alice, 111); reserve_balance(&Alice, 111); assert!(slash_reserved(&Alice, 42)); - assert_eq!(reserved_balance(&Alice), 69); - assert_eq!(free_balance(&Alice), 0); + assert_eq!(ReservedBalanceOf::get(*Alice), 69); + assert_eq!(FreeBalanceOf::get(*Alice), 0); }); } #[test] fn slashing_incomplete_reserved_balance_should_work() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + FreeBalanceOf::insert(*Alice, 111); reserve_balance(&Alice, 42); assert!(!slash_reserved(&Alice, 69)); - assert_eq!(free_balance(&Alice), 69); - assert_eq!(reserved_balance(&Alice), 0); + assert_eq!(FreeBalanceOf::get(*Alice), 69); + assert_eq!(ReservedBalanceOf::get(*Alice), 0); }); } #[test] fn transferring_reserved_balance_should_work() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + FreeBalanceOf::insert(*Alice, 111); reserve_balance(&Alice, 111); assert!(transfer_reserved_balance(&Alice, &Bob, 42)); - assert_eq!(reserved_balance(&Alice), 69); - assert_eq!(free_balance(&Alice), 0); - assert_eq!(reserved_balance(&Bob), 0); - assert_eq!(free_balance(&Bob), 42); + assert_eq!(ReservedBalanceOf::get(*Alice), 69); + assert_eq!(FreeBalanceOf::get(*Alice), 0); + assert_eq!(ReservedBalanceOf::get(*Bob), 0); + assert_eq!(FreeBalanceOf::get(*Bob), 42); }); } #[test] fn transferring_incomplete_reserved_balance_should_work() { with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + FreeBalanceOf::insert(*Alice, 111); reserve_balance(&Alice, 42); assert!(!transfer_reserved_balance(&Alice, &Bob, 69)); - assert_eq!(reserved_balance(&Alice), 0); - assert_eq!(free_balance(&Alice), 69); - assert_eq!(reserved_balance(&Bob), 0); - assert_eq!(free_balance(&Bob), 42); + assert_eq!(ReservedBalanceOf::get(*Alice), 0); + assert_eq!(FreeBalanceOf::get(*Alice), 69); + assert_eq!(ReservedBalanceOf::get(*Bob), 0); + assert_eq!(FreeBalanceOf::get(*Bob), 42); }); } } diff --git a/substrate/demo/runtime/src/runtime/system.rs b/substrate/demo/runtime/src/runtime/system.rs index e3a6e19ef51f00537871d8b1b5e995d1194fe2c3..5469d6aa9bfc8b81219d0d008adb92f25067c653 100644 --- a/substrate/demo/runtime/src/runtime/system.rs +++ b/substrate/demo/runtime/src/runtime/system.rs @@ -21,7 +21,7 @@ use rstd::prelude::*; use rstd::mem; use runtime_io::{print, storage_root, enumerated_trie_root}; use codec::{KeyedVec, Slicable}; -use runtime_support::{Hashable, storage}; +use runtime_support::{Hashable, storage, StorageValue, StorageMap}; use environment::with_env; use demo_primitives::{AccountId, Hash, TxOrder, BlockNumber, Header, Log}; use block::Block; @@ -30,9 +30,12 @@ use runtime::{staking, session}; use runtime::democracy::PrivPass; use dispatch; -pub const NONCE_OF: &[u8] = b"sys:non:"; -pub const BLOCK_HASH_AT: &[u8] = b"sys:old:"; -pub const CODE: &[u8] = b"sys:cod"; +storage_items! { + pub Nonce: b"sys:non" => default map [ AccountId => TxOrder ]; + pub BlockHashAt: b"sys:old" => required map [ BlockNumber => Hash ]; +} + +pub const CODE: &'static[u8] = b":code"; /// The current block number being processed. Set by `execute_block`. @@ -40,11 +43,6 @@ pub fn block_number() -> BlockNumber { with_env(|e| e.block_number) } -/// Get the block hash of a given block (uses storage). -pub fn block_hash(number: BlockNumber) -> Hash { - storage::get_or_default(&number.to_keyed_vec(BLOCK_HASH_AT)) -} - impl_dispatch! { pub mod privileged; fn set_code(new: Vec<u8>) = 0; @@ -145,12 +143,11 @@ fn execute_transaction(utx: UncheckedTransaction) { { // check nonce - let nonce_key = tx.signed.to_keyed_vec(NONCE_OF); - let expected_nonce: TxOrder = storage::get_or(&nonce_key, 0); + let expected_nonce: TxOrder = Nonce::get(&tx.signed); assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce"); // increment nonce in storage - storage::put(&nonce_key, &(expected_nonce + 1)); + Nonce::insert(&tx.signed, &(expected_nonce + 1)); } // decode parameters and dispatch @@ -163,7 +160,7 @@ fn initial_checks(block: &Block) { // check parent_hash is correct. assert!( - header.number > 0 && block_hash(header.number - 1) == header.parent_hash, + header.number > 0 && BlockHashAt::get(&(header.number - 1)) == header.parent_hash, "Parent hash should be valid." ); @@ -192,7 +189,7 @@ fn final_checks(block: &Block) { fn post_finalise(header: &Header) { // store the header hash in storage; we can't do it before otherwise there would be a // cyclic dependency. - storage::put(&header.number.to_keyed_vec(BLOCK_HASH_AT), &header.blake2_256()); + BlockHashAt::insert(&header.number, &header.blake2_256().into()); } #[cfg(feature = "std")] @@ -220,7 +217,7 @@ pub mod testing { pub fn externalities() -> TestExternalities { map![ - twox_128(&0u64.to_keyed_vec(BLOCK_HASH_AT)).to_vec() => [69u8; 32].encode() + twox_128(&BlockHashAt::key_for(&0)).to_vec() => [69u8; 32].encode() ] } } @@ -231,6 +228,7 @@ mod tests { use super::internal::*; use runtime_io::{with_externalities, twox_128, TestExternalities}; + use runtime_support::StorageValue; use codec::{Joiner, KeyedVec, Slicable}; use keyring::Keyring::*; use environment::with_env; @@ -244,8 +242,8 @@ mod tests { #[test] fn staking_balance_transfer_dispatch_works() { let mut t: TestExternalities = map![ - twox_128(&One.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(staking::TRANSACTION_FEE).to_vec() => vec![10u8, 0, 0, 0, 0, 0, 0, 0] + twox_128(&staking::FreeBalanceOf::key_for(*One)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TransactionFee::key()).to_vec() => vec![10u8, 0, 0, 0, 0, 0, 0, 0] ]; let tx = UncheckedTransaction { @@ -275,7 +273,7 @@ mod tests { let h = Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("584e0c1f4d4b96153591e3906d756762493dffeb5fa7159e7107014aec8d9c3d").into(), + state_root: hex!("cc3f1f5db826013193e502c76992b5e933b12367e37a269a9822b89218323e9f").into(), transaction_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(), digest: Digest { logs: vec![], }, }; diff --git a/substrate/demo/runtime/src/runtime/timestamp.rs b/substrate/demo/runtime/src/runtime/timestamp.rs index ff2c18b9bd4bab247b006289685c73adce7f8d56..ed51ebabc72795126ff49dce3622744458c200c5 100644 --- a/substrate/demo/runtime/src/runtime/timestamp.rs +++ b/substrate/demo/runtime/src/runtime/timestamp.rs @@ -16,16 +16,13 @@ //! Timestamp manager: just handles the current timestamp. -use runtime_support::storage; +use runtime_support::storage::StorageValue; use runtime::staking::PublicPass; pub type Timestamp = u64; -pub const CURRENT_TIMESTAMP: &[u8] = b"tim:val"; - -/// Get the current time. -pub fn get() -> Timestamp { - storage::get_or_default(CURRENT_TIMESTAMP) +storage_items! { + pub Now: b"tim:val" => required Timestamp; } impl_dispatch! { @@ -36,7 +33,7 @@ impl_dispatch! { impl<'a> public::Dispatch for PublicPass<'a> { /// Set the current time. fn set(self, now: Timestamp) { - storage::put(CURRENT_TIMESTAMP, &now); + Now::put(&now); } } @@ -46,6 +43,7 @@ mod tests { use super::public::*; use runtime_io::{with_externalities, twox_128, TestExternalities}; + use runtime_support::storage::StorageValue; use runtime::timestamp; use codec::{Joiner, KeyedVec}; use demo_primitives::AccountId; @@ -54,13 +52,13 @@ mod tests { #[test] fn timestamp_works() { let mut t: TestExternalities = map![ - twox_128(CURRENT_TIMESTAMP).to_vec() => vec![].and(&42u64) + twox_128(Now::key()).to_vec() => vec![].and(&42u64) ]; with_externalities(&mut t, || { - assert_eq!(get(), 42); + assert_eq!(Now::get(), 42); PublicPass::nobody().set(69); - assert_eq!(get(), 69); + assert_eq!(Now::get(), 69); }); } } diff --git a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm index 8d4177558c879383d18ca9954e22d0c54b394113..00854daf6fc89be40cfe268dfed20d17bb68e871 100644 Binary files a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm and b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm differ diff --git a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm index 43f146e82f7b5fed169d463fa837a22d4712c589..b033a3c8809c99b3a5aa7d2d45948d9e184d34fb 100644 Binary files a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm and b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm differ diff --git a/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm b/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm index 68f8fe0114541bf47fc02b224d5c1450d506c2ed..7072339a0712581faa3d0d6c6370673df0ff70de 100644 Binary files a/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm and b/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm differ diff --git a/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm b/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm index 06caf6119bea69b895da6b8f025f0147d66db725..57be0867032a5e1ffdb5b49e77ebcd77c8ceaa5a 100644 Binary files a/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm and b/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm differ diff --git a/substrate/substrate/runtime-support/src/lib.rs b/substrate/substrate/runtime-support/src/lib.rs index 6e946ce6c798881fb5b2b761c633e0a52109b494..b3aea78cbc6e62754b4d3d9ae5ab9d59305ae1bb 100644 --- a/substrate/substrate/runtime-support/src/lib.rs +++ b/substrate/substrate/runtime-support/src/lib.rs @@ -29,5 +29,5 @@ pub use self::storage::generator::Storage as GenericStorage; pub mod storage; mod hashable; -pub use self::storage::StorageVec; +pub use self::storage::{StorageVec, StorageList, StorageValue, StorageMap}; pub use self::hashable::Hashable; diff --git a/substrate/substrate/runtime-support/src/storage/generator.rs b/substrate/substrate/runtime-support/src/storage/generator.rs index ce02a4e099264c549670ffc312dd0063502c41ee..b77b58d418124f2469697ce595e36b77e2ac0ea4 100644 --- a/substrate/substrate/runtime-support/src/storage/generator.rs +++ b/substrate/substrate/runtime-support/src/storage/generator.rs @@ -36,7 +36,7 @@ //! //! storage_items! { //! // public value -//! pub Value: b"stored_key" => SessionKey; +//! pub Value: b"putd_key" => SessionKey; //! // private map. //! Balances: b"private_map:" => map [AuthorityId => Balance]; //! // private list. @@ -48,38 +48,73 @@ use codec; use rstd::vec::Vec; +#[doc(hidden)] +pub use rstd::borrow::Borrow; /// Abstraction around storage. pub trait Storage { + /// true if the key exists in storage. + fn exists(&self, key: &[u8]) -> bool; + /// Load the bytes of a key from storage. Can panic if the type is incorrect. - fn load<T: codec::Slicable>(&self, key: &[u8]) -> Option<T>; + fn get<T: codec::Slicable>(&self, key: &[u8]) -> Option<T>; + + /// Load the bytes of a key from storage. Can panic if the type is incorrect. Will panic if + /// it's not there. + fn require<T: codec::Slicable>(&self, key: &[u8]) -> T { self.get(key).expect("Required values must be in storage") } + + /// Load the bytes of a key from storage. Can panic if the type is incorrect. The type's + /// default is returned if it's not there. + fn get_or_default<T: codec::Slicable + Default>(&self, key: &[u8]) -> T { self.get(key).unwrap_or_default() } /// Put a value in under a key. - fn store<T: codec::Slicable>(&self, key: &[u8], val: &T); + fn put<T: codec::Slicable>(&self, key: &[u8], val: &T); /// Remove the bytes of a key from storage. fn kill(&self, key: &[u8]); /// Take a value from storage, deleting it after reading. fn take<T: codec::Slicable>(&self, key: &[u8]) -> Option<T> { - let value = self.load(key); + let value = self.get(key); self.kill(key); value } + + /// Take a value from storage, deleting it after reading. + fn take_or_panic<T: codec::Slicable>(&self, key: &[u8]) -> T { self.take(key).expect("Required values must be in storage") } + + /// Take a value from storage, deleting it after reading. + fn take_or_default<T: codec::Slicable + Default>(&self, key: &[u8]) -> T { self.take(key).unwrap_or_default() } } /// A strongly-typed value kept in storage. pub trait StorageValue<T: codec::Slicable> { + /// The type that get/take returns. + type Query; + /// Get the storage key. fn key() -> &'static [u8]; + + /// true if the value is defined in storage. + fn exists<S: Storage>(storage: &S) -> bool { + storage.exists(Self::key()) + } + /// Load the value from the provided storage instance. - fn load<S: Storage>(storage: &S) -> Option<T>; + fn get<S: Storage>(storage: &S) -> Self::Query; + + /// Take a value from storage, removing it afterwards. + fn take<S: Storage>(storage: &S) -> Self::Query; + /// Store a value under this key into the provded storage instance. - fn store<S: Storage>(val: &T, storage: &S); + fn put<S: Storage>(val: &T, storage: &S) { + storage.put(Self::key(), val) + } + /// Clear the storage value. - fn kill<S: Storage>(storage: &S); - /// Take a value from storage, removing it afterwards. - fn take<S: Storage>(storage: &S) -> Option<T>; + fn kill<S: Storage>(storage: &S) { + storage.kill(Self::key()) + } } /// A strongly-typed list in storage. @@ -87,7 +122,7 @@ pub trait StorageList<T: codec::Slicable> { /// Get the prefix key in storage. fn prefix() -> &'static [u8]; - /// Get the key used to store the length field. + /// Get the key used to put the length field. fn len_key() -> Vec<u8>; /// Get the storage key used to fetch a value at a given index. @@ -114,225 +149,119 @@ pub trait StorageList<T: codec::Slicable> { /// A strongly-typed map in storage. pub trait StorageMap<K: codec::Slicable, V: codec::Slicable> { + /// The type that get/take returns. + type Query; + /// Get the prefix key in storage. fn prefix() -> &'static [u8]; /// Get the storage key used to fetch a value corresponding to a specific key. fn key_for(x: &K) -> Vec<u8>; + /// true if the value is defined in storage. + fn exists<S: Storage>(key: &K, storage: &S) -> bool { + storage.exists(&Self::key_for(key)[..]) + } + /// Load the value associated with the given key from the map. - fn get<S: Storage>(key: &K, storage: &S) -> Option<V>; + fn get<S: Storage>(key: &K, storage: &S) -> Self::Query; + + /// Take the value under a key. + fn take<S: Storage>(key: &K, storage: &S) -> Self::Query; /// Store a value to be associated with the given key from the map. - fn insert<S: Storage>(key: &K, val: &V, storage: &S); + fn insert<S: Storage>(key: &K, val: &V, storage: &S) { + storage.put(&Self::key_for(key)[..], val); + } /// Remove the value under a key. - fn remove<S: Storage>(key: &K, storage: &S); - - /// Take the value under a key. - fn take<S: Storage>(key: &K, storage: &S) -> Option<V>; + fn remove<S: Storage>(key: &K, storage: &S) { + storage.kill(&Self::key_for(key)[..]); + } } #[macro_export] #[doc(hidden)] macro_rules! __storage_items_internal { // generator for values. - (($($vis:tt)*) $name: ident: $key: expr => $ty:ty) => { + (($($vis:tt)*) ($get_fn:ident) ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { + __storage_items_internal!{ ($($vis)*) () ($gettype) ($getter) ($taker) $name : $key => $ty } + pub fn $get_fn() -> $gettype { <$name as $crate::storage::generator::StorageValue<$ty>> :: get(&$crate::storage::RuntimeStorage) } + }; + (($($vis:tt)*) () ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { $($vis)* struct $name; - #[allow(unused)] - impl $name { - /// Get the storage key. - $($vis)* fn key() -> &'static [u8] { - $key - } - - /// Load the value from the provided storage instance. - $($vis)* fn load<S: $crate::GenericStorage>(storage: &S) -> Option<$ty> { - storage.load($key) - } - - /// Store a value under this key into the provded storage instance. - $($vis)* fn store<S: $crate::GenericStorage>(val: &$ty, storage: &S) { - storage.store($key, val) - } - - /// Kill the value. - $($vis)* fn kill<S: $crate::GenericStorage>(storage: &S) { - storage.kill($key) - } - - /// Take and remove the value from the provided storage instance. - $($vis)* fn take<S: $crate::GenericStorage>(storage: &S) -> Option<$ty> { - storage.take($key) - } - } - impl $crate::storage::generator::StorageValue<$ty> for $name { + type Query = $gettype; + + /// Get the storage key. fn key() -> &'static [u8] { $key } - fn load<S: $crate::GenericStorage>(storage: &S) -> Option<$ty> { - $name::load(storage) - } - - fn store<S: $crate::GenericStorage>(val: &$ty, storage: &S) { - $name::store(val, storage) - } - - fn kill<S: $crate::GenericStorage>(storage: &S) { - $name::kill(storage) + /// Load the value from the provided storage instance. + fn get<S: $crate::GenericStorage>(storage: &S) -> Self::Query { + storage.$getter($key) } - fn take<S: $crate::GenericStorage>(storage: &S) -> Option<$ty> { - $name::take(storage) + /// Take a value from storage, removing it afterwards. + fn take<S: $crate::GenericStorage>(storage: &S) -> Self::Query { + storage.$taker($key) } } }; // generator for maps. - (($($vis:tt)*) $name: ident: $prefix: expr => map [$kty: ty => $ty:ty]) => { + (($($vis:tt)*) ($get_fn:ident) ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { + __storage_items_internal!{ ($($vis)*) () ($gettype) ($getter) ($taker) $name : $prefix => map [$kty => $ty] } + pub fn $get_fn<K: $crate::storage::generator::Borrow<$kty>>(key: K) -> $gettype { + <$name as $crate::storage::generator::StorageMap<$kty, $ty>> :: get(key.borrow(), &$crate::storage::RuntimeStorage) + } + }; + (($($vis:tt)*) () ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { $($vis)* struct $name; - #[allow(unused)] - impl $name { + impl $crate::storage::generator::StorageMap<$kty, $ty> for $name { + type Query = $gettype; + /// Get the prefix key in storage. - $($vis)* fn prefix() -> &'static [u8] { + fn prefix() -> &'static [u8] { $prefix } /// Get the storage key used to fetch a value corresponding to a specific key. - $($vis)* fn key_for(x: &$kty) -> Vec<u8> { + fn key_for(x: &$kty) -> Vec<u8> { let mut key = $prefix.to_vec(); key.extend($crate::codec::Slicable::encode(x)); key } /// Load the value associated with the given key from the map. - $($vis)* fn get<S: $crate::GenericStorage>(key: &$kty, storage: &S) -> Option<$ty> { - let key = $name::key_for(key); - storage.load(&key[..]) - } - - /// Store a value to be associated with the given key from the map. - $($vis)* fn insert<S: $crate::GenericStorage>(key: &$kty, val: &$ty, storage: &S) { - let key = $name::key_for(key); - storage.store(&key[..], val); - } - - /// Remove the value from storage. - $($vis)* fn remove<S: $crate::GenericStorage>(key: &$kty, storage: &S) { - storage.kill(&$name::key_for(key)[..]); + fn get<S: $crate::GenericStorage>(key: &$kty, storage: &S) -> Self::Query { + let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); + storage.$getter(&key[..]) } /// Take the value, reading and removing it. - $($vis)* fn take<S: $crate::GenericStorage>(key: &$kty, storage: &S) -> Option<$ty> { - let key = $name::key_for(key); - storage.take(&key[..]) - } - } - - impl $crate::storage::generator::StorageMap<$kty, $ty> for $name { - fn prefix() -> &'static [u8] { - $prefix - } - - fn key_for(x: &$kty) -> Vec<u8> { - $name::key_for(x) - } - - fn get<S: $crate::GenericStorage>(key: &$kty, storage: &S) -> Option<$ty> { - $name::get(key, storage) - } - - fn insert<S: $crate::GenericStorage>(key: &$kty, val: &$ty, storage: &S) { - $name::insert(key, val, storage) - } - - fn remove<S: $crate::GenericStorage>(key: &$kty, storage: &S) { - $name::remove(key, storage) - } - - fn take<S: $crate::GenericStorage>(key: &$kty, storage: &S) -> Option<$ty> { - $name::take(key, storage) + fn take<S: $crate::GenericStorage>(key: &$kty, storage: &S) -> Self::Query { + let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); + storage.$taker(&key[..]) } } }; // generator for lists. - (($($vis:tt)*) $name: ident: $prefix: expr => list [$ty:ty]) => { + (($($vis:tt)*) $name:ident : $prefix:expr => list [$ty:ty]) => { $($vis)* struct $name; - #[allow(unused)] impl $name { - /// Get the prefix key in storage. - $($vis)* fn prefix() -> &'static [u8] { - $prefix - } - - /// Get the key used to store the length field. - // TODO: concat macro should accept byte literals. - $($vis)* fn len_key() -> Vec<u8> { - let mut key = $prefix.to_vec(); - key.extend(b"len"); - key - } - - /// Get the storage key used to fetch a value at a given index. - $($vis)* fn key_for(index: u32) -> Vec<u8> { - let mut key = $prefix.to_vec(); - key.extend($crate::codec::Slicable::encode(&index)); - key - } - - /// Read out all the items. - $($vis)* fn items<S: $crate::GenericStorage>(storage: &S) -> Vec<$ty> { - (0..$name::len(storage)) - .map(|i| $name::get(i, storage).expect("all items within length are set; qed")) - .collect() - } - - /// Set the current set of items. - $($vis)* fn set_items<S: $crate::GenericStorage>(items: &[$ty], storage: &S) { - $name::set_len(items.len() as u32, storage); - items.iter() - .enumerate() - .for_each(|(i, item)| $name::set_item(i as u32, item, storage)); - } - - $($vis)* fn set_item<S: $crate::GenericStorage>(index: u32, item: &$ty, storage: &S) { - if index < $name::len(storage) { - storage.store(&$name::key_for(index)[..], item); - } - } - - /// Load the value at given index. Returns `None` if the index is out-of-bounds. - $($vis)* fn get<S: $crate::GenericStorage>(index: u32, storage: &S) -> Option<$ty> { - storage.load(&$name::key_for(index)[..]) - } - - /// Load the length of the list. - $($vis)* fn len<S: $crate::GenericStorage>(storage: &S) -> u32 { - storage.load(&$name::len_key()).unwrap_or_default() - } - - /// Clear the list. - $($vis)* fn clear<S: $crate::GenericStorage>(storage: &S) { - for i in 0..$name::len(storage) { - $name::clear_item(i, storage); - } - - storage.kill(&$name::len_key()[..]) - } - fn clear_item<S: $crate::GenericStorage>(index: u32, storage: &S) { - if index < $name::len(storage) { - storage.kill(&$name::key_for(index)); + if index < <$name as $crate::storage::generator::StorageList<$ty>>::len(storage) { + storage.kill(&<$name as $crate::storage::generator::StorageList<$ty>>::key_for(index)); } } fn set_len<S: $crate::GenericStorage>(count: u32, storage: &S) { - (count..$name::len(storage)).for_each(|i| $name::clear_item(i, storage)); - storage.store(&$name::len_key(), &count); + (count..<$name as $crate::storage::generator::StorageList<$ty>>::len(storage)).for_each(|i| $name::clear_item(i, storage)); + storage.put(&<$name as $crate::storage::generator::StorageList<$ty>>::len_key(), &count); } } @@ -342,42 +271,59 @@ macro_rules! __storage_items_internal { $prefix } - /// Get the key used to store the length field. + /// Get the key used to put the length field. // TODO: concat macro should accept byte literals. fn len_key() -> Vec<u8> { - $name::len_key() + let mut key = $prefix.to_vec(); + key.extend(b"len"); + key } /// Get the storage key used to fetch a value at a given index. fn key_for(index: u32) -> Vec<u8> { - $name::key_for(index) + let mut key = $prefix.to_vec(); + key.extend($crate::codec::Slicable::encode(&index)); + key } /// Read out all the items. fn items<S: $crate::GenericStorage>(storage: &S) -> Vec<$ty> { - $name::items(storage) + (0..<$name as $crate::storage::generator::StorageList<$ty>>::len(storage)) + .map(|i| <$name as $crate::storage::generator::StorageList<$ty>>::get(i, storage).expect("all items within length are set; qed")) + .collect() } /// Set the current set of items. fn set_items<S: $crate::GenericStorage>(items: &[$ty], storage: &S) { - $name::set_items(items, storage) + $name::set_len(items.len() as u32, storage); + items.iter() + .enumerate() + .for_each(|(i, item)| <$name as $crate::storage::generator::StorageList<$ty>>::set_item(i as u32, item, storage)); } fn set_item<S: $crate::GenericStorage>(index: u32, item: &$ty, storage: &S) { - $name::set_item(index, item, storage) + if index < <$name as $crate::storage::generator::StorageList<$ty>>::len(storage) { + storage.put(&<$name as $crate::storage::generator::StorageList<$ty>>::key_for(index)[..], item); + } } /// Load the value at given index. Returns `None` if the index is out-of-bounds. fn get<S: $crate::GenericStorage>(index: u32, storage: &S) -> Option<$ty> { - $name::get(index, storage) + storage.get(&<$name as $crate::storage::generator::StorageList<$ty>>::key_for(index)[..]) } + /// Load the length of the list. fn len<S: $crate::GenericStorage>(storage: &S) -> u32 { - $name::len(storage) + storage.get(&<$name as $crate::storage::generator::StorageList<$ty>>::len_key()).unwrap_or_default() } + /// Clear the list. fn clear<S: $crate::GenericStorage>(storage: &S) { - $name::clear(storage) + for i in 0..<$name as $crate::storage::generator::StorageList<$ty>>::len(storage) { + $name::clear_item(i, storage); + } + + storage.kill(&<$name as $crate::storage::generator::StorageList<$ty>>::len_key()[..]) } } }; @@ -387,29 +333,114 @@ macro_rules! __storage_items_internal { #[macro_export] macro_rules! storage_items { // simple values - ($name: ident: $key: expr => $ty:ty; $($t:tt)*) => { - __storage_items_internal!(() $name: $key => $ty); + ($name:ident : $key:expr => $ty:ty; $($t:tt)*) => { + __storage_items_internal!(() () (Option<$ty>) (get) (take) $name: $key => $ty); + storage_items!($($t)*); + }; + (pub $name:ident : $key:expr => $ty:ty; $($t:tt)*) => { + __storage_items_internal!((pub) () (Option<$ty>) (get) (take) $name: $key => $ty); storage_items!($($t)*); }; - (pub $name: ident: $key: expr => $ty:ty; $($t:tt)*) => { - __storage_items_internal!((pub) $name: $key => $ty); + ($name:ident : $key:expr => default $ty:ty; $($t:tt)*) => { + __storage_items_internal!(() () ($ty) (get_or_default) (take_or_default) $name: $key => $ty); storage_items!($($t)*); }; + (pub $name:ident : $key:expr => default $ty:ty; $($t:tt)*) => { + __storage_items_internal!((pub) () ($ty) (get_or_default) (take_or_default) $name: $key => $ty); + storage_items!($($t)*); + }; + ($name:ident : $key:expr => required $ty:ty; $($t:tt)*) => { + __storage_items_internal!(() () ($ty) (require) (take_or_panic) $name: $key => $ty); + storage_items!($($t)*); + }; + (pub $name:ident : $key:expr => required $ty:ty; $($t:tt)*) => { + __storage_items_internal!((pub) () ($ty) (require) (take_or_panic) $name: $key => $ty); + storage_items!($($t)*); + }; + + ($name:ident get($getfn:ident) : $key:expr => $ty:ty; $($t:tt)*) => { + __storage_items_internal!(() ($getfn) (Option<$ty>) (get) (take) $name: $key => $ty); + storage_items!($($t)*); + }; + (pub $name:ident get($getfn:ident) : $key:expr => $ty:ty; $($t:tt)*) => { + __storage_items_internal!((pub) ($getfn) (Option<$ty>) (get) (take) $name: $key => $ty); + storage_items!($($t)*); + }; + ($name:ident get($getfn:ident) : $key:expr => default $ty:ty; $($t:tt)*) => { + __storage_items_internal!(() ($getfn) ($ty) (get_or_default) (take_or_default) $name: $key => $ty); + storage_items!($($t)*); + }; + (pub $name:ident get($getfn:ident) : $key:expr => default $ty:ty; $($t:tt)*) => { + __storage_items_internal!((pub) ($getfn) ($ty) (get_or_default) (take_or_default) $name: $key => $ty); + storage_items!($($t)*); + }; + ($name:ident get($getfn:ident) : $key:expr => required $ty:ty; $($t:tt)*) => { + __storage_items_internal!(() ($getfn) ($ty) (require) (take_or_panic) $name: $key => $ty); + storage_items!($($t)*); + }; + (pub $name:ident get($getfn:ident) : $key:expr => required $ty:ty; $($t:tt)*) => { + __storage_items_internal!((pub) ($getfn) ($ty) (require) (take_or_panic) $name: $key => $ty); + storage_items!($($t)*); + }; + // maps - ($name: ident: $prefix: expr => map [$kty: ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!(() $name: $prefix => map [$kty => $ty]); + ($name:ident : $prefix:expr => map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!(() () (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + storage_items!($($t)*); + }; + (pub $name:ident : $prefix:expr => map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!((pub) () (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + storage_items!($($t)*); + }; + ($name:ident : $prefix:expr => default map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!(() () ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + storage_items!($($t)*); + }; + (pub $name:ident : $prefix:expr => default map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!((pub) () ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + storage_items!($($t)*); + }; + ($name:ident : $prefix:expr => required map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!(() () ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + storage_items!($($t)*); + }; + (pub $name:ident : $prefix:expr => required map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!((pub) () ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + storage_items!($($t)*); + }; + + ($name:ident get($getfn:ident) : $prefix:expr => map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!(() ($getfn) (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + storage_items!($($t)*); + }; + (pub $name:ident get($getfn:ident) : $prefix:expr => map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!((pub) ($getfn) (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; - (pub $name: ident: $prefix: expr => map [$kty: ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!((pub) $name: $prefix => map [$kty => $ty]); + ($name:ident get($getfn:ident) : $prefix:expr => default map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!(() ($getfn) ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; + (pub $name:ident get($getfn:ident) : $prefix:expr => default map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!((pub) ($getfn) ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + storage_items!($($t)*); + }; + ($name:ident get($getfn:ident) : $prefix:expr => required map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!(() ($getfn) ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + storage_items!($($t)*); + }; + (pub $name:ident get($getfn:ident) : $prefix:expr => required map [$kty: ty => $ty:ty]; $($t:tt)*) => { + __storage_items_internal!((pub) ($getfn) ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + storage_items!($($t)*); + }; + + // lists - ($name: ident: $prefix: expr => list [$ty:ty]; $($t:tt)*) => { + ($name:ident : $prefix:expr => list [$ty:ty]; $($t:tt)*) => { __storage_items_internal!(() $name: $prefix => list [$ty]); storage_items!($($t)*); }; - (pub $name: ident: $prefix: expr => list [$ty:ty]; $($t:tt)*) => { + (pub $name:ident : $prefix:expr => list [$ty:ty]; $($t:tt)*) => { __storage_items_internal!((pub) $name: $prefix => list [$ty]); storage_items!($($t)*); }; @@ -424,11 +455,15 @@ mod tests { use super::*; impl Storage for RefCell<HashMap<Vec<u8>, Vec<u8>>> { - fn load<T: Slicable>(&self, key: &[u8]) -> Option<T> { + fn exists(&self, key: &[u8]) -> bool { + self.borrow_mut().get(key).is_some() + } + + fn get<T: Slicable>(&self, key: &[u8]) -> Option<T> { self.borrow_mut().get(key).map(|v| T::decode(&mut &v[..]).unwrap()) } - fn store<T: Slicable>(&self, key: &[u8], val: &T) { + fn put<T: Slicable>(&self, key: &[u8], val: &T) { self.borrow_mut().insert(key.to_owned(), val.encode()); } @@ -443,14 +478,14 @@ mod tests { Map: b"c:" => map [u32 => [u8; 32]]; } - #[test] + #[test] fn value() { let storage = RefCell::new(HashMap::new()); - assert!(Value::load(&storage).is_none()); - Value::store(&100_000, &storage); - assert_eq!(Value::load(&storage), Some(100_000)); + assert!(Value::get(&storage).is_none()); + Value::put(&100_000, &storage); + assert_eq!(Value::get(&storage), Some(100_000)); Value::kill(&storage); - assert!(Value::load(&storage).is_none()); + assert!(Value::get(&storage).is_none()); } #[test] diff --git a/substrate/substrate/runtime-support/src/storage/mod.rs b/substrate/substrate/runtime-support/src/storage/mod.rs index fb4aa17487360e52efc10d79b86fdf83d5af3c2f..635a30848f5a24f9c303f3ed90234a81ab68c78d 100644 --- a/substrate/substrate/runtime-support/src/storage/mod.rs +++ b/substrate/substrate/runtime-support/src/storage/mod.rs @@ -47,7 +47,7 @@ pub fn get<T: Slicable + Sized>(key: &[u8]) -> Option<T> { key: &key[..], pos: 0, }; - Slicable::decode(&mut input).expect("stroage is not null, therefore must be a valid type") + Slicable::decode(&mut input).expect("storage is not null, therefore must be a valid type") }) } @@ -122,58 +122,78 @@ pub fn put_raw(key: &[u8], value: &[u8]) { runtime_io::set_storage(&twox_128(key)[..], value) } -struct RuntimeStorage; +/// The underlying runtime storage. +pub struct RuntimeStorage; impl ::GenericStorage for RuntimeStorage { + fn exists(&self, key: &[u8]) -> bool { + super::storage::exists(key) + } + /// Load the bytes of a key from storage. Can panic if the type is incorrect. - fn load<T: Slicable>(&self, key: &[u8]) -> Option<T> { - get(key) + fn get<T: Slicable>(&self, key: &[u8]) -> Option<T> { + super::storage::get(key) } /// Put a value in under a key. - fn store<T: Slicable>(&self, key: &[u8], val: &T) { - put(key, val) + fn put<T: Slicable>(&self, key: &[u8], val: &T) { + super::storage::put(key, val) } /// Remove the bytes of a key from storage. fn kill(&self, key: &[u8]) { - kill(key) + super::storage::kill(key) } /// Take a value from storage, deleting it after reading. fn take<T: Slicable>(&self, key: &[u8]) -> Option<T> { - take(key) + super::storage::take(key) } } /// A trait for working with macro-generated storage values under the substrate storage API. pub trait StorageValue<T: Slicable> { + /// The type that get/take return. + type Query; + /// Get the storage key. fn key() -> &'static [u8]; + + /// Does the value (explicitly) exist in storage? + fn exists() -> bool; + /// Load the value from the provided storage instance. - fn load() -> Option<T>; + fn get() -> Self::Query; + /// Store a value under this key into the provded storage instance. - fn store(val: &T); + fn put<Arg: Borrow<T>>(val: Arg); + /// Clear the storage value. fn kill(); + /// Take a value from storage, removing it afterwards. - fn take() -> Option<T>; + fn take() -> Self::Query; } impl<T: Slicable, U> StorageValue<T> for U where U: generator::StorageValue<T> { + type Query = U::Query; + fn key() -> &'static [u8] { <U as generator::StorageValue<T>>::key() } - fn load() -> Option<T> { - U::load(&RuntimeStorage) + fn exists() -> bool { + U::exists(&RuntimeStorage) + } + fn get() -> Self::Query { + U::get(&RuntimeStorage) } - fn store(val: &T) { - U::store(val, &RuntimeStorage) + fn put<Arg: Borrow<T>>(val: Arg) { + U::put(val.borrow(), &RuntimeStorage) } fn kill() { U::kill(&RuntimeStorage) } - fn take() -> Option<T> { + fn take() -> Self::Query { U::take(&RuntimeStorage) } } @@ -196,7 +216,7 @@ pub trait StorageList<T: Slicable> { fn set_items(items: &[T]); /// Set the item at the given index. - fn set_item(index: u32, item: &T); + fn set_item<Arg: Borrow<T>>(index: u32, val: Arg); /// Load the value at given index. Returns `None` if the index is out-of-bounds. fn get(index: u32) -> Option<T>; @@ -229,8 +249,8 @@ impl<T: Slicable, U> StorageList<T> for U where U: generator::StorageList<T> { U::set_items(items, &RuntimeStorage) } - fn set_item(index: u32, item: &T) { - U::set_item(index, item, &RuntimeStorage) + fn set_item<Arg: Borrow<T>>(index: u32, val: Arg) { + U::set_item(index, val.borrow(), &RuntimeStorage) } fn get(index: u32) -> Option<T> { @@ -248,48 +268,60 @@ impl<T: Slicable, U> StorageList<T> for U where U: generator::StorageList<T> { /// A strongly-typed map in storage. pub trait StorageMap<K: Slicable, V: Slicable> { + /// The type that get/take return. + type Query; + /// Get the prefix key in storage. fn prefix() -> &'static [u8]; /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for(x: &K) -> Vec<u8>; + fn key_for<KeyArg: Borrow<K>>(key: KeyArg) -> Vec<u8>; + + /// Does the value (explicitly) exist in storage? + fn exists<KeyArg: Borrow<K>>(key: KeyArg) -> bool; /// Load the value associated with the given key from the map. - fn get(key: &K) -> Option<V>; + fn get<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query; /// Store a value to be associated with the given key from the map. - fn insert(key: &K, val: &V); + fn insert<KeyArg: Borrow<K>, ValArg: Borrow<V>>(key: KeyArg, val: ValArg); /// Remove the value under a key. - fn remove(key: &K); + fn remove<KeyArg: Borrow<K>>(key: KeyArg); /// Take the value under a key. - fn take(key: &K) -> Option<V>; + fn take<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query; } impl<K: Slicable, V: Slicable, U> StorageMap<K, V> for U where U: generator::StorageMap<K, V> { + type Query = U::Query; + fn prefix() -> &'static [u8] { <U as generator::StorageMap<K, V>>::prefix() } - fn key_for(item: &K) -> Vec<u8> { - <U as generator::StorageMap<K, V>>::key_for(item) + fn key_for<KeyArg: Borrow<K>>(key: KeyArg) -> Vec<u8> { + <U as generator::StorageMap<K, V>>::key_for(key.borrow()) + } + + fn exists<KeyArg: Borrow<K>>(key: KeyArg) -> bool { + U::exists(key.borrow(), &RuntimeStorage) } - fn get(key: &K) -> Option<V> { - U::get(key, &RuntimeStorage) + fn get<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query { + U::get(key.borrow(), &RuntimeStorage) } - fn insert(key: &K, val: &V) { - U::insert(key, val, &RuntimeStorage) + fn insert<KeyArg: Borrow<K>, ValArg: Borrow<V>>(key: KeyArg, val: ValArg) { + U::insert(key.borrow(), val.borrow(), &RuntimeStorage) } - fn remove(key: &K) { - U::remove(key, &RuntimeStorage) + fn remove<KeyArg: Borrow<K>>(key: KeyArg) { + U::remove(key.borrow(), &RuntimeStorage) } - fn take(key: &K) -> Option<V> { - U::take(key, &RuntimeStorage) + fn take<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query { + U::take(key.borrow(), &RuntimeStorage) } } diff --git a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index b7150f9c4c350640c84ef908d233c9c9618f2dc4..63c43ca592414e834452fb3a16a0a360a8869acd 100644 Binary files a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm index e7533bbd880e220b5de92621dde2562f93cf6e01..b43b00f68772fcf6a1054abe5dc4bc26451cf00c 100644 Binary files a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm and b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm differ