Revise storage API.

This commit is contained in:
Gav
2018-01-28 17:08:45 +01:00
parent 59469995b2
commit bfd599e5de
11 changed files with 175 additions and 134 deletions
@@ -17,7 +17,9 @@
//! Endian manager. //! Endian manager.
/// Trait to allow conversion to a know endian representation when sensitive. /// Trait to allow conversion to a know endian representation when sensitive.
// note: the copy bound and static lifetimes are necessary for safety of `Slicable` blanket implementation. /// Types implementing this trait must have a size > 0.
// note: the copy bound and static lifetimes are necessary for safety of `Slicable` blanket
// implementation.
pub trait EndianSensitive: Copy + 'static { pub trait EndianSensitive: Copy + 'static {
fn to_le(self) -> Self { self } fn to_le(self) -> Self { self }
fn to_be(self) -> Self { self } fn to_be(self) -> Self { self }
@@ -49,6 +49,7 @@ pub trait NonTrivialSlicable: Slicable {}
impl<T: EndianSensitive> Slicable for T { impl<T: EndianSensitive> Slicable for T {
fn set_as_slice<F: Fn(&mut [u8], usize) -> bool>(fill_slice: &F) -> Option<Self> { fn set_as_slice<F: Fn(&mut [u8], usize) -> bool>(fill_slice: &F) -> Option<Self> {
let size = mem::size_of::<T>(); let size = mem::size_of::<T>();
assert!(size > 0, "EndianSensitive can never be implemented for a zero-sized type.");
let mut result: T = unsafe { mem::zeroed() }; let mut result: T = unsafe { mem::zeroed() };
let result_slice = unsafe { let result_slice = unsafe {
let ptr = &mut result as *mut _ as *mut u8; let ptr = &mut result as *mut _ as *mut u8;
@@ -62,6 +63,7 @@ impl<T: EndianSensitive> Slicable for T {
} }
fn as_slice_then<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R { fn as_slice_then<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
let size = mem::size_of::<Self>(); let size = mem::size_of::<Self>();
assert!(size > 0, "EndianSensitive can never be implemented for a zero-sized type.");
self.as_le_then(|le| { self.as_le_then(|le| {
let value_slice = unsafe { let value_slice = unsafe {
let ptr = le as *const _ as *const u8; let ptr = le as *const _ as *const u8;
@@ -37,15 +37,14 @@ pub enum Function {
impl Function { impl Function {
/// Derive `Some` value from a `u8`, or `None` if it's invalid. /// Derive `Some` value from a `u8`, or `None` if it's invalid.
pub fn from_u8(value: u8) -> Option<Function> { pub fn from_u8(value: u8) -> Option<Function> {
match value { use self::*;
x if x == Function::StakingStake as u8 => Some(Function::StakingStake), let functions = [Function::StakingStake, Function::StakingUnstake,
x if x == Function::StakingUnstake as u8 => Some(Function::StakingUnstake), Function::StakingTransfer, Function::SessionSetKey, Function::TimestampSet,
x if x == Function::StakingTransfer as u8 => Some(Function::StakingTransfer), Function::GovernancePropose, Function::GovernanceApprove];
x if x == Function::SessionSetKey as u8 => Some(Function::SessionSetKey), if (value as usize) < functions.len() {
x if x == Function::TimestampSet as u8 => Some(Function::TimestampSet), Some(functions[value as usize])
x if x == Function::GovernancePropose as u8 => Some(Function::GovernancePropose), } else {
x if x == Function::GovernanceApprove as u8 => Some(Function::GovernanceApprove), None
_ => None,
} }
} }
} }
@@ -38,14 +38,19 @@ pub enum InternalFunction {
impl InternalFunction { impl InternalFunction {
/// Derive `Some` value from a `u8`, or `None` if it's invalid. /// Derive `Some` value from a `u8`, or `None` if it's invalid.
pub fn from_u8(value: u8) -> Option<InternalFunction> { pub fn from_u8(value: u8) -> Option<InternalFunction> {
match value { use self::*;
x if x == InternalFunction::SystemSetCode as u8 => Some(InternalFunction::SystemSetCode), let functions = [
x if x == InternalFunction::StakingSetSessionsPerEra as u8 => Some(InternalFunction::StakingSetSessionsPerEra), InternalFunction::SystemSetCode,
x if x == InternalFunction::StakingSetBondingDuration as u8 => Some(InternalFunction::StakingSetBondingDuration), InternalFunction::StakingSetSessionsPerEra,
x if x == InternalFunction::StakingSetValidatorCount as u8 => Some(InternalFunction::StakingSetValidatorCount), InternalFunction::StakingSetBondingDuration,
x if x == InternalFunction::GovernanceSetApprovalPpmRequired as u8 => Some(InternalFunction::GovernanceSetApprovalPpmRequired), InternalFunction::StakingSetValidatorCount,
x if x == InternalFunction::SessionSetLength as u8 => Some(InternalFunction::SessionSetLength), InternalFunction::GovernanceSetApprovalPpmRequired,
_ => None, InternalFunction::SessionSetLength
];
if (value as usize) < functions.len() {
Some(functions[value as usize])
} else {
None
} }
} }
} }
@@ -27,14 +27,14 @@
use runtime_std::prelude::*; use runtime_std::prelude::*;
use codec::KeyedVec; use codec::KeyedVec;
use support::{Storable, StorageVec, kill}; use support::storage;
use primitives::{AccountID, Hash, BlockNumber, Proposal}; use primitives::{AccountID, Hash, BlockNumber, Proposal};
use runtime::{staking, system, session}; use runtime::{staking, system, session};
/// The proportion of validators required for a propsal to be approved measured as the number out /// The proportion of validators required for a propsal to be approved measured as the number out
/// of 1000. /// of 1000.
pub fn approval_ppm_required() -> u32 { pub fn approval_ppm_required() -> u32 {
Storable::lookup(b"gov:apr").unwrap_or(1000) storage::get_or(b"gov:apr", 1000)
} }
/// The number of concrete validator approvals required for a proposal to pass. /// The number of concrete validator approvals required for a proposal to pass.
@@ -49,10 +49,10 @@ pub mod public {
/// Proposal is by the `transactor` and will automatically count as an approval. Transactor must /// Proposal is by the `transactor` and will automatically count as an approval. Transactor must
/// be a current validator. It is illegal to propose when there is already a proposal in effect. /// be a current validator. It is illegal to propose when there is already a proposal in effect.
pub fn propose(validator: &AccountID, proposal: &Proposal) { pub fn propose(validator: &AccountID, proposal: &Proposal) {
if Proposal::lookup(b"gov:pro").is_some() { if storage::exists(b"gov:pro") {
panic!("there may only be one proposal per era."); panic!("there may only be one proposal per era.");
} }
proposal.store(b"gov:pro"); storage::put(b"gov:pro", proposal);
approve(validator, staking::current_era()); approve(validator, staking::current_era());
} }
@@ -62,17 +62,17 @@ pub mod public {
if era_index != staking::current_era() { if era_index != staking::current_era() {
panic!("approval vote applied on non-current era.") panic!("approval vote applied on non-current era.")
} }
if Proposal::lookup(b"gov:pro").is_none() { if !storage::exists(b"gov:pro") {
panic!("there must be a proposal in order to approve."); panic!("there must be a proposal in order to approve.");
} }
if session::validators().into_iter().position(|v| &v == validator).is_none() { if session::validators().into_iter().position(|v| &v == validator).is_none() {
panic!("transactor must be a validator to approve."); panic!("transactor must be a validator to approve.");
} }
let key = validator.to_keyed_vec(b"gov:app:"); let key = validator.to_keyed_vec(b"gov:app:");
if bool::lookup(&key).is_some() { if storage::exists(&key) {
panic!("transactor may not approve a proposal twice in one era."); panic!("transactor may not approve a proposal twice in one era.");
} }
true.store(&key); storage::put(&key, &true);
} }
} }
@@ -84,7 +84,7 @@ pub mod privileged {
/// validator. `1000` would require the approval of all validators; `667` would require two-thirds /// validator. `1000` would require the approval of all validators; `667` would require two-thirds
/// (or there abouts) of validators. /// (or there abouts) of validators.
pub fn set_approval_ppm_required(ppm: u32) { pub fn set_approval_ppm_required(ppm: u32) {
ppm.store(b"gov:apr"); storage::put(b"gov:apr", &ppm);
} }
} }
@@ -94,11 +94,10 @@ pub mod internal {
/// Current era is ending; we should finish up any proposals. /// Current era is ending; we should finish up any proposals.
pub fn end_of_an_era() { pub fn end_of_an_era() {
// tally up votes for the current proposal, if any. enact if there are sufficient approvals. // tally up votes for the current proposal, if any. enact if there are sufficient approvals.
if let Some(proposal) = Proposal::lookup(b"gov:pro") { if let Some(proposal) = storage::take::<Proposal>(b"gov:pro") {
kill(b"gov:pro");
let approvals_required = approvals_required(); let approvals_required = approvals_required();
let approved = session::validators().into_iter() let approved = session::validators().into_iter()
.filter_map(|v| bool::take(&v.to_keyed_vec(b"gov:app:"))) .filter_map(|v| storage::take::<bool>(&v.to_keyed_vec(b"gov:app:")))
.take(approvals_required as usize) .take(approvals_required as usize)
.count() as u32; .count() as u32;
if approved == approvals_required { if approved == approvals_required {
@@ -19,7 +19,7 @@
use runtime_std::prelude::*; use runtime_std::prelude::*;
use codec::KeyedVec; use codec::KeyedVec;
use support::{kill, Storable, StorageVec}; use support::{storage, StorageVec};
use primitives::{AccountID, SessionKey, BlockNumber}; use primitives::{AccountID, SessionKey, BlockNumber};
use runtime::{system, staking, consensus}; use runtime::{system, staking, consensus};
@@ -30,7 +30,7 @@ pub fn validators() -> Vec<AccountID> {
/// The number of blocks in each session. /// The number of blocks in each session.
pub fn length() -> BlockNumber { pub fn length() -> BlockNumber {
Storable::lookup_default(b"ses:len") storage::get_or(b"ses:len", 0)
} }
/// The number of validators currently. /// The number of validators currently.
@@ -40,12 +40,12 @@ pub fn validator_count() -> usize {
/// The current era index. /// The current era index.
pub fn current_index() -> BlockNumber { pub fn current_index() -> BlockNumber {
Storable::lookup_default(b"ses:ind") storage::get_or(b"ses:ind", 0)
} }
/// The block number at which the era length last changed. /// The block number at which the era length last changed.
pub fn last_length_change() -> BlockNumber { pub fn last_length_change() -> BlockNumber {
Storable::lookup_default(b"ses:llc") storage::get_or(b"ses:llc", 0)
} }
pub mod public { pub mod public {
@@ -55,7 +55,7 @@ pub mod public {
/// session. /// session.
pub fn set_key(validator: &AccountID, key: &SessionKey) { pub fn set_key(validator: &AccountID, key: &SessionKey) {
// set new value for next session // set new value for next session
key.store(&validator.to_keyed_vec(b"ses:nxt:")); storage::put(&validator.to_keyed_vec(b"ses:nxt:"), key);
} }
} }
@@ -64,7 +64,7 @@ pub mod privileged {
/// Set a new era length. Won't kick in until the next era change (at current length). /// Set a new era length. Won't kick in until the next era change (at current length).
pub fn set_length(new: BlockNumber) { pub fn set_length(new: BlockNumber) {
new.store(b"ses:nln"); storage::put(b"ses:nln", &new);
} }
} }
@@ -102,21 +102,20 @@ impl StorageVec for ValidatorStorageVec {
/// Move onto next session: register the new authority set. /// Move onto next session: register the new authority set.
fn rotate_session() { fn rotate_session() {
// Increment current session index. // Increment current session index.
(current_index() + 1).store(b"ses:ind"); storage::put(b"ses:ind", &(current_index() + 1));
// Enact era length change. // Enact era length change.
if let Some(next_len) = u64::lookup(b"ses:nln") { if let Some(next_len) = storage::get::<u64>(b"ses:nln") {
next_len.store(b"ses:len"); storage::put(b"ses:len", &next_len);
system::block_number().store(b"ses:llc"); storage::put(b"ses:llc", &system::block_number());
kill(b"ses:nln"); storage::kill(b"ses:nln");
} }
// Update any changes in session keys. // Update any changes in session keys.
validators().iter().enumerate().for_each(|(i, v)| { validators().iter().enumerate().for_each(|(i, v)| {
let k = v.to_keyed_vec(b"ses:nxt:"); let k = v.to_keyed_vec(b"ses:nxt:");
if let Some(n) = Storable::lookup(&k) { if let Some(n) = storage::take(&k) {
consensus::internal::set_authority(i as u32, &n); consensus::internal::set_authority(i as u32, &n);
kill(&k);
} }
}); });
} }
@@ -19,7 +19,7 @@
use runtime_std::prelude::*; use runtime_std::prelude::*;
use runtime_std::cell::RefCell; use runtime_std::cell::RefCell;
use codec::KeyedVec; use codec::KeyedVec;
use support::{Storable, StorageVec}; use support::{storage, StorageVec};
use primitives::{BlockNumber, AccountID}; use primitives::{BlockNumber, AccountID};
use runtime::{system, session, governance}; use runtime::{system, session, governance};
@@ -31,12 +31,12 @@ pub type Bondage = u64;
/// The length of the bonding duration in eras. /// The length of the bonding duration in eras.
pub fn bonding_duration() -> BlockNumber { pub fn bonding_duration() -> BlockNumber {
Storable::lookup_default(b"sta:loc") storage::get_default(b"sta:loc")
} }
/// The length of a staking era in sessions. /// The length of a staking era in sessions.
pub fn validator_count() -> usize { pub fn validator_count() -> usize {
u32::lookup_default(b"sta:vac") as usize storage::get_default::<u32>(b"sta:vac") as usize
} }
/// The length of a staking era in blocks. /// The length of a staking era in blocks.
@@ -46,27 +46,27 @@ pub fn era_length() -> BlockNumber {
/// The length of a staking era in sessions. /// The length of a staking era in sessions.
pub fn sessions_per_era() -> BlockNumber { pub fn sessions_per_era() -> BlockNumber {
Storable::lookup_default(b"sta:spe") storage::get_default(b"sta:spe")
} }
/// The current era index. /// The current era index.
pub fn current_era() -> BlockNumber { pub fn current_era() -> BlockNumber {
Storable::lookup_default(b"sta:era") storage::get_default(b"sta:era")
} }
/// The block number at which the era length last changed. /// The block number at which the era length last changed.
pub fn last_era_length_change() -> BlockNumber { pub fn last_era_length_change() -> BlockNumber {
Storable::lookup_default(b"sta:lec") storage::get_default(b"sta:lec")
} }
/// The balance of a given account. /// The balance of a given account.
pub fn balance(who: &AccountID) -> Balance { pub fn balance(who: &AccountID) -> Balance {
Storable::lookup_default(&who.to_keyed_vec(b"sta:bal:")) storage::get_default(&who.to_keyed_vec(b"sta:bal:"))
} }
/// The liquidity-state of a given account. /// The liquidity-state of a given account.
pub fn bondage(who: &AccountID) -> Bondage { pub fn bondage(who: &AccountID) -> Bondage {
Storable::lookup_default(&who.to_keyed_vec(b"sta:bon:")) storage::get_default(&who.to_keyed_vec(b"sta:bon:"))
} }
// Each identity's stake may be in one of three bondage states, given by an integer: // Each identity's stake may be in one of three bondage states, given by an integer:
@@ -81,14 +81,14 @@ pub mod public {
/// Transfer some unlocked staking balance to another staker. /// Transfer some unlocked staking balance to another staker.
pub fn transfer(transactor: &AccountID, dest: &AccountID, value: Balance) { pub fn transfer(transactor: &AccountID, dest: &AccountID, value: Balance) {
let from_key = transactor.to_keyed_vec(b"sta:bal:"); let from_key = transactor.to_keyed_vec(b"sta:bal:");
let from_balance = Balance::lookup_default(&from_key); let from_balance = storage::get_default::<Balance>(&from_key);
assert!(from_balance >= value); assert!(from_balance >= value);
let to_key = dest.to_keyed_vec(b"sta:bal:"); let to_key = dest.to_keyed_vec(b"sta:bal:");
let to_balance: Balance = Storable::lookup_default(&to_key); let to_balance: Balance = storage::get_default(&to_key);
assert!(bondage(transactor) <= bondage(dest)); assert!(bondage(transactor) <= bondage(dest));
assert!(to_balance + value > to_balance); // no overflow assert!(to_balance + value > to_balance); // no overflow
(from_balance - value).store(&from_key); storage::put(&from_key, &(from_balance - value));
(to_balance + value).store(&to_key); storage::put(&to_key, &(to_balance + value));
} }
/// Declare the desire to stake for the transactor. /// Declare the desire to stake for the transactor.
@@ -100,7 +100,7 @@ pub mod public {
assert!(intentions.iter().find(|t| *t == transactor).is_none(), "Cannot stake if already staked."); assert!(intentions.iter().find(|t| *t == transactor).is_none(), "Cannot stake if already staked.");
intentions.push(transactor.clone()); intentions.push(transactor.clone());
IntentionStorageVec::set_items(&intentions); IntentionStorageVec::set_items(&intentions);
u64::max_value().store(&transactor.to_keyed_vec(b"sta:bon:")); storage::put(&transactor.to_keyed_vec(b"sta:bon:"), &u64::max_value());
} }
/// Retract the desire to stake for the transactor. /// Retract the desire to stake for the transactor.
@@ -114,7 +114,7 @@ pub mod public {
panic!("Cannot unstake if not already staked."); panic!("Cannot unstake if not already staked.");
} }
IntentionStorageVec::set_items(&intentions); IntentionStorageVec::set_items(&intentions);
(current_era() + bonding_duration()).store(&transactor.to_keyed_vec(b"sta:bon:")); storage::put(&transactor.to_keyed_vec(b"sta:bon:"), &(current_era() + bonding_duration()));
} }
} }
@@ -123,17 +123,17 @@ pub mod privileged {
/// Set the number of sessions in an era. /// Set the number of sessions in an era.
pub fn set_sessions_per_era(new: BlockNumber) { pub fn set_sessions_per_era(new: BlockNumber) {
new.store(b"sta:nse"); storage::put(b"sta:nse", &new);
} }
/// The length of the bonding duration in eras. /// The length of the bonding duration in eras.
pub fn set_bonding_duration(new: BlockNumber) { pub fn set_bonding_duration(new: BlockNumber) {
new.store(b"sta:loc"); storage::put(b"sta:loc", &new);
} }
/// The length of a staking era in sessions. /// The length of a staking era in sessions.
pub fn set_validator_count(new: usize) { pub fn set_validator_count(new: usize) {
(new as u32).store(b"sta:vac"); storage::put(b"sta:vac", &(new as u32));
} }
} }
@@ -164,13 +164,13 @@ fn new_era() {
governance::internal::end_of_an_era(); governance::internal::end_of_an_era();
// Increment current era. // Increment current era.
(current_era() + 1).store(b"sta:era"); storage::put(b"sta:era", &(current_era() + 1));
// Enact era length change. // Enact era length change.
let next_spe: u64 = Storable::lookup_default(b"sta:nse"); let next_spe: u64 = storage::get_default(b"sta:nse");
if next_spe > 0 && next_spe != sessions_per_era() { if next_spe > 0 && next_spe != sessions_per_era() {
next_spe.store(b"sta:spe"); storage::put(b"sta:spe", &next_spe);
system::block_number().store(b"sta:lec"); storage::put(b"sta:lec", &system::block_number());
} }
// evaluate desired staking amounts and nominations and optimise to find the best // evaluate desired staking amounts and nominations and optimise to find the best
@@ -20,7 +20,7 @@
use runtime_std::prelude::*; use runtime_std::prelude::*;
use runtime_std::{mem, print}; use runtime_std::{mem, print};
use codec::KeyedVec; use codec::KeyedVec;
use support::{Hashable, Storable, with_env}; use support::{Hashable, storage, with_env};
use primitives::{Block, BlockNumber, Hash, UncheckedTransaction, TxOrder}; use primitives::{Block, BlockNumber, Hash, UncheckedTransaction, TxOrder};
use runtime::{staking, session}; use runtime::{staking, session};
@@ -31,7 +31,7 @@ pub fn block_number() -> BlockNumber {
/// Get the block hash of a given block (uses storage). /// Get the block hash of a given block (uses storage).
pub fn block_hash(number: BlockNumber) -> Hash { pub fn block_hash(number: BlockNumber) -> Hash {
Storable::lookup_default(&number.to_keyed_vec(b"sys:old:")) storage::get_default(&number.to_keyed_vec(b"sys:old:"))
} }
pub mod privileged { pub mod privileged {
@@ -39,7 +39,7 @@ pub mod privileged {
/// Set the new code. /// Set the new code.
pub fn set_code(new: &[u8]) { pub fn set_code(new: &[u8]) {
new.store(b":code"); storage::put_raw(b":code", new);
} }
} }
@@ -77,7 +77,7 @@ pub mod internal {
// store the header hash in storage. // store the header hash in storage.
let header_hash_key = header.number.to_keyed_vec(b"sys:old:"); let header_hash_key = header.number.to_keyed_vec(b"sys:old:");
header.blake2_256().store(&header_hash_key); storage::put(&header_hash_key, &header.blake2_256());
// execute transactions // execute transactions
block.transactions.iter().for_each(execute_transaction); block.transactions.iter().for_each(execute_transaction);
@@ -102,11 +102,11 @@ pub mod internal {
// check nonce // check nonce
let nonce_key = tx.signed.to_keyed_vec(b"sys:non:"); let nonce_key = tx.signed.to_keyed_vec(b"sys:non:");
let expected_nonce: TxOrder = Storable::lookup_default(&nonce_key); let expected_nonce: TxOrder = storage::get_default(&nonce_key);
assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce"); assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce");
// increment nonce in storage // increment nonce in storage
(expected_nonce + 1).store(&nonce_key); storage::put(&nonce_key, &(expected_nonce + 1));
// decode parameters and dispatch // decode parameters and dispatch
tx.function.dispatch(&tx.signed, &tx.input_data); tx.function.dispatch(&tx.signed, &tx.input_data);
@@ -16,14 +16,14 @@
//! Timestamp manager: just handles the current timestamp. //! Timestamp manager: just handles the current timestamp.
use support::Storable; use support::storage;
/// Representation of a time. /// Representation of a time.
pub type Timestamp = u64; pub type Timestamp = u64;
/// Get the current time. /// Get the current time.
pub fn get() -> Timestamp { pub fn get() -> Timestamp {
Storable::lookup_default(b"tim:val") storage::get_default(b"tim:val")
} }
pub mod public { pub mod public {
@@ -31,7 +31,7 @@ pub mod public {
/// Set the current time. /// Set the current time.
pub fn set(now: Timestamp) { pub fn set(now: Timestamp) {
now.store(b"tim:val") storage::put(b"tim:val", &now);
} }
} }
@@ -17,7 +17,7 @@
//! Support code for the runtime. //! Support code for the runtime.
mod environment; mod environment;
mod storable; pub mod storage;
mod hashable; mod hashable;
#[cfg(feature = "with-std")] #[cfg(feature = "with-std")]
mod statichex; mod statichex;
@@ -25,8 +25,8 @@ mod statichex;
#[cfg(feature = "with-std")] #[cfg(feature = "with-std")]
mod testing; mod testing;
pub use self::environment::{Environment, with_env}; pub use self::environment::with_env;
pub use self::storable::{StorageVec, Storable, kill}; pub use self::storage::StorageVec;
pub use self::hashable::Hashable; pub use self::hashable::Hashable;
#[cfg(feature = "with-std")] #[cfg(feature = "with-std")]
pub use self::statichex::{StaticHexConversion, StaticHexInto}; pub use self::statichex::{StaticHexConversion, StaticHexInto};
@@ -20,60 +20,95 @@ use runtime_std::prelude::*;
use runtime_std::{self, twox_128}; use runtime_std::{self, twox_128};
use codec::{Slicable, KeyedVec}; use codec::{Slicable, KeyedVec};
/// Trait for a value which may be stored in the storage DB.
pub trait Storable {
/// Lookup the value in storage and deserialise, giving a default value if not found.
fn lookup_default(key: &[u8]) -> Self where Self: Sized + Default {
Self::lookup(key).unwrap_or_else(Default::default)
}
/// Lookup `Some` value in storage and deserialise; `None` if it's not there.
fn lookup(_key: &[u8]) -> Option<Self> where Self: Sized {
unimplemented!()
}
/// Retrives and returns the serialised value of a key from storage, removing it immediately.
fn take(key: &[u8]) -> Option<Self> where Self: Sized {
if let Some(value) = Self::lookup(key) {
kill(key);
Some(value)
} else {
None
}
}
/// Place the value in storage under `key`.
fn store(&self, key: &[u8]);
}
// TODO: consider using blake256 to avoid possible preimage attack. // TODO: consider using blake256 to avoid possible preimage attack.
/// Remove `key` from storage. /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
pub fn get<T: Slicable + Sized>(key: &[u8]) -> Option<T> {
Slicable::set_as_slice(&|out, offset|
runtime_std::read_storage(&twox_128(key)[..], out, offset) >= out.len()
)
}
/// Return the value of the item in storage under `key`, or the type's default if there is no
/// explicit entry.
pub fn get_default<T: Slicable + Sized + Default>(key: &[u8]) -> T {
get(key).unwrap_or_else(Default::default)
}
/// Return the value of the item in storage under `key`, or `default_value` if there is no
/// explicit entry.
pub fn get_or<T: Slicable + Sized>(key: &[u8], default_value: T) -> T {
get(key).unwrap_or(default_value)
}
/// Return the value of the item in storage under `key`, or `default_value()` if there is no
/// explicit entry.
pub fn get_or_else<T: Slicable + Sized, F: FnOnce() -> T>(key: &[u8], default_value: F) -> T {
get(key).unwrap_or_else(default_value)
}
/// Please `value` in storage under `key`.
pub fn put<T: Slicable>(key: &[u8], value: &T) {
value.as_slice_then(|slice| runtime_std::set_storage(&twox_128(key)[..], slice));
}
/// Please `value` in storage under `key`.
pub fn place<T: Slicable>(key: &[u8], value: T) {
value.as_slice_then(|slice| runtime_std::set_storage(&twox_128(key)[..], slice));
}
/// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise.
pub fn take<T: Slicable + Sized>(key: &[u8]) -> Option<T> {
let r = get(key);
if r.is_some() {
kill(key);
}
r
}
/// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage,
/// the default for its type.
pub fn take_default<T: Slicable + Sized + Default>(key: &[u8]) -> T {
take(key).unwrap_or_else(Default::default)
}
/// Return the value of the item in storage under `key`, or `default_value` if there is no
/// explicit entry. Ensure there is no explicit entry on return.
pub fn take_or<T: Slicable + Sized>(key: &[u8], default_value: T) -> T {
take(key).unwrap_or(default_value)
}
/// Return the value of the item in storage under `key`, or `default_value()` if there is no
/// explicit entry. Ensure there is no explicit entry on return.
pub fn take_or_else<T: Slicable + Sized, F: FnOnce() -> T>(key: &[u8], default_value: F) -> T {
take(key).unwrap_or_else(default_value)
}
/// Check to see if `key` has an explicit entry in storage.
pub fn exists(key: &[u8]) -> bool {
let mut x = [0u8; 1];
runtime_std::read_storage(&twox_128(key)[..], &mut x[..], 0) == 1
}
/// Ensure `key` has no explicit entry in storage.
pub fn kill(key: &[u8]) { pub fn kill(key: &[u8]) {
runtime_std::set_storage(&twox_128(key)[..], b""); runtime_std::set_storage(&twox_128(key)[..], b"");
} }
impl<T: Sized + Slicable> Storable for T { /// Get a Vec of bytes from storage.
fn lookup(key: &[u8]) -> Option<Self> { pub fn get_raw(key: &[u8]) -> Vec<u8> {
Slicable::set_as_slice(&|out, offset| runtime_std::storage(&twox_128(key)[..])
runtime_std::read_storage(&twox_128(key)[..], out, offset) >= out.len()
)
}
fn store(&self, key: &[u8]) {
self.as_slice_then(|slice| runtime_std::set_storage(&twox_128(key)[..], slice));
}
} }
impl Storable for [u8] { /// Put a raw byte slice into storage.
fn store(&self, key: &[u8]) { pub fn put_raw(key: &[u8], value: &[u8]) {
runtime_std::set_storage(&twox_128(key)[..], self) runtime_std::set_storage(&twox_128(key)[..], value)
}
} }
/// A trait to conveniently store a vector of storable data. /// A trait to conveniently store a vector of storable data.
// TODO: add iterator support // TODO: add iterator support
pub trait StorageVec { pub trait StorageVec {
type Item: Default + Sized + Storable; type Item: Default + Sized + Slicable;
const PREFIX: &'static [u8]; const PREFIX: &'static [u8];
/// Get the current set of items. /// Get the current set of items.
@@ -88,20 +123,20 @@ pub trait StorageVec {
} }
fn set_item(index: u32, item: &Self::Item) { fn set_item(index: u32, item: &Self::Item) {
item.store(&index.to_keyed_vec(Self::PREFIX)); put(&index.to_keyed_vec(Self::PREFIX), item);
} }
fn item(index: u32) -> Self::Item { fn item(index: u32) -> Self::Item {
Storable::lookup_default(&index.to_keyed_vec(Self::PREFIX)) get_default(&index.to_keyed_vec(Self::PREFIX))
} }
fn set_count(count: u32) { fn set_count(count: u32) {
(count..Self::count()).for_each(|i| Self::set_item(i, &Self::Item::default())); (count..Self::count()).for_each(|i| Self::set_item(i, &Self::Item::default()));
count.store(&b"len".to_keyed_vec(Self::PREFIX)); put(&b"len".to_keyed_vec(Self::PREFIX), &count);
} }
fn count() -> u32 { fn count() -> u32 {
Storable::lookup_default(&b"len".to_keyed_vec(Self::PREFIX)) get_default(&b"len".to_keyed_vec(Self::PREFIX))
} }
} }
@@ -118,14 +153,14 @@ mod tests {
let mut t = TestExternalities { storage: HashMap::new(), }; let mut t = TestExternalities { storage: HashMap::new(), };
with_externalities(&mut t, || { with_externalities(&mut t, || {
let x = 69u32; let x = 69u32;
x.store(b":test"); put(b":test", &x);
let y = u32::lookup(b":test").unwrap(); let y: u32 = get(b":test").unwrap();
assert_eq!(x, y); assert_eq!(x, y);
}); });
with_externalities(&mut t, || { with_externalities(&mut t, || {
let x = 69426942i64; let x = 69426942i64;
x.store(b":test"); put(b":test", &x);
let y = i64::lookup(b":test").unwrap(); let y: i64 = get(b":test").unwrap();
assert_eq!(x, y); assert_eq!(x, y);
}); });
} }
@@ -135,15 +170,15 @@ mod tests {
let mut t = TestExternalities { storage: HashMap::new(), }; let mut t = TestExternalities { storage: HashMap::new(), };
with_externalities(&mut t, || { with_externalities(&mut t, || {
let x = true; let x = true;
x.store(b":test"); put(b":test", &x);
let y = bool::lookup(b":test").unwrap(); let y: bool = get(b":test").unwrap();
assert_eq!(x, y); assert_eq!(x, y);
}); });
with_externalities(&mut t, || { with_externalities(&mut t, || {
let x = false; let x = false;
x.store(b":test"); put(b":test", &x);
let y = bool::lookup(b":test").unwrap(); let y: bool = get(b":test").unwrap();
assert_eq!(x, y); assert_eq!(x, y);
}); });
} }
@@ -155,7 +190,7 @@ mod tests {
runtime_std::set_storage(&twox_128(b":test"), b"\x0b\0\0\0Hello world"); runtime_std::set_storage(&twox_128(b":test"), b"\x0b\0\0\0Hello world");
let x = b"Hello world".to_vec(); let x = b"Hello world".to_vec();
println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test")))); println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test"))));
let y = <Vec<u8>>::lookup(b":test").unwrap(); let y = get::<Vec<u8>>(b":test").unwrap();
assert_eq!(x, y); assert_eq!(x, y);
}); });
@@ -167,13 +202,13 @@ mod tests {
let x = b"Hello world".to_vec(); let x = b"Hello world".to_vec();
with_externalities(&mut t, || { with_externalities(&mut t, || {
x.store(b":test"); put(b":test", &x);
}); });
println!("Ext is {:?}", t); println!("Ext is {:?}", t);
with_externalities(&mut t, || { with_externalities(&mut t, || {
println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test")))); println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test"))));
let y = <Vec<u8>>::lookup(b":test").unwrap(); let y: Vec<u8> = get(b":test").unwrap();
assert_eq!(x, y); assert_eq!(x, y);
}); });
} }
@@ -184,8 +219,8 @@ mod tests {
let mut t = TestExternalities { storage: HashMap::new(), }; let mut t = TestExternalities { storage: HashMap::new(), };
with_externalities(&mut t, || { with_externalities(&mut t, || {
let x = Proposal { function: InternalFunction::StakingSetSessionsPerEra, input_data: b"Hello world".to_vec() }; let x = Proposal { function: InternalFunction::StakingSetSessionsPerEra, input_data: b"Hello world".to_vec() };
x.store(b":test"); put(b":test", &x);
let y = Proposal::lookup(b":test").unwrap(); let y: Proposal = get(b":test").unwrap();
assert_eq!(x, y); assert_eq!(x, y);
}); });
} }