Refactor away from opaque hashes (#5226)

* System.BlockHash

* Fix hash

* Introduce K/V iteration in all _concat maps

Also move across:
- System.Account (blake2_128_concat)
- Balances.Locks (twox_64_concat)
- ElectionsPhragmen.VotesOf (twox_64_concat)
- ElectionsPhragmen.StakeOf (twox_64_concat)
- Identity.IdentityOf (twox_64_concat)
- Identity.SubsOf (twox_64_concat)
- Society.Payouts (twox_64_concat)
- Session.NextKeys (twox_64_concat)
- Identity.SuperOf (blake2_128_concat)
- Session.KeyOwner (blake2_128_concat)
- Society.SuspendedCandidates (twox_64_concat)
- Society.SuspendedMembers (twox_64_concat)
- Society.Vouching (twox_64_concat)
- Society.Strikes (twox_64_concat)
- System.EventTopics
- Balances.Account

* Build fixes

* Ensure migration happens in correct order

* Staking.*

* Vesting.* Offences.*

* Democracy.*

* Babe.* Collective.*

* Grandpa.*

* Assets.* Benchmark.* Contracts.* Elections.* Asset.* Nicks.*

Also introduce real account list

* ImOnline.*

* Treasury.*

* Recovery.*

* Final bits.

* Docs

* Fix one test

* Fix test

* All passing except the UI tests

* Remove linked_map part 1

* Remove linked_map

* Some iterator utils for double maps.

* Remove old migrations

* Introduce tombstone for LinkedMap type

* Migration for genesis hash

* Fix build

* Fix hash

* Rename Map is_linked -> unused, keeping backwards compat (#5256)

* Update frame/balances/src/lib.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update frame/elections/src/lib.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Remove old migration code.

* Update frame/system/src/lib.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update bin/node/runtime/src/lib.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Fix hash

* fix session migration

* Fix watning

Co-authored-by: Jaco Greeff <jacogr@gmail.com>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: Robert Habermeier <rphmeier@gmail.com>
This commit is contained in:
Gavin Wood
2020-03-16 23:19:53 +01:00
committed by GitHub
parent 846a9ce8c6
commit af9083f53b
94 changed files with 1111 additions and 2020 deletions
@@ -40,7 +40,7 @@ impl system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
impl Trait for Test {
@@ -162,7 +162,7 @@ impl system::Trait for Runtime {
/// This type is being generated by `construct_runtime!`.
type ModuleToIndex = ModuleToIndex;
/// What to do if a new account is created.
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
/// What to do if an account is fully reaped from the system.
type OnKilledAccount = ();
/// The data to be stored in an account.
+1
View File
@@ -140,6 +140,7 @@ impl frame_system::Trait for Runtime {
type Version = Version;
type ModuleToIndex = ModuleToIndex;
type AccountData = pallet_balances::AccountData<Balance>;
type MigrateAccount = (Balances, Identity, Democracy, Elections, ImOnline, Recovery, Session, Society, Staking, Vesting);
type OnNewAccount = ();
type OnKilledAccount = ();
}
+3 -3
View File
@@ -228,11 +228,11 @@ decl_error! {
decl_storage! {
trait Store for Module<T: Trait> as Assets {
/// The number of units of assets held by any given account.
Balances: map hasher(blake2_256) (T::AssetId, T::AccountId) => T::Balance;
Balances: map hasher(blake2_128_concat) (T::AssetId, T::AccountId) => T::Balance;
/// The next asset identifier up for grabs.
NextAssetId get(fn next_asset_id): T::AssetId;
/// The total unit supply of an asset.
TotalSupply: map hasher(blake2_256) T::AssetId => T::Balance;
TotalSupply: map hasher(twox_64_concat) T::AssetId => T::Balance;
}
}
@@ -294,7 +294,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
impl Trait for Test {
+1 -1
View File
@@ -62,7 +62,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
@@ -158,7 +158,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+1 -1
View File
@@ -432,7 +432,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+7 -1
View File
@@ -146,7 +146,7 @@ decl_storage! {
/// We reset all segments and return to `0` at the beginning of every
/// epoch.
SegmentIndex build(|_| 0): u32;
UnderConstruction: map hasher(blake2_256) u32 => Vec<[u8; 32 /* VRF_OUTPUT_LENGTH */]>;
UnderConstruction: map hasher(twox_64_concat) u32 => Vec<[u8; 32 /* VRF_OUTPUT_LENGTH */]>;
/// Temporary value (cleared at block finalization) which is `Some`
/// if per-block initialization has already been called for current block.
@@ -188,6 +188,12 @@ decl_module! {
Self::deposit_vrf_output(&vrf_output);
}
}
fn on_runtime_upgrade() {
for i in 0..=SegmentIndex::get() {
UnderConstruction::migrate_key_from_blake(i);
}
}
}
}
+1 -1
View File
@@ -65,7 +65,7 @@ impl frame_system::Trait for Test {
type MaximumBlockLength = MaximumBlockLength;
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+10 -4
View File
@@ -167,7 +167,7 @@ use frame_support::{
Currency, OnKilledAccount, OnUnbalanced, TryDrop, StoredMap,
WithdrawReason, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement,
Imbalance, SignedImbalance, ReservableCurrency, Get, ExistenceRequirement::KeepAlive,
ExistenceRequirement::AllowDeath, IsDeadAccount, BalanceStatus as Status
ExistenceRequirement::AllowDeath, IsDeadAccount, BalanceStatus as Status, MigrateAccount,
}
};
use sp_runtime::{
@@ -372,11 +372,11 @@ decl_storage! {
/// is ever zero, then the entry *MUST* be removed.
///
/// NOTE: This is only used in the case that this module is used to store balances.
pub Account: map hasher(blake2_256) T::AccountId => AccountData<T::Balance>;
pub Account: map hasher(blake2_128_concat) T::AccountId => AccountData<T::Balance>;
/// Any liquidity locks on some account balances.
/// NOTE: Should only be accessed when setting, changing and freeing a lock.
pub Locks get(fn locks): map hasher(blake2_256) T::AccountId => Vec<BalanceLock<T::Balance>>;
pub Locks get(fn locks): map hasher(blake2_128_concat) T::AccountId => Vec<BalanceLock<T::Balance>>;
/// Storage version of the pallet.
///
@@ -531,6 +531,12 @@ decl_module! {
}
}
impl<T: Trait<I>, I: Instance> MigrateAccount<T::AccountId> for Module<T, I> {
fn migrate_account(account: &T::AccountId) {
Locks::<T, I>::migrate_key_from_blake(account);
}
}
impl<T: Trait<I>, I: Instance> Module<T, I> {
// PRIVATE MUTABLES
@@ -850,7 +856,7 @@ impl<T: Subtrait<I>, I: Instance> frame_system::Trait for ElevatedTrait<T, I> {
type AvailableBlockRatio = T::AvailableBlockRatio;
type Version = T::Version;
type ModuleToIndex = T::ModuleToIndex;
type OnNewAccount = T::OnNewAccount;
type MigrateAccount = (); type OnNewAccount = T::OnNewAccount;
type OnKilledAccount = T::OnKilledAccount;
type AccountData = T::AccountData;
}
@@ -66,7 +66,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = super::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
+1 -1
View File
@@ -66,7 +66,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = super::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = Module<Test>;
}
parameter_types! {
+3 -3
View File
@@ -41,10 +41,10 @@ pub trait Trait: system::Trait {
decl_storage! {
trait Store for Module<T: Trait> as Benchmark {
MyMemberList: Vec<T::AccountId>;
MyMemberMap: map hasher(blake2_256) T::AccountId => bool;
MyMemberMap: map hasher(blake2_128_concat) T::AccountId => bool;
MyValue: u32;
MyMap: map hasher(blake2_256) u32 => u32;
MyDoubleMap: double_map hasher(blake2_256) u32, hasher(blake2_256) u32 => u32;
MyMap: map hasher(twox_64_concat) u32 => u32;
MyDoubleMap: double_map hasher(twox_64_concat) u32, hasher(identity) u32 => u32;
}
}
+1 -1
View File
@@ -71,7 +71,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+18 -3
View File
@@ -106,10 +106,10 @@ decl_storage! {
pub Proposals get(fn proposals): Vec<T::Hash>;
/// Actual proposal for a given hash, if it's current.
pub ProposalOf get(fn proposal_of):
map hasher(blake2_256) T::Hash => Option<<T as Trait<I>>::Proposal>;
map hasher(identity) T::Hash => Option<<T as Trait<I>>::Proposal>;
/// Votes on a given proposal, if it is ongoing.
pub Voting get(fn voting):
map hasher(blake2_256) T::Hash => Option<Votes<T::AccountId, T::BlockNumber>>;
map hasher(identity) T::Hash => Option<Votes<T::AccountId, T::BlockNumber>>;
/// Proposals so far.
pub ProposalCount get(fn proposal_count): u32;
/// The current members of the collective. This is stored sorted (just by value).
@@ -168,6 +168,17 @@ decl_error! {
}
}
mod migration {
use super::*;
pub fn migrate<T: Trait<I>, I: Instance>() {
for p in Proposals::<T, I>::get().into_iter() {
ProposalOf::<T, I>::migrate_key_from_blake(&p);
Voting::<T, I>::migrate_key_from_blake(&p);
}
}
}
// Note: this module is not benchmarked. The weights are obtained based on the similarity of the
// executed logic with other democracy function. Note that councillor operations are assigned to the
// operational class.
@@ -177,6 +188,10 @@ decl_module! {
fn deposit_event() = default;
fn on_runtime_upgrade() {
migration::migrate::<T, I>();
}
/// Set the collective's membership.
///
/// - `new_members`: The new member list. Be nice to the chain and
@@ -535,7 +550,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
impl Trait<Instance1> for Test {
+3 -8
View File
@@ -98,7 +98,6 @@ mod rent;
#[cfg(test)]
mod tests;
mod migration;
use crate::exec::ExecutionContext;
use crate::account_db::{AccountDb, DirectAccountDb};
@@ -667,10 +666,6 @@ decl_module! {
fn on_finalize() {
GasSpent::kill();
}
fn on_runtime_upgrade() {
migration::on_runtime_upgrade::<T>()
}
}
}
@@ -934,13 +929,13 @@ decl_storage! {
/// Current cost schedule for contracts.
CurrentSchedule get(fn current_schedule) config(): Schedule = Schedule::default();
/// A mapping from an original code hash to the original code, untouched by instrumentation.
pub PristineCode: map hasher(blake2_256) CodeHash<T> => Option<Vec<u8>>;
pub PristineCode: map hasher(identity) CodeHash<T> => Option<Vec<u8>>;
/// A mapping between an original code hash and instrumented wasm code, ready for execution.
pub CodeStorage: map hasher(blake2_256) CodeHash<T> => Option<wasm::PrefabWasmModule>;
pub CodeStorage: map hasher(identity) CodeHash<T> => Option<wasm::PrefabWasmModule>;
/// The subtrie counter.
pub AccountCounter: u64 = 0;
/// The code associated with a given account.
pub ContractInfoOf: map hasher(blake2_256) T::AccountId => Option<ContractInfo<T>>;
pub ContractInfoOf: map hasher(twox_64_concat) T::AccountId => Option<ContractInfo<T>>;
/// The price of one unit of gas.
GasPrice get(fn gas_price) config(): BalanceOf<T> = 1.into();
}
@@ -1,62 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Migration code to update storage.
use super::*;
use frame_support::storage::migration::{put_storage_value, take_storage_value, StorageIterator};
pub fn on_runtime_upgrade<T: Trait>() {
change_name_contract_to_contracts::<T>()
}
// Change the storage name used by this pallet from `Contract` to `Contracts`.
//
// Since the format of the storage items themselves have not changed, we do not
// need to keep track of a storage version. If the runtime does not need to be
// upgraded, nothing here will happen anyway.
fn change_name_contract_to_contracts<T: Trait>() {
sp_runtime::print("Migrating Contracts.");
if let Some(gas_spent) = take_storage_value::<Gas>(b"Contract", b"GasSpent", &[]) {
put_storage_value(b"Contracts", b"GasSpent", &[], gas_spent);
}
if let Some(current_schedule) = take_storage_value::<Schedule>(b"Contract", b"CurrentSchedule", &[]) {
put_storage_value(b"Contracts", b"CurrentSchedule", &[], current_schedule);
}
for (hash, pristine_code) in StorageIterator::<Vec<u8>>::new(b"Contract", b"PristineCode").drain() {
put_storage_value(b"Contracts", b"PristineCode", &hash, pristine_code);
}
for (hash, code_storage) in StorageIterator::<wasm::PrefabWasmModule>::new(b"Contract", b"CodeStorage").drain() {
put_storage_value(b"Contracts", b"CodeStorage", &hash, code_storage);
}
if let Some(current_schedule) = take_storage_value::<u64>(b"Contract", b"AccountCounter", &[]) {
put_storage_value(b"Contracts", b"AccountCounter", &[], current_schedule);
}
for (hash, contract_info_of) in StorageIterator::<ContractInfo<T>>::new(b"Contract", b"ContractInfoOf").drain() {
put_storage_value(b"Contracts", b"ContractInfoOf", &hash, contract_info_of);
}
if let Some(get_price) = take_storage_value::<BalanceOf<T>>(b"Contract", b"GetPrice", &[]) {
put_storage_value(b"Contracts", b"GetPrice", &[], get_price);
}
}
+1 -1
View File
@@ -116,7 +116,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = Contracts;
}
impl pallet_balances::Trait for Test {
+46 -13
View File
@@ -159,7 +159,7 @@ use sp_runtime::{
};
use codec::{Ref, Encode, Decode, Input, Output};
use frame_support::{
decl_module, decl_storage, decl_event, decl_error, ensure, Parameter,
decl_module, decl_storage, decl_event, decl_error, ensure, Parameter, IterableStorageMap,
weights::SimpleDispatchInfo,
traits::{
Currency, ReservableCurrency, LockableCurrency, WithdrawReason, LockIdentifier, Get,
@@ -170,6 +170,7 @@ use frame_system::{self as system, ensure_signed, ensure_root};
mod vote_threshold;
pub use vote_threshold::{Approved, VoteThreshold};
use frame_support::traits::MigrateAccount;
const DEMOCRACY_ID: LockIdentifier = *b"democrac";
@@ -420,11 +421,11 @@ decl_storage! {
/// Map of hashes to the proposal preimage, along with who registered it and their deposit.
/// The block number is the block at which it was deposited.
pub Preimages:
map hasher(blake2_256) T::Hash
map hasher(identity) T::Hash
=> Option<(Vec<u8>, T::AccountId, BalanceOf<T>, T::BlockNumber)>;
/// Those who have locked a deposit.
pub DepositOf get(fn deposit_of):
map hasher(blake2_256) PropIndex => Option<(BalanceOf<T>, Vec<T::AccountId>)>;
map hasher(twox_64_concat) PropIndex => Option<(BalanceOf<T>, Vec<T::AccountId>)>;
/// The next free referendum index, aka the number of referenda started so far.
pub ReferendumCount get(fn referendum_count) build(|_| 0 as ReferendumIndex): ReferendumIndex;
@@ -433,32 +434,32 @@ decl_storage! {
pub LowestUnbaked get(fn lowest_unbaked) build(|_| 0 as ReferendumIndex): ReferendumIndex;
/// Information concerning any given referendum.
pub ReferendumInfoOf get(fn referendum_info):
map hasher(blake2_256) ReferendumIndex
map hasher(twox_64_concat) ReferendumIndex
=> Option<ReferendumInfo<T::BlockNumber, T::Hash>>;
/// Queue of successful referenda to be dispatched. Stored ordered by block number.
pub DispatchQueue get(fn dispatch_queue): Vec<(T::BlockNumber, T::Hash, ReferendumIndex)>;
/// Get the voters for the current proposal.
pub VotersFor get(fn voters_for):
map hasher(blake2_256) ReferendumIndex => Vec<T::AccountId>;
map hasher(twox_64_concat) ReferendumIndex => Vec<T::AccountId>;
/// Get the vote in a given referendum of a particular voter. The result is meaningful only
/// if `voters_for` includes the voter when called with the referendum (you'll get the
/// default `Vote` value otherwise). If you don't want to check `voters_for`, then you can
/// also check for simple existence with `VoteOf::contains_key` first.
pub VoteOf get(fn vote_of): map hasher(blake2_256) (ReferendumIndex, T::AccountId) => Vote;
pub VoteOf get(fn vote_of): map hasher(twox_64_concat) (ReferendumIndex, T::AccountId) => Vote;
/// Who is able to vote for whom. Value is the fund-holding account, key is the
/// vote-transaction-sending account.
pub Proxy get(fn proxy): map hasher(blake2_256) T::AccountId => Option<ProxyState<T::AccountId>>;
pub Proxy get(fn proxy): map hasher(twox_64_concat) T::AccountId => Option<ProxyState<T::AccountId>>;
/// Get the account (and lock periods) to which another account is delegating vote.
pub Delegations get(fn delegations):
linked_map hasher(blake2_256) T::AccountId => (T::AccountId, Conviction);
map hasher(twox_64_concat) T::AccountId => (T::AccountId, Conviction);
/// Accounts for which there are locks in action which may be removed at some point in the
/// future. The value is the block number at which the lock expires and may be removed.
pub Locks get(locks): map hasher(blake2_256) T::AccountId => Option<T::BlockNumber>;
pub Locks get(locks): map hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;
/// True if the last referendum tabled was submitted externally. False if it was a public
/// proposal.
@@ -473,10 +474,10 @@ decl_storage! {
/// A record of who vetoed what. Maps proposal hash to a possible existent block number
/// (until when it may not be resubmitted) and who vetoed it.
pub Blacklist get(fn blacklist):
map hasher(blake2_256) T::Hash => Option<(T::BlockNumber, Vec<T::AccountId>)>;
map hasher(identity) T::Hash => Option<(T::BlockNumber, Vec<T::AccountId>)>;
/// Record of all proposals that have been subject to emergency cancellation.
pub Cancellations: map hasher(blake2_256) T::Hash => bool;
pub Cancellations: map hasher(identity) T::Hash => bool;
}
}
@@ -583,9 +584,41 @@ decl_error! {
}
}
impl<T: Trait> MigrateAccount<T::AccountId> for Module<T> {
fn migrate_account(a: &T::AccountId) {
Proxy::<T>::migrate_key_from_blake(a);
Locks::<T>::migrate_key_from_blake(a);
Delegations::<T>::migrate_key_from_blake(a);
for i in LowestUnbaked::get()..ReferendumCount::get() {
VoteOf::<T>::migrate_key_from_blake((i, a));
}
}
}
mod migration {
use super::*;
pub fn migrate<T: Trait>() {
Blacklist::<T>::remove_all();
Cancellations::<T>::remove_all();
for i in LowestUnbaked::get()..ReferendumCount::get() {
VotersFor::<T>::migrate_key_from_blake(i);
ReferendumInfoOf::<T>::migrate_key_from_blake(i);
}
for (p, h, _) in PublicProps::<T>::get().into_iter() {
DepositOf::<T>::migrate_key_from_blake(p);
Preimages::<T>::migrate_key_from_blake(h);
}
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error<T>;
fn on_runtime_upgrade() {
migration::migrate::<T>();
}
/// The minimum period of locking and the period between a proposal being approved and enacted.
///
/// It should generally be a little more than the unstake period to ensure that
@@ -1290,7 +1323,7 @@ impl<T: Trait> Module<T> {
recursion_limit: u32,
) -> (BalanceOf<T>, BalanceOf<T>) {
if recursion_limit == 0 { return (Zero::zero(), Zero::zero()); }
<Delegations<T>>::enumerate()
<Delegations<T>>::iter()
.filter(|(delegator, (delegate, _))|
*delegate == to && !<VoteOf<T>>::contains_key(&(ref_index, delegator.clone()))
).fold(
@@ -1606,7 +1639,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
+16 -8
View File
@@ -84,18 +84,18 @@
use sp_std::prelude::*;
use sp_runtime::{
print, DispatchResult, DispatchError, Perbill,
traits::{Zero, StaticLookup, Convert},
print, DispatchResult, DispatchError, Perbill, traits::{Zero, StaticLookup, Convert},
};
use frame_support::{
decl_storage, decl_event, ensure, decl_module, decl_error, weights::SimpleDispatchInfo,
traits::{
storage::{StorageMap, IterableStorageMap}, traits::{
Currency, Get, LockableCurrency, LockIdentifier, ReservableCurrency, WithdrawReasons,
ChangeMembers, OnUnbalanced, WithdrawReason, Contains, BalanceStatus
}
};
use sp_phragmen::ExtendedBalance;
use frame_system::{self as system, ensure_signed, ensure_root};
use frame_support::traits::MigrateAccount;
const MODULE_ID: LockIdentifier = *b"phrelect";
@@ -160,9 +160,9 @@ decl_storage! {
pub ElectionRounds get(fn election_rounds): u32 = Zero::zero();
/// Votes of a particular voter, with the round index of the votes.
pub VotesOf get(fn votes_of): linked_map hasher(blake2_256) T::AccountId => Vec<T::AccountId>;
pub VotesOf get(fn votes_of): map hasher(twox_64_concat) T::AccountId => Vec<T::AccountId>;
/// Locked stake of a voter.
pub StakeOf get(fn stake_of): map hasher(blake2_256) T::AccountId => BalanceOf<T>;
pub StakeOf get(fn stake_of): map hasher(twox_64_concat) T::AccountId => BalanceOf<T>;
/// The present candidate list. Sorted based on account-id. A current member or a runner can
/// never enter this vector and is always implicitly assumed to be a candidate.
@@ -474,6 +474,14 @@ decl_event!(
}
);
impl<T: Trait> MigrateAccount<T::AccountId> for Module<T> {
fn migrate_account(a: &T::AccountId) {
if StakeOf::<T>::migrate_key_from_blake(a).is_some() {
VotesOf::<T>::migrate_key_from_blake(a);
}
}
}
impl<T: Trait> Module<T> {
/// Attempts to remove a member `who`. If a runner up exists, it is used as the replacement.
/// Otherwise, `Ok(false)` is returned to signal the caller.
@@ -637,7 +645,7 @@ impl<T: Trait> Module<T> {
// previous runners_up are also always candidates for the next round.
candidates.append(&mut Self::runners_up_ids());
let voters_and_votes = <VotesOf<T>>::enumerate()
let voters_and_votes = VotesOf::<T>::iter()
.map(|(v, i)| (v, i))
.collect::<Vec<(T::AccountId, Vec<T::AccountId>)>>();
let maybe_phragmen_result = sp_phragmen::elect::<_, _, _, T::CurrencyToVote, Perbill>(
@@ -817,7 +825,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
@@ -1001,7 +1009,7 @@ mod tests {
}
fn all_voters() -> Vec<u64> {
<VotesOf<Test>>::enumerate().map(|(v, _)| v).collect::<Vec<u64>>()
<VotesOf<Test>>::iter().map(|(v, _)| v).collect::<Vec<u64>>()
}
fn balances(who: &u64) -> (u64, u64) {
+5 -5
View File
@@ -236,16 +236,16 @@ decl_storage! {
// [`all_approvals_of`]. Furthermore, each vector of scalars is chunked with the cap of
// `APPROVAL_SET_SIZE`.
pub ApprovalsOf get(fn approvals_of):
map hasher(blake2_256) (T::AccountId, SetIndex) => Vec<ApprovalFlag>;
map hasher(twox_64_concat) (T::AccountId, SetIndex) => Vec<ApprovalFlag>;
/// The vote index and list slot that the candidate `who` was registered or `None` if they
/// are not currently registered.
pub RegisterInfoOf get(fn candidate_reg_info):
map hasher(blake2_256) T::AccountId => Option<(VoteIndex, u32)>;
map hasher(twox_64_concat) T::AccountId => Option<(VoteIndex, u32)>;
/// Basic information about a voter.
pub VoterInfoOf get(fn voter_info):
map hasher(blake2_256) T::AccountId => Option<VoterInfo<BalanceOf<T>>>;
map hasher(twox_64_concat) T::AccountId => Option<VoterInfo<BalanceOf<T>>>;
/// The present voter list (chunked and capped at [`VOTER_SET_SIZE`]).
pub Voters get(fn voters): map hasher(blake2_256) SetIndex => Vec<Option<T::AccountId>>;
pub Voters get(fn voters): map hasher(twox_64_concat) SetIndex => Vec<Option<T::AccountId>>;
/// the next free set to store a voter in. This will keep growing.
pub NextVoterSet get(fn next_nonfull_voter_set): SetIndex = 0;
/// Current number of Voters.
@@ -266,7 +266,7 @@ decl_storage! {
/// Who is able to vote for whom. Value is the fund-holding account, key is the
/// vote-transaction-sending account.
pub Proxy get(fn proxy): map hasher(blake2_256) T::AccountId => Option<T::AccountId>;
pub Proxy get(fn proxy): map hasher(blake2_128_concat) T::AccountId => Option<T::AccountId>;
}
}
+1 -1
View File
@@ -55,7 +55,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+3 -3
View File
@@ -132,9 +132,9 @@ pub trait Trait: frame_system::Trait + pallet_timestamp::Trait {
decl_storage! {
trait Store for Module<T: Trait> as EVM {
Accounts get(fn accounts) config(): map hasher(blake2_256) H160 => Account;
AccountCodes: map hasher(blake2_256) H160 => Vec<u8>;
AccountStorages: double_map hasher(blake2_256) H160, hasher(blake2_256) H256 => H256;
Accounts get(fn accounts) config(): map hasher(blake2_128_concat) H160 => Account;
AccountCodes: map hasher(blake2_128_concat) H160 => Vec<u8>;
AccountStorages: double_map hasher(blake2_128_concat) H160, hasher(blake2_128_concat) H256 => H256;
}
}
@@ -66,7 +66,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+3 -3
View File
@@ -345,7 +345,7 @@ decl_storage! {
// - `Foo::put(1); Foo::get()` returns `1`;
// - `Foo::kill(); Foo::get()` returns `0` (u32::default()).
// e.g. Foo: u32;
// e.g. pub Bar get(fn bar): map hasher(blake2_256) T::AccountId => Vec<(T::Balance, u64)>;
// e.g. pub Bar get(fn bar): map hasher(blake2_128_concat) T::AccountId => Vec<(T::Balance, u64)>;
//
// For basic value items, you'll get a type which implements
// `frame_support::StorageValue`. For map items, you'll get a type which
@@ -357,7 +357,7 @@ decl_storage! {
Dummy get(fn dummy) config(): Option<T::Balance>;
// A map that has enumerable entries.
Bar get(fn bar) config(): linked_map hasher(blake2_256) T::AccountId => T::Balance;
Bar get(fn bar) config(): map hasher(blake2_128_concat) T::AccountId => T::Balance;
// this one uses the default, we'll demonstrate the usage of 'mutate' API.
Foo get(fn foo) config(): T::Balance;
@@ -731,7 +731,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
+7 -4
View File
@@ -191,6 +191,7 @@ where
digest,
frame_system::InitKind::Full,
);
<frame_system::Module<System> as OnInitialize<System::BlockNumber>>::on_initialize(*block_number);
<AllModules as OnInitialize<System::BlockNumber>>::on_initialize(*block_number);
<frame_system::Module<System>>::register_extra_weight_unchecked(
<AllModules as WeighBlock<System::BlockNumber>>::on_initialize(*block_number)
@@ -249,11 +250,11 @@ where
/// Execute given extrinsics and take care of post-extrinsics book-keeping.
fn execute_extrinsics_with_book_keeping(extrinsics: Vec<Block::Extrinsic>, block_number: NumberFor<Block>) {
extrinsics.into_iter().for_each(Self::apply_extrinsic_no_note);
// post-extrinsics book-keeping
<frame_system::Module<System>>::note_finished_extrinsics();
<frame_system::Module<System> as OnFinalize<System::BlockNumber>>::on_finalize(block_number);
<AllModules as OnFinalize<System::BlockNumber>>::on_finalize(block_number);
}
@@ -261,7 +262,9 @@ where
/// except state-root.
pub fn finalize_block() -> System::Header {
<frame_system::Module<System>>::note_finished_extrinsics();
<AllModules as OnFinalize<System::BlockNumber>>::on_finalize(<frame_system::Module<System>>::block_number());
let block_number = <frame_system::Module<System>>::block_number();
<frame_system::Module<System> as OnFinalize<System::BlockNumber>>::on_finalize(block_number);
<AllModules as OnFinalize<System::BlockNumber>>::on_finalize(block_number);
// set up extrinsics
<frame_system::Module<System>>::derive_extrinsics();
@@ -478,7 +481,7 @@ mod tests {
type Version = RuntimeVersion;
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
@@ -595,7 +598,7 @@ mod tests {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("e97d724f480f6e3215bd5c24b9ba51250e2514ac1c99e563fd77bfb9d6100b1c").into(),
state_root: hex!("489ae9b57a19bb4733a264dc64bbcae9b140a904657a681ed3bb5fbbe8cf412b").into(),
extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(),
digest: Digest { logs: vec![], },
},
+1 -7
View File
@@ -26,8 +26,6 @@ use frame_support::traits::Get;
use frame_system::{ensure_none, Trait as SystemTrait};
use sp_finality_tracker::{INHERENT_IDENTIFIER, FinalizedInherentData};
mod migration;
pub const DEFAULT_WINDOW_SIZE: u32 = 101;
pub const DEFAULT_REPORT_LATENCY: u32 = 1000;
@@ -91,10 +89,6 @@ decl_module! {
fn on_finalize() {
Self::update_hint(<Self as Store>::Update::take())
}
fn on_runtime_upgrade() {
migration::on_runtime_upgrade::<T>()
}
}
}
@@ -268,7 +262,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
@@ -1,54 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
// Migration code to update storage.
use super::*;
use frame_support::storage::migration::{put_storage_value, take_storage_value};
pub fn on_runtime_upgrade<T: Trait>() {
change_name_timestamp_to_finality_tracker::<T>()
}
// Change the storage name used by this pallet from `Timestamp` to `FinalityTracker`.
//
// Since the format of the storage items themselves have not changed, we do not
// need to keep track of a storage version. If the runtime does not need to be
// upgraded, nothing here will happen anyway.
fn change_name_timestamp_to_finality_tracker<T:Trait>() {
sp_runtime::print("Migrating Finality Tracker.");
if let Some(recent_hints) = take_storage_value::<Vec<T::BlockNumber>>(b"Timestamp", b"RecentHints", &[]) {
put_storage_value(b"FinalityTracker", b"RecentHints", &[], recent_hints);
}
if let Some(ordered_hints) = take_storage_value::<Vec<T::BlockNumber>>(b"Timestamp", b"OrderedHints", &[]) {
put_storage_value(b"FinalityTracker", b"OrderedHints", &[], ordered_hints);
}
if let Some(median) = take_storage_value::<T::BlockNumber>(b"Timestamp", b"Median", &[]) {
put_storage_value(b"FinalityTracker", b"Median", &[], median);
}
if let Some(update) = take_storage_value::<T::BlockNumber>(b"Timestamp", b"Update", &[]) {
put_storage_value(b"FinalityTracker", b"Update", &[], update);
}
if let Some(initialized) = take_storage_value::<bool>(b"Timestamp", b"Initialized", &[]) {
put_storage_value(b"FinalityTracker", b"Initialized", &[], initialized);
}
}
+6 -6
View File
@@ -439,26 +439,26 @@ decl_storage! {
pub TotalIssuance get(fn total_issuance) build(|config: &GenesisConfig<T>| {
let issuance = config.initial_balance * (config.endowed_accounts.len() as u32).into();
config.assets.iter().map(|id| (id.clone(), issuance)).collect::<Vec<_>>()
}): map hasher(blake2_256) T::AssetId => T::Balance;
}): map hasher(twox_64_concat) T::AssetId => T::Balance;
/// The free balance of a given asset under an account.
pub FreeBalance:
double_map hasher(blake2_256) T::AssetId, hasher(twox_128) T::AccountId => T::Balance;
double_map hasher(twox_64_concat) T::AssetId, hasher(blake2_128_concat) T::AccountId => T::Balance;
/// The reserved balance of a given asset under an account.
pub ReservedBalance:
double_map hasher(blake2_256) T::AssetId, hasher(twox_128) T::AccountId => T::Balance;
double_map hasher(twox_64_concat) T::AssetId, hasher(blake2_128_concat) T::AccountId => T::Balance;
/// Next available ID for user-created asset.
pub NextAssetId get(fn next_asset_id) config(): T::AssetId;
/// Permission options for a given asset.
pub Permissions get(fn get_permission):
map hasher(blake2_256) T::AssetId => PermissionVersions<T::AccountId>;
map hasher(twox_64_concat) T::AssetId => PermissionVersions<T::AccountId>;
/// Any liquidity locks on some account balances.
pub Locks get(fn locks):
map hasher(blake2_256) T::AccountId => Vec<BalanceLock<T::Balance>>;
map hasher(blake2_128_concat) T::AccountId => Vec<BalanceLock<T::Balance>>;
/// The identity of the asset which is the one that is designated for the chain's staking system.
pub StakingAssetId get(fn staking_asset_id) config(): T::AssetId;
@@ -1123,7 +1123,7 @@ impl<T: Subtrait> frame_system::Trait for ElevatedTrait<T> {
type Version = T::Version;
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
impl<T: Subtrait> Trait for ElevatedTrait<T> {
+1 -1
View File
@@ -63,7 +63,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+16 -2
View File
@@ -174,8 +174,9 @@ decl_storage! {
/// in the "set" of Grandpa validators from genesis.
CurrentSetId get(fn current_set_id) build(|_| fg_primitives::SetId::default()): SetId;
/// A mapping from grandpa set ID to the index of the *most recent* session for which its members were responsible.
SetIdSession get(fn session_for_set): map hasher(blake2_256) SetId => Option<SessionIndex>;
/// A mapping from grandpa set ID to the index of the *most recent* session for which its
/// members were responsible.
SetIdSession get(fn session_for_set): map hasher(twox_64_concat) SetId => Option<SessionIndex>;
}
add_extra_genesis {
config(authorities): AuthorityList;
@@ -183,6 +184,15 @@ decl_storage! {
}
}
mod migration {
use super::*;
pub fn migrate<T: Trait>() {
for i in 0..=CurrentSetId::get() {
SetIdSession::migrate_key_from_blake(i);
}
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error<T>;
@@ -195,6 +205,10 @@ decl_module! {
// FIXME: https://github.com/paritytech/substrate/issues/1112
}
fn on_runtime_upgrade() {
migration::migrate::<T>();
}
fn on_initialize() {
#[cfg(feature = "migrate-authorities")]
Self::migrate_authorities();
+1 -1
View File
@@ -66,7 +66,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+17 -9
View File
@@ -77,10 +77,10 @@ use frame_support::{
weights::SimpleDispatchInfo,
};
use frame_system::{self as system, ensure_signed, ensure_root};
use frame_support::traits::MigrateAccount;
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;
mod migration;
type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
type NegativeImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::NegativeImbalance;
@@ -386,18 +386,18 @@ decl_storage! {
trait Store for Module<T: Trait> as Identity {
/// Information that is pertinent to identify the entity behind an account.
pub IdentityOf get(fn identity):
map hasher(blake2_256) T::AccountId => Option<Registration<BalanceOf<T>>>;
map hasher(twox_64_concat) T::AccountId => Option<Registration<BalanceOf<T>>>;
/// The super-identity of an alternative "sub" identity together with its name, within that
/// context. If the account is not some other account's sub-identity, then just `None`.
pub SuperOf get(fn super_of):
map hasher(blake2_256) T::AccountId => Option<(T::AccountId, Data)>;
map hasher(blake2_128_concat) T::AccountId => Option<(T::AccountId, Data)>;
/// Alternative "sub" identities of this account.
///
/// The first item is the deposit, the second is a vector of the accounts.
pub SubsOf get(fn subs_of):
map hasher(blake2_256) T::AccountId => (BalanceOf<T>, Vec<T::AccountId>);
map hasher(twox_64_concat) T::AccountId => (BalanceOf<T>, Vec<T::AccountId>);
/// The set of registrars. Not expected to get very big as can only be added through a
/// special origin (likely a council motion).
@@ -874,10 +874,6 @@ decl_module! {
Self::deposit_event(RawEvent::IdentityKilled(target, deposit));
}
fn on_runtime_upgrade() {
migration::on_runtime_upgrade::<T>()
}
}
}
@@ -891,6 +887,18 @@ impl<T: Trait> Module<T> {
}
}
impl<T: Trait> MigrateAccount<T::AccountId> for Module<T> {
fn migrate_account(a: &T::AccountId) {
if IdentityOf::<T>::migrate_key_from_blake(a).is_some() {
if let Some((_, subs)) = SubsOf::<T>::migrate_key_from_blake(a) {
for sub in subs.into_iter() {
SuperOf::<T>::migrate_key_from_blake(sub);
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -941,7 +949,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
-52
View File
@@ -1,52 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Migration code to update storage.
use super::*;
use frame_support::storage::migration::{put_storage_value, take_storage_value, StorageIterator};
pub fn on_runtime_upgrade<T: Trait>() {
change_name_sudo_to_identity::<T>()
}
// Change the storage name used by this pallet from `Sudo` to `Identity`.
//
// Since the format of the storage items themselves have not changed, we do not
// need to keep track of a storage version. If the runtime does not need to be
// upgraded, nothing here will happen anyway.
fn change_name_sudo_to_identity<T: Trait>() {
sp_runtime::print("Migrating Identity.");
for (hash, identity_of) in StorageIterator::<Registration<BalanceOf<T>>>::new(b"Sudo", b"IdentityOf").drain() {
put_storage_value(b"Identity", b"IdentityOf", &hash, identity_of);
}
for (hash, super_of) in StorageIterator::<(T::AccountId, Data)>::new(b"Sudo", b"SuperOf").drain() {
put_storage_value(b"Identity", b"SuperOf", &hash, super_of);
}
for (hash, subs_of) in StorageIterator::<(BalanceOf<T>, Vec<T::AccountId>)>::new(b"Sudo", b"SubsOf").drain() {
put_storage_value(b"Identity", b"SubsOf", &hash, subs_of);
}
if let Some(registrars) = take_storage_value::<Vec<Option<RegistrarInfo<BalanceOf<T>, T::AccountId>>>>(b"Sudo", b"Registrars", &[]) {
put_storage_value(b"Identity", b"Registrars", &[], registrars);
}
sp_runtime::print("Done Identity.");
}
+32 -4
View File
@@ -95,6 +95,7 @@ use frame_support::{
};
use frame_system::{self as system, ensure_none};
use frame_system::offchain::SubmitUnsignedTransaction;
use frame_support::traits::MigrateAccount;
pub mod sr25519 {
mod app_sr25519 {
@@ -274,16 +275,17 @@ decl_storage! {
/// The current set of keys that may issue a heartbeat.
Keys get(fn keys): Vec<T::AuthorityId>;
/// For each session index, we keep a mapping of `AuthIndex`
/// to `offchain::OpaqueNetworkState`.
/// For each session index, we keep a mapping of `AuthIndex` to
/// `offchain::OpaqueNetworkState`.
ReceivedHeartbeats get(fn received_heartbeats):
double_map hasher(blake2_256) SessionIndex, hasher(blake2_256) AuthIndex
double_map hasher(twox_64_concat) SessionIndex, hasher(twox_64_concat) AuthIndex
=> Option<Vec<u8>>;
/// For each session index, we keep a mapping of `T::ValidatorId` to the
/// number of blocks authored by the given authority.
AuthoredBlocks get(fn authored_blocks):
double_map hasher(blake2_256) SessionIndex, hasher(blake2_256) T::ValidatorId => u32;
double_map hasher(twox_64_concat) SessionIndex, hasher(twox_64_concat) T::ValidatorId
=> u32;
}
add_extra_genesis {
config(keys): Vec<T::AuthorityId>;
@@ -301,12 +303,38 @@ decl_error! {
}
}
mod migration {
use super::*;
use frame_support::Blake2_256;
pub fn migrate<T: Trait>() {
let current_index = <pallet_session::Module<T>>::current_index();
let key_count = Keys::<T>::get().len() as AuthIndex;
for i in 0..key_count {
ReceivedHeartbeats::migrate_keys::<Blake2_256, Blake2_256, _, _>(current_index, i);
}
}
}
impl<T: Trait> MigrateAccount<T::AccountId> for Module<T> {
fn migrate_account(a: &T::AccountId) {
use frame_support::Blake2_256;
let current_index = <pallet_session::Module<T>>::current_index();
if let Ok(v) = a.using_encoded(|mut d| T::ValidatorId::decode(&mut d)) {
AuthoredBlocks::<T>::migrate_keys::<Blake2_256, Blake2_256, _, _>(current_index, v);
}
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error<T>;
fn deposit_event() = default;
fn on_runtime_upgrade() {
migration::migrate::<T>();
}
fn heartbeat(
origin,
heartbeat: Heartbeat<T::BlockNumber>,
+1 -1
View File
@@ -119,7 +119,7 @@ impl frame_system::Trait for Runtime {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+1 -1
View File
@@ -66,7 +66,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+1 -1
View File
@@ -321,7 +321,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
ord_parameter_types! {
+3 -1
View File
@@ -277,6 +277,7 @@ pub enum StorageHasher {
Twox128,
Twox256,
Twox64Concat,
Identity,
}
/// A storage entry type.
@@ -288,7 +289,8 @@ pub enum StorageEntryType {
hasher: StorageHasher,
key: DecodeDifferentStr,
value: DecodeDifferentStr,
is_linked: bool,
// is_linked flag previously, unused now to keep backwards compat
unused: bool,
},
DoubleMap {
hasher: StorageHasher,
+2 -2
View File
@@ -78,7 +78,7 @@ pub trait Trait: frame_system::Trait {
decl_storage! {
trait Store for Module<T: Trait> as Nicks {
/// The lookup table for names.
NameOf: map hasher(blake2_256) T::AccountId => Option<(Vec<u8>, BalanceOf<T>)>;
NameOf: map hasher(twox_64_concat) T::AccountId => Option<(Vec<u8>, BalanceOf<T>)>;
}
}
@@ -286,7 +286,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
+12 -3
View File
@@ -54,11 +54,13 @@ pub trait Trait: frame_system::Trait {
decl_storage! {
trait Store for Module<T: Trait> as Offences {
/// The primary structure that holds all offence records keyed by report identifiers.
Reports get(fn reports): map hasher(blake2_256) ReportIdOf<T> => Option<OffenceDetails<T::AccountId, T::IdentificationTuple>>;
Reports get(fn reports):
map hasher(twox_64_concat) ReportIdOf<T>
=> Option<OffenceDetails<T::AccountId, T::IdentificationTuple>>;
/// A vector of reports of the same kind that happened at the same time slot.
ConcurrentReportsIndex:
double_map hasher(blake2_256) Kind, hasher(blake2_256) OpaqueTimeSlot
double_map hasher(twox_64_concat) Kind, hasher(twox_64_concat) OpaqueTimeSlot
=> Vec<ReportIdOf<T>>;
/// Enumerates all reports of a kind along with the time they happened.
@@ -67,7 +69,7 @@ decl_storage! {
///
/// Note that the actual type of this mapping is `Vec<u8>`, this is because values of
/// different types are not supported at the moment so we are doing the manual serialization.
ReportsByKindIndex: map hasher(blake2_256) Kind => Vec<u8>; // (O::TimeSlot, ReportIdOf<T>)
ReportsByKindIndex: map hasher(twox_64_concat) Kind => Vec<u8>; // (O::TimeSlot, ReportIdOf<T>)
}
}
@@ -83,8 +85,15 @@ decl_module! {
/// Offences module, currently just responsible for taking offence reports.
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn deposit_event() = default;
fn on_runtime_upgrade() {
Reports::<T>::remove_all();
ConcurrentReportsIndex::<T>::remove_all();
ReportsByKindIndex::remove_all();
}
}
}
impl<T: Trait, O: Offence<T::IdentificationTuple>>
ReportOffence<T::AccountId, T::IdentificationTuple, O> for Module<T>
where
+1 -1
View File
@@ -90,7 +90,7 @@ impl frame_system::Trait for Runtime {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
@@ -192,7 +192,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+10 -2
View File
@@ -163,6 +163,7 @@ use frame_support::{
traits::{Currency, ReservableCurrency, Get, BalanceStatus},
};
use frame_system::{self as system, ensure_signed, ensure_root};
use frame_support::traits::MigrateAccount;
#[cfg(test)]
mod mock;
@@ -238,7 +239,7 @@ decl_storage! {
trait Store for Module<T: Trait> as Recovery {
/// The set of recoverable accounts and their recovery configuration.
pub Recoverable get(fn recovery_config):
map hasher(blake2_256) T::AccountId
map hasher(twox_64_concat) T::AccountId
=> Option<RecoveryConfig<T::BlockNumber, BalanceOf<T>, T::AccountId>>;
/// Active recovery attempts.
@@ -253,7 +254,14 @@ decl_storage! {
///
/// Map from the user who can access it to the recovered account.
pub Proxy get(fn proxy):
map hasher(blake2_256) T::AccountId => Option<T::AccountId>;
map hasher(blake2_128_concat) T::AccountId => Option<T::AccountId>;
}
}
impl<T: Trait> MigrateAccount<T::AccountId> for Module<T> {
fn migrate_account(a: &T::AccountId) {
Recoverable::<T>::migrate_key_from_blake(a);
Proxy::<T>::migrate_key_from_blake(a);
}
}
+1 -1
View File
@@ -79,7 +79,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u128>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+1 -1
View File
@@ -165,7 +165,7 @@ decl_storage! {
/// check if a candidate is already in the pool, without having to
/// iterate over the entire pool (the `Pool` is not sorted by
/// `T::AccountId`, but by `T::Score` instead).
CandidateExists get(fn candidate_exists): map hasher(blake2_256) T::AccountId => bool;
CandidateExists get(fn candidate_exists): map hasher(twox_64_concat) T::AccountId => bool;
/// The current membership, stored as an ordered Vec.
Members get(fn members): Vec<T::AccountId>;
+1 -1
View File
@@ -71,7 +71,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+16 -2
View File
@@ -56,12 +56,12 @@ decl_storage! {
trait Store for Module<T: Trait> as Session {
/// Mapping from historical session indices to session-data root hash and validator count.
HistoricalSessions get(fn historical_root):
map hasher(blake2_256) SessionIndex => Option<(T::Hash, ValidatorCount)>;
map hasher(twox_64_concat) SessionIndex => Option<(T::Hash, ValidatorCount)>;
/// The range of historical sessions we store. [first, last)
StoredRange: Option<(SessionIndex, SessionIndex)>;
/// Deprecated.
CachedObsolete:
map hasher(blake2_256) SessionIndex
map hasher(twox_64_concat) SessionIndex
=> Option<Vec<(T::ValidatorId, T::FullIdentification)>>;
}
}
@@ -71,6 +71,20 @@ decl_module! {
fn on_initialize(_n: T::BlockNumber) {
CachedObsolete::<T>::remove_all();
}
fn on_runtime_upgrade() {
migration::migrate::<T>();
}
}
}
mod migration {
use super::*;
pub fn migrate<T: Trait>() {
if let Some((begin, end)) = StoredRange::get() {
for i in begin..end {
HistoricalSessions::<T>::migrate_key_from_blake(i);
}
}
}
}
+13 -26
View File
@@ -109,6 +109,7 @@ use frame_support::{ensure, decl_module, decl_event, decl_storage, decl_error, C
use frame_support::{traits::{Get, FindAuthor, ValidatorRegistration}, Parameter};
use frame_support::dispatch::{self, DispatchResult, DispatchError};
use frame_system::{self as system, ensure_signed};
use frame_support::traits::MigrateAccount;
#[cfg(test)]
mod mock;
@@ -364,10 +365,10 @@ decl_storage! {
DisabledValidators get(fn disabled_validators): Vec<u32>;
/// The next session keys for a validator.
NextKeys: map hasher(blake2_256) T::ValidatorId => Option<T::Keys>;
NextKeys: map hasher(twox_64_concat) T::ValidatorId => Option<T::Keys>;
/// The owner of a key. The key is the `KeyTypeId` + the encoded key.
KeyOwner: map hasher(blake2_256) (KeyTypeId, Vec<u8>) => Option<T::ValidatorId>;
KeyOwner: map hasher(twox_64_concat) (KeyTypeId, Vec<u8>) => Option<T::ValidatorId>;
}
add_extra_genesis {
config(keys): Vec<(T::AccountId, T::ValidatorId, T::Keys)>;
@@ -498,36 +499,22 @@ decl_module! {
Self::rotate_session();
}
}
}
}
/// Called when the runtime is upgraded.
fn on_runtime_upgrade() {
Self::migrate();
impl<T: Trait> MigrateAccount<T::AccountId> for Module<T> {
fn migrate_account(a: &T::AccountId) {
if let Some(v) = T::ValidatorIdOf::convert(a.clone()) {
if let Some(keys) = NextKeys::<T>::migrate_key_from_blake(v) {
for id in T::Keys::key_ids() {
KeyOwner::<T>::migrate_key_from_blake((*id, keys.get_raw(*id)));
}
}
}
}
}
impl<T: Trait> Module<T> {
/// Move keys from NextKeys and KeyOwner, if any exist.
fn migrate() {
use frame_support::storage::migration::{put_storage_value, StorageIterator};
sp_runtime::print("Migrating session's double-maps...");
let prefix = {
const DEDUP_KEY_PREFIX: &[u8] = b":session:keys";
let encoded_prefix_key_hash = codec::Encode::encode(&DEDUP_KEY_PREFIX);
let mut h = sp_io::hashing::twox_64(&encoded_prefix_key_hash[..]).to_vec();
h.extend(&encoded_prefix_key_hash[..]);
h
};
for (hash, value) in StorageIterator::<T::Keys>::with_suffix(b"Session", b"NextKeys", &prefix[..]).drain() {
put_storage_value(b"Session", b"NextKeys", &hash, value);
}
for (hash, value) in StorageIterator::<T::ValidatorId>::with_suffix(b"Session", b"KeyOwner", &prefix[..]).drain() {
put_storage_value(b"Session", b"KeyOwner", &hash, value);
}
}
/// Move on to next session. Register new validator set and session keys. Changes
/// to the validator set have a session of delay to take effect. This allows for
/// equivocation punishment after a fork.
+1 -1
View File
@@ -179,7 +179,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+12 -9
View File
@@ -261,10 +261,7 @@ use sp_runtime::{Percent, ModuleId, RuntimeDebug,
};
use frame_support::{decl_error, decl_module, decl_storage, decl_event, ensure, dispatch::DispatchResult};
use frame_support::weights::SimpleDispatchInfo;
use frame_support::traits::{
Currency, ReservableCurrency, Randomness, Get, ChangeMembers, BalanceStatus,
ExistenceRequirement::AllowDeath,
};
use frame_support::traits::{Currency, ReservableCurrency, Randomness, Get, ChangeMembers, BalanceStatus, ExistenceRequirement::AllowDeath, MigrateAccount};
use frame_system::{self as system, ensure_signed, ensure_root};
type BalanceOf<T, I> = <<T as Trait<I>>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
@@ -414,7 +411,7 @@ decl_storage! {
/// The set of suspended candidates.
pub SuspendedCandidates get(suspended_candidate):
map hasher(blake2_256) T::AccountId
map hasher(twox_64_concat) T::AccountId
=> Option<(BalanceOf<T, I>, BidKind<T::AccountId, BalanceOf<T, I>>)>;
/// Amount of our account balance that is specifically for the next round's bid(s).
@@ -432,19 +429,19 @@ decl_storage! {
}): Vec<T::AccountId>;
/// The set of suspended members.
pub SuspendedMembers get(fn suspended_member): map hasher(blake2_256) T::AccountId => bool;
pub SuspendedMembers get(fn suspended_member): map hasher(twox_64_concat) T::AccountId => bool;
/// The current bids, stored ordered by the value of the bid.
Bids: Vec<Bid<T::AccountId, BalanceOf<T, I>>>;
/// Members currently vouching or banned from vouching again
Vouching get(fn vouching): map hasher(blake2_256) T::AccountId => Option<VouchingStatus>;
Vouching get(fn vouching): map hasher(twox_64_concat) T::AccountId => Option<VouchingStatus>;
/// Pending payouts; ordered by block number, with the amount that should be paid out.
Payouts: map hasher(blake2_256) T::AccountId => Vec<(T::BlockNumber, BalanceOf<T, I>)>;
Payouts: map hasher(twox_64_concat) T::AccountId => Vec<(T::BlockNumber, BalanceOf<T, I>)>;
/// The ongoing number of losing votes cast by the member.
Strikes: map hasher(blake2_256) T::AccountId => StrikeCount;
Strikes: map hasher(twox_64_concat) T::AccountId => StrikeCount;
/// Double map from Candidate -> Voter -> (Maybe) Vote.
Votes: double_map
@@ -1133,6 +1130,12 @@ decl_event! {
}
}
impl<T: Trait> MigrateAccount<T::AccountId> for Module<T> {
fn migrate_account(a: &T::AccountId) {
Payouts::<T>::migrate_key_from_blake(a);
}
}
/// Simple ensure origin struct to filter for the founder account.
pub struct EnsureFounder<T>(sp_std::marker::PhantomData<T>);
impl<T: Trait> EnsureOrigin<T::Origin> for EnsureFounder<T> {
+1 -1
View File
@@ -77,7 +77,7 @@ impl frame_system::Trait for Test {
type AvailableBlockRatio = AvailableBlockRatio;
type Version = ();
type ModuleToIndex = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
type AccountData = pallet_balances::AccountData<u64>;
}
+49 -27
View File
@@ -254,19 +254,16 @@ mod mock;
#[cfg(test)]
mod tests;
mod slashing;
mod migration;
pub mod inflation;
use sp_std::{prelude::*, result, collections::btree_map::BTreeMap};
use codec::{HasCompact, Encode, Decode};
use frame_support::{
decl_module, decl_event, decl_storage, ensure, decl_error,
weights::SimpleDispatchInfo,
dispatch::DispatchResult,
traits::{
Currency, LockIdentifier, LockableCurrency,
WithdrawReasons, OnUnbalanced, Imbalance, Get, Time
decl_module, decl_event, decl_storage, ensure, decl_error, weights::SimpleDispatchInfo,
dispatch::DispatchResult, storage::IterableStorageMap, traits::{
Currency, LockIdentifier, LockableCurrency, WithdrawReasons, OnUnbalanced, Imbalance, Get,
Time
}
};
use pallet_session::historical::SessionManager;
@@ -287,6 +284,7 @@ use sp_runtime::{Serialize, Deserialize};
use frame_system::{self as system, ensure_signed, ensure_root};
use sp_phragmen::ExtendedBalance;
use frame_support::traits::MigrateAccount;
const DEFAULT_MINIMUM_VALIDATOR_COUNT: u32 = 4;
const MAX_NOMINATIONS: usize = 16;
@@ -685,13 +683,13 @@ impl Default for Forcing {
// storage migration logic. This should match directly with the semantic versions of the Rust crate.
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)]
enum Releases {
V1_0_0,
V1_0_0Ancient,
V2_0_0,
}
impl Default for Releases {
fn default() -> Self {
Releases::V1_0_0
Releases::V2_0_0
}
}
@@ -719,23 +717,23 @@ decl_storage! {
pub Invulnerables get(fn invulnerables) config(): Vec<T::AccountId>;
/// Map from all locked "stash" accounts to the controller account.
pub Bonded get(fn bonded): map hasher(blake2_256) T::AccountId => Option<T::AccountId>;
pub Bonded get(fn bonded): map hasher(twox_64_concat) T::AccountId => Option<T::AccountId>;
/// Map from all (unlocked) "controller" accounts to the info regarding the staking.
pub Ledger get(fn ledger):
map hasher(blake2_256) T::AccountId
map hasher(blake2_128_concat) T::AccountId
=> Option<StakingLedger<T::AccountId, BalanceOf<T>>>;
/// Where the reward payment should be made. Keyed by stash.
pub Payee get(fn payee): map hasher(blake2_256) T::AccountId => RewardDestination;
pub Payee get(fn payee): map hasher(twox_64_concat) T::AccountId => RewardDestination;
/// The map from (wannabe) validator stash key to the preferences of that validator.
pub Validators get(fn validators):
linked_map hasher(blake2_256) T::AccountId => ValidatorPrefs;
map hasher(twox_64_concat) T::AccountId => ValidatorPrefs;
/// The map from nominator stash key to the set of stash keys of all validators to nominate.
pub Nominators get(fn nominators):
linked_map hasher(blake2_256) T::AccountId => Option<Nominations<T::AccountId>>;
map hasher(twox_64_concat) T::AccountId => Option<Nominations<T::AccountId>>;
/// The current era index.
///
@@ -751,7 +749,7 @@ decl_storage! {
/// The session index at which the era start for the last `HISTORY_DEPTH` eras
pub ErasStartSessionIndex get(fn eras_start_session_index):
map hasher(blake2_256) EraIndex => Option<SessionIndex>;
map hasher(twox_64_concat) EraIndex => Option<SessionIndex>;
/// Exposure of validator at era.
///
@@ -780,7 +778,7 @@ decl_storage! {
/// Similarly to `ErasStakers` this holds the preferences of validators.
///
/// This is keyed fist by the era index to allow bulk deletion and then the stash account.
/// This is keyed first by the era index to allow bulk deletion and then the stash account.
///
/// Is it removed after `HISTORY_DEPTH` eras.
// If prefs hasn't been set or has been removed then 0 commission is returned.
@@ -792,17 +790,17 @@ decl_storage! {
///
/// Eras that haven't finished yet or has been removed doesn't have reward.
pub ErasValidatorReward get(fn eras_validator_reward):
map hasher(blake2_256) EraIndex => Option<BalanceOf<T>>;
map hasher(twox_64_concat) EraIndex => Option<BalanceOf<T>>;
/// Rewards for the last `HISTORY_DEPTH` eras.
/// If reward hasn't been set or has been removed then 0 reward is returned.
pub ErasRewardPoints get(fn eras_reward_points):
map hasher(blake2_256) EraIndex => EraRewardPoints<T::AccountId>;
map hasher(twox_64_concat) EraIndex => EraRewardPoints<T::AccountId>;
/// The total amount staked for the last `HISTORY_DEPTH` eras.
/// If total hasn't been set or has been removed then 0 stake is returned.
pub ErasTotalStake get(fn eras_total_stake):
map hasher(blake2_256) EraIndex => BalanceOf<T>;
map hasher(twox_64_concat) EraIndex => BalanceOf<T>;
/// True if the next session change will be a new era regardless of index.
pub ForceEra get(fn force_era) config(): Forcing;
@@ -818,7 +816,7 @@ decl_storage! {
/// All unapplied slashes that are queued for later.
pub UnappliedSlashes:
map hasher(blake2_256) EraIndex => Vec<UnappliedSlash<T::AccountId, BalanceOf<T>>>;
map hasher(twox_64_concat) EraIndex => Vec<UnappliedSlash<T::AccountId, BalanceOf<T>>>;
/// A mapping from still-bonded eras to the first session index of that era.
///
@@ -829,21 +827,21 @@ decl_storage! {
/// All slashing events on validators, mapped by era to the highest slash proportion
/// and slash value of the era.
ValidatorSlashInEra:
double_map hasher(blake2_256) EraIndex, hasher(twox_128) T::AccountId
double_map hasher(twox_64_concat) EraIndex, hasher(twox_64_concat) T::AccountId
=> Option<(Perbill, BalanceOf<T>)>;
/// All slashing events on nominators, mapped by era to the highest slash value of the era.
NominatorSlashInEra:
double_map hasher(blake2_256) EraIndex, hasher(twox_128) T::AccountId
double_map hasher(twox_64_concat) EraIndex, hasher(twox_64_concat) T::AccountId
=> Option<BalanceOf<T>>;
/// Slashing spans for stash accounts.
SlashingSpans: map hasher(blake2_256) T::AccountId => Option<slashing::SlashingSpans>;
SlashingSpans: map hasher(twox_64_concat) T::AccountId => Option<slashing::SlashingSpans>;
/// Records information about the maximum slash of a stash within a slashing span,
/// as well as how much reward has been paid out.
SpanSlash:
map hasher(blake2_256) (T::AccountId, slashing::SpanIndex)
map hasher(twox_64_concat) (T::AccountId, slashing::SpanIndex)
=> slashing::SpanRecord<BalanceOf<T>>;
/// The earliest era for which we have a pending, unapplied slash.
@@ -957,7 +955,7 @@ decl_module! {
fn deposit_event() = default;
fn on_runtime_upgrade() {
migration::on_runtime_upgrade::<T>();
migrate::<T>();
}
fn on_finalize() {
@@ -1480,6 +1478,30 @@ decl_module! {
}
}
impl<T: Trait> MigrateAccount<T::AccountId> for Module<T> {
fn migrate_account(a: &T::AccountId) {
if let Some(controller) = Bonded::<T>::migrate_key_from_blake(a) {
Ledger::<T>::migrate_key_from_blake(controller);
Payee::<T>::migrate_key_from_blake(a);
Validators::<T>::migrate_key_from_blake(a);
Nominators::<T>::migrate_key_from_blake(a);
SlashingSpans::<T>::migrate_key_from_blake(a);
}
}
}
fn migrate<T: Trait>() {
if let Some(current_era) = CurrentEra::get() {
let history_depth = HistoryDepth::get();
for era in current_era.saturating_sub(history_depth)..=current_era {
ErasStartSessionIndex::migrate_key_from_blake(era);
ErasValidatorReward::<T>::migrate_key_from_blake(era);
ErasRewardPoints::<T>::migrate_key_from_blake(era);
ErasTotalStake::<T>::migrate_key_from_blake(era);
}
}
}
impl<T: Trait> Module<T> {
// PUBLIC IMMUTABLES
@@ -1823,14 +1845,14 @@ impl<T: Trait> Module<T> {
let mut all_nominators: Vec<(T::AccountId, Vec<T::AccountId>)> = Vec::new();
let mut all_validators_and_prefs = BTreeMap::new();
let mut all_validators = Vec::new();
for (validator, preference) in <Validators<T>>::enumerate() {
for (validator, preference) in <Validators<T>>::iter() {
let self_vote = (validator.clone(), vec![validator.clone()]);
all_nominators.push(self_vote);
all_validators_and_prefs.insert(validator.clone(), preference);
all_validators.push(validator);
}
let nominator_votes = <Nominators<T>>::enumerate().map(|(nominator, nominations)| {
let nominator_votes = <Nominators<T>>::iter().map(|(nominator, nominations)| {
let Nominations { submitted_in, mut targets, suppressed: _ } = nominations;
// Filter out nomination targets which were nominated before the most recent
@@ -1,73 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
/// Deprecated storages used for migration from v1.0.0 to v2.0.0 only.
use crate::{Trait, BalanceOf, MomentOf, SessionIndex, Exposure, UnlockChunk};
use codec::{Encode, Decode, HasCompact};
use frame_support::{decl_module, decl_storage};
use sp_std::prelude::*;
/// Reward points of an era. Used to split era total payout between validators.
#[derive(Encode, Decode, Default)]
pub struct EraPoints {
/// Total number of points. Equals the sum of reward points for each validator.
pub total: u32,
/// The reward points earned by a given validator. The index of this vec corresponds to the
/// index into the current validator set.
pub individual: Vec<u32>,
}
#[derive(Encode, Decode)]
pub struct OldStakingLedger<AccountId, Balance: HasCompact> {
pub stash: AccountId,
#[codec(compact)]
pub total: Balance,
#[codec(compact)]
pub active: Balance,
pub unlocking: Vec<UnlockChunk<Balance>>,
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin { }
}
decl_storage! {
pub trait Store for Module<T: Trait> as Staking {
pub SlotStake: BalanceOf<T>;
/// The currently elected validator set keyed by stash account ID.
pub CurrentElected: Vec<T::AccountId>;
/// The start of the current era.
pub CurrentEraStart: MomentOf<T>;
/// The session index at which the current era started.
pub CurrentEraStartSessionIndex: SessionIndex;
/// Rewards for the current era. Using indices of current elected set.
pub CurrentEraPointsEarned: EraPoints;
/// Nominators for a particular account that is in action right now. You can't iterate
/// through validators here, but you can find them in the Session module.
///
/// This is keyed by the stash account.
pub Stakers: map hasher(blake2_256) T::AccountId => Exposure<T::AccountId, BalanceOf<T>>;
/// Old upgrade flag.
pub IsUpgraded: bool;
}
}
@@ -1,119 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Update storage from v1.0.0 to v2.0.0
//!
//! In old version the staking module has several issue about handling session delay, the
//! current era was always considered the active one.
//!
//! After the migration the current era will still be considered the active one for the era of
//! the upgrade. And the delay issue will be fixed when planning the next era.
// * create:
// * ActiveEraStart
// * ErasRewardPoints
// * ActiveEra
// * ErasStakers
// * ErasStakersClipped
// * ErasValidatorPrefs
// * ErasTotalStake
// * ErasStartSessionIndex
// * translate StakingLedger
// * removal of:
// * Stakers
// * SlotStake
// * CurrentElected
// * CurrentEraStart
// * CurrentEraStartSessionIndex
// * CurrentEraPointsEarned
use super::*;
mod deprecated;
#[cfg(test)]
mod tests;
#[cfg(test)]
mod test_upgrade_from_master_dataset;
pub fn on_runtime_upgrade<T: Trait>() {
match StorageVersion::get() {
Releases::V2_0_0 => return,
Releases::V1_0_0 => upgrade_v1_to_v2::<T>(),
}
}
fn upgrade_v1_to_v2<T: Trait>() {
deprecated::IsUpgraded::kill();
let current_era_start_index = deprecated::CurrentEraStartSessionIndex::get();
let current_era = <Module<T> as Store>::CurrentEra::get().unwrap_or(0);
let current_era_start = deprecated::CurrentEraStart::<T>::get();
<Module<T> as Store>::ErasStartSessionIndex::insert(current_era, current_era_start_index);
<Module<T> as Store>::ActiveEra::put(ActiveEraInfo {
index: current_era,
start: Some(current_era_start),
});
let current_elected = deprecated::CurrentElected::<T>::get();
let mut current_total_stake = <BalanceOf<T>>::zero();
for validator in &current_elected {
let exposure = deprecated::Stakers::<T>::get(validator);
current_total_stake += exposure.total;
<Module<T> as Store>::ErasStakers::insert(current_era, validator, &exposure);
let mut exposure_clipped = exposure;
let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize;
if exposure_clipped.others.len() > clipped_max_len {
exposure_clipped.others.sort_unstable_by(|a, b| a.value.cmp(&b.value).reverse());
exposure_clipped.others.truncate(clipped_max_len);
}
<Module<T> as Store>::ErasStakersClipped::insert(current_era, validator, exposure_clipped);
let pref = <Module<T> as Store>::Validators::get(validator);
<Module<T> as Store>::ErasValidatorPrefs::insert(current_era, validator, pref);
}
<Module<T> as Store>::ErasTotalStake::insert(current_era, current_total_stake);
let points = deprecated::CurrentEraPointsEarned::get();
<Module<T> as Store>::ErasRewardPoints::insert(current_era, EraRewardPoints {
total: points.total,
individual: current_elected.iter().cloned().zip(points.individual.iter().cloned()).collect(),
});
let res = <Module<T> as Store>::Ledger::translate_values(
|old: deprecated::OldStakingLedger<T::AccountId, BalanceOf<T>>| StakingLedger {
stash: old.stash,
total: old.total,
active: old.active,
unlocking: old.unlocking,
last_reward: None,
}
);
if let Err(e) = res {
frame_support::print("Encountered error in migration of Staking::Ledger map.");
frame_support::print("The number of removed key/value is:");
frame_support::print(e);
}
// Kill old storages
deprecated::Stakers::<T>::remove_all();
deprecated::SlotStake::<T>::kill();
deprecated::CurrentElected::<T>::kill();
deprecated::CurrentEraStart::<T>::kill();
deprecated::CurrentEraStartSessionIndex::kill();
deprecated::CurrentEraPointsEarned::kill();
StorageVersion::put(Releases::V2_0_0);
}
File diff suppressed because one or more lines are too long
@@ -1,220 +0,0 @@
use crate::*;
use crate::mock::*;
use frame_support::storage::migration::*;
use sp_core::hashing::blake2_256;
use super::test_upgrade_from_master_dataset;
use sp_runtime::traits::OnRuntimeUpgrade;
#[test]
fn upgrade_works() {
ExtBuilder::default().build().execute_with(|| {
start_era(3);
assert_eq!(Session::validators(), vec![21, 11]);
// Insert fake data to check the migration
put_storage_value::<Vec<AccountId>>(b"Staking", b"CurrentElected", b"", vec![21, 31]);
put_storage_value::<SessionIndex>(b"Staking", b"CurrentEraStartSessionIndex", b"", 5);
put_storage_value::<MomentOf<Test>>(b"Staking", b"CurrentEraStart", b"", 777);
put_storage_value(
b"Staking", b"Stakers", &blake2_256(&11u64.encode()),
Exposure::<AccountId, Balance> {
total: 10,
own: 10,
others: vec![],
}
);
put_storage_value(
b"Staking", b"Stakers", &blake2_256(&21u64.encode()),
Exposure::<AccountId, Balance> {
total: 20,
own: 20,
others: vec![],
}
);
put_storage_value(
b"Staking", b"Stakers", &blake2_256(&31u64.encode()),
Exposure::<AccountId, Balance> {
total: 30,
own: 30,
others: vec![],
}
);
put_storage_value::<(u32, Vec<u32>)>(b"Staking", b"CurrentEraPointsEarned", b"", (12, vec![2, 10]));
<Staking as Store>::ErasStakers::remove_all();
<Staking as Store>::ErasStakersClipped::remove_all();
<Staking as Store>::StorageVersion::put(Releases::V1_0_0);
// Perform upgrade
Staking::on_runtime_upgrade();
assert_eq!(<Staking as Store>::StorageVersion::get(), Releases::V2_0_0);
// Check migration
assert_eq!(<Staking as Store>::ErasStartSessionIndex::get(3).unwrap(), 5);
assert_eq!(<Staking as Store>::ErasRewardPoints::get(3), EraRewardPoints {
total: 12,
individual: vec![(21, 2), (31, 10)].into_iter().collect(),
});
assert_eq!(<Staking as Store>::ActiveEra::get().unwrap().index, 3);
assert_eq!(<Staking as Store>::ActiveEra::get().unwrap().start, Some(777));
assert_eq!(<Staking as Store>::CurrentEra::get().unwrap(), 3);
assert_eq!(<Staking as Store>::ErasStakers::get(3, 11), Exposure {
total: 0,
own: 0,
others: vec![],
});
assert_eq!(<Staking as Store>::ErasStakers::get(3, 21), Exposure {
total: 20,
own: 20,
others: vec![],
});
assert_eq!(<Staking as Store>::ErasStakers::get(3, 31), Exposure {
total: 30,
own: 30,
others: vec![],
});
assert_eq!(<Staking as Store>::ErasStakersClipped::get(3, 11), Exposure {
total: 0,
own: 0,
others: vec![],
});
assert_eq!(<Staking as Store>::ErasStakersClipped::get(3, 21), Exposure {
total: 20,
own: 20,
others: vec![],
});
assert_eq!(<Staking as Store>::ErasStakersClipped::get(3, 31), Exposure {
total: 30,
own: 30,
others: vec![],
});
assert_eq!(<Staking as Store>::ErasValidatorPrefs::get(3, 21), Staking::validators(21));
assert_eq!(<Staking as Store>::ErasValidatorPrefs::get(3, 31), Staking::validators(31));
assert_eq!(<Staking as Store>::ErasTotalStake::get(3), 50);
})
}
// Test that an upgrade from previous test environment works.
#[test]
fn test_upgrade_from_master_works() {
let data_sets = &[
test_upgrade_from_master_dataset::_0,
test_upgrade_from_master_dataset::_1,
test_upgrade_from_master_dataset::_2,
test_upgrade_from_master_dataset::_3,
test_upgrade_from_master_dataset::_4,
test_upgrade_from_master_dataset::_5,
test_upgrade_from_master_dataset::_6,
test_upgrade_from_master_dataset::_7,
test_upgrade_from_master_dataset::_8,
];
for data_set in data_sets.iter() {
let mut storage = sp_runtime::Storage::default();
for (key, value) in data_set.iter() {
storage.top.insert(key.to_vec(), value.to_vec());
}
let mut ext = sp_io::TestExternalities::from(storage);
ext.execute_with(|| {
let old_stakers =
get_storage_value::<Vec<AccountId>>(b"Staking", b"CurrentElected", b"").unwrap();
let old_staker_0 = old_stakers[0];
let old_staker_1 = old_stakers[1];
let old_current_era =
get_storage_value::<EraIndex>(b"Staking", b"CurrentEra", b"").unwrap();
let old_staker_0_exposure = get_storage_value::<Exposure<AccountId, Balance>>(
b"Staking", b"Stakers", &blake2_256(&old_staker_0.encode())
).unwrap();
let old_staker_1_exposure = get_storage_value::<Exposure<AccountId, Balance>>(
b"Staking", b"Stakers", &blake2_256(&old_staker_1.encode())
).unwrap();
let (
old_era_points_earned_total,
old_era_points_earned_individual
) = get_storage_value::<(u32, Vec<u32>)>(b"Staking", b"CurrentEraPointsEarned", b"")
.unwrap_or((0, vec![]));
Staking::on_runtime_upgrade();
assert!(<Staking as Store>::StorageVersion::get() == Releases::V2_0_0);
// Check ActiveEra and CurrentEra
let active_era = Staking::active_era().unwrap().index;
let current_era = Staking::current_era().unwrap();
assert!(current_era == active_era);
assert!(current_era == old_current_era);
// Check ErasStartSessionIndex
let active_era_start = Staking::eras_start_session_index(active_era).unwrap();
let current_era_start = Staking::eras_start_session_index(current_era).unwrap();
let current_session_index = Session::current_index();
assert!(current_era_start == active_era_start);
assert!(active_era_start <= current_session_index);
assert_eq!(<Staking as Store>::ErasStartSessionIndex::iter().count(), 1);
// Check ErasStakers
assert_eq!(<Staking as Store>::ErasStakers::iter().count(), 2);
assert_eq!(
<Staking as Store>::ErasStakers::get(current_era, old_staker_0),
old_staker_0_exposure
);
assert_eq!(
<Staking as Store>::ErasStakers::get(current_era, old_staker_1),
old_staker_1_exposure
);
// Check ErasStakersClipped
assert_eq!(<Staking as Store>::ErasStakersClipped::iter().count(), 2);
assert!(<Staking as Store>::ErasStakersClipped::iter().all(|exposure_clipped| {
let max = <Test as Trait>::MaxNominatorRewardedPerValidator::get() as usize;
exposure_clipped.others.len() <= max
}));
assert_eq!(
<Staking as Store>::ErasStakersClipped::get(current_era, old_staker_0),
old_staker_0_exposure
);
assert_eq!(
<Staking as Store>::ErasStakersClipped::get(current_era, old_staker_1),
old_staker_1_exposure
);
// Check ErasValidatorPrefs
assert_eq!(<Staking as Store>::ErasValidatorPrefs::iter().count(), 2);
assert_eq!(
<Staking as Store>::ErasValidatorPrefs::get(current_era, old_staker_0),
Staking::validators(old_staker_0)
);
assert_eq!(
<Staking as Store>::ErasValidatorPrefs::get(current_era, old_staker_1),
Staking::validators(old_staker_1)
);
// Check ErasTotalStake
assert_eq!(<Staking as Store>::ErasTotalStake::iter().count(), 1);
assert_eq!(
<Staking as Store>::ErasTotalStake::get(current_era),
old_staker_0_exposure.total + old_staker_1_exposure.total
);
// Check ErasRewardPoints
assert_eq!(<Staking as Store>::ErasRewardPoints::iter().count(), 1);
let mut individual = BTreeMap::new();
if let Some(p) = old_era_points_earned_individual.get(0) {
individual.insert(old_staker_0, p.clone());
}
if let Some(p) = old_era_points_earned_individual.get(1) {
individual.insert(old_staker_1, p.clone());
}
assert_eq!(
<Staking as Store>::ErasRewardPoints::get(current_era),
EraRewardPoints {
total: old_era_points_earned_total,
individual,
}
);
// Check ErasValidatorReward
assert_eq!(<Staking as Store>::ErasValidatorReward::iter().count(), 0);
});
}
}
+4 -6
View File
@@ -25,10 +25,8 @@ use sp_staking::{SessionIndex, offence::{OffenceDetails, OnOffenceHandler}};
use sp_core::{H256, crypto::key_types};
use sp_io;
use frame_support::{
assert_ok, impl_outer_origin, parameter_types, StorageLinkedMap, StorageValue, StorageMap,
StorageDoubleMap,
traits::{Currency, Get, FindAuthor},
weights::Weight,
assert_ok, impl_outer_origin, parameter_types, StorageValue, StorageMap,
StorageDoubleMap, IterableStorageMap, traits::{Currency, Get, FindAuthor}, weights::Weight,
};
use crate::{
EraIndex, GenesisConfig, Module, Trait, StakerStatus, ValidatorPrefs, RewardDestination,
@@ -140,7 +138,7 @@ impl frame_system::Trait for Test {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
impl pallet_balances::Trait for Test {
@@ -373,7 +371,7 @@ pub fn check_exposure_all(era: EraIndex) {
}
pub fn check_nominator_all(era: EraIndex) {
<Nominators<Test>>::enumerate()
<Nominators<Test>>::iter()
.for_each(|(acc, _)| check_nominator_exposure(era, acc));
}
+4 -4
View File
@@ -76,7 +76,7 @@ fn basic_setup_works() {
assert_eq!(Staking::ledger(&1), None);
// ValidatorPrefs are default
assert_eq!(<Validators<Test>>::enumerate().collect::<Vec<_>>(), vec![
assert_eq!(<Validators<Test>>::iter().collect::<Vec<_>>(), vec![
(31, ValidatorPrefs::default()),
(21, ValidatorPrefs::default()),
(11, ValidatorPrefs::default())
@@ -2769,7 +2769,7 @@ fn slash_kicks_validators_not_nominators() {
// This is the best way to check that the validator was chilled; `get` will
// return default value.
for (stash, _) in <Staking as Store>::Validators::enumerate() {
for (stash, _) in <Staking as Store>::Validators::iter() {
assert!(stash != 11);
}
@@ -2869,7 +2869,7 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() {
// Fail: Era not finished yet
Error::<Test>::InvalidEraToReward
);
// Era 0 can't be rewarded anymore and current era can't be rewarded yet
// only era 1 and 2 can be rewarded.
@@ -2909,7 +2909,7 @@ fn zero_slash_keeps_nominators() {
// This is the best way to check that the validator was chilled; `get` will
// return default value.
for (stash, _) in <Staking as Store>::Validators::enumerate() {
for (stash, _) in <Staking as Store>::Validators::iter() {
assert!(stash != 11);
}
+1 -1
View File
@@ -14,7 +14,7 @@ serde = { version = "1.0.101", optional = true, features = ["derive"] }
codec = { package = "parity-scale-codec", version = "1.2.0", default-features = false, features = ["derive"] }
frame-metadata = { version = "11.0.0-alpha.2", default-features = false, path = "../metadata" }
sp-std = { version = "2.0.0-alpha.2", default-features = false, path = "../../primitives/std" }
sp-io ={ path = "../../primitives/io", default-features = false , version = "2.0.0-alpha.2"}
sp-io = { path = "../../primitives/io", default-features = false , version = "2.0.0-alpha.2"}
sp-runtime = { version = "2.0.0-alpha.2", default-features = false, path = "../../primitives/runtime" }
sp-core = { version = "2.0.0-alpha.2", default-features = false, path = "../../primitives/core" }
sp-arithmetic = { version = "2.0.0-alpha.2", default-features = false, path = "../../primitives/arithmetic" }
+31 -45
View File
@@ -33,8 +33,8 @@ use proc_macro::TokenStream;
/// decl_storage! {
/// trait Store for Module<T: Trait> as Example {
/// Foo get(fn foo) config(): u32=12;
/// Bar: map hasher(blake2_256) u32 => u32;
/// pub Zed build(|config| vec![(0, 0)]): linked_map hasher(blake2_256) u32 => u32;
/// Bar: map hasher(identity) u32 => u32;
/// pub Zed build(|config| vec![(0, 0)]): map hasher(identity) u32 => u32;
/// }
/// }
/// ```
@@ -70,10 +70,28 @@ use proc_macro::TokenStream;
/// And [`StoragePrefixedMap`](../frame_support/storage/trait.StoragePrefixedMap.html).
///
/// `$hash` representing a choice of hashing algorithms available in the
/// [`Hashable`](../frame_support/trait.Hashable.html) trait.
/// [`Hashable`](../frame_support/trait.Hashable.html) trait. You will generally want to use one
/// of three hashers:
/// * `blake2_128_concat`: The default, safe choice. Use if you are unsure or don't care. It is
/// secure against user-tainted keys, fairly fast and memory-efficient and supports
/// iteration over its keys and values. This must be used if the keys of your map can be
/// selected *en masse* by untrusted users.
/// * `twox_64_concat`: This is an insecure hasher and can only be used safely if you know that
/// the preimages cannot be chosen at will by untrusted users. It is memory-efficient, extremely
/// performant and supports iteration over its keys and values. You can safely use this is the
/// key is:
/// - A (slowly) incrementing index.
/// - Known to be the result of a cryptographic hash (though `identity` is a better choice here).
/// - Known to be the public key of a cryptographic key pair in existence.
/// * `identity`: This is not a hasher at all, and just uses the key material directly. Since it
/// does no hashing or appending, it's the fastest possible hasher, however, it's also the least
/// secure. It can be used only if you know that the key will be cryptographically/securely
/// randomly distributed over the binary encoding space. In most cases this will not be true.
/// One case where it is true, however, if where the key is itself the result of a cryptographic
/// hash of some existent data.
///
/// `blake2_256` and `blake2_128_concat` are strong hasher. One should use another hasher
/// with care, see generator documentation.
/// Other hashers will tend to be "opaque" and not support iteration over the keys in the
/// map. It is not recommended to use these.
///
/// The generator is implemented with:
/// * `module_prefix`: $module_prefix
@@ -85,36 +103,6 @@ use proc_macro::TokenStream;
/// twox128(module_prefix) ++ twox128(storage_prefix) ++ hasher(encode(key))
/// ```
///
/// * Linked map: `Foo: linked_map hasher($hash) type => type`: Implements the
/// [`StorageLinkedMap`](../frame_support/storage/trait.StorageLinkedMap.html) trait using the
/// [`StorageLinkedMap generator`](../frame_support/storage/generator/trait.StorageLinkedMap.html).
/// And [`StoragePrefixedMap`](../frame_support/storage/trait.StoragePrefixedMap.html).
///
/// `$hash` representing a choice of hashing algorithms available in the
/// [`Hashable`](../frame_support/trait.Hashable.html) trait.
///
/// `blake2_256` and `blake2_128_concat` are strong hasher. One should use another hasher
/// with care, see generator documentation.
///
/// All key formatting logic can be accessed in a type-agnostic format via the
/// `KeyFormat` trait, which
/// is implemented for the storage linked map type as well.
///
/// The generator key format is implemented with:
/// * `module_prefix`: $module_prefix
/// * `storage_prefix`: storage_name
/// * `head_prefix`: `"HeadOf" ++ storage_name`
/// * `Hasher`: $hash
///
/// Thus the keys are stored at:
/// ```nocompile
/// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key))
/// ```
/// and head is stored at:
/// ```nocompile
/// Twox128(module_prefix) ++ Twox128(head_prefix)
/// ```
///
/// * Double map: `Foo: double_map hasher($hash1) u32, hasher($hash2) u32 => u32`: Implements the
/// [`StorageDoubleMap`](../frame_support/storage/trait.StorageDoubleMap.html) trait using the
/// [`StorageDoubleMap generator`](../frame_support/storage/generator/trait.StorageDoubleMap.html).
@@ -124,14 +112,6 @@ use proc_macro::TokenStream;
/// [`Hashable`](../frame_support/trait.Hashable.html) trait. They must be chosen with care, see
/// generator documentation.
///
/// If the first key is untrusted, a cryptographic `hasher` such as `blake2_256` or
/// `blake2_128_concat` must be used.
/// Otherwise, other values of all storage items can be compromised.
///
/// If the second key is untrusted, a cryptographic `hasher` such as `blake2_256` or
/// `blake2_128_concat` must be used.
/// Otherwise, other items in storage with the same first key can be compromised.
///
/// The generator is implemented with:
/// * `module_prefix`: $module_prefix
/// * `storage_prefix`: storage_name
@@ -145,10 +125,16 @@ use proc_macro::TokenStream;
///
/// Supported hashers (ordered from least to best security):
///
/// * `twox_64_concat` - TwoX with 64bit + key concatenated.
/// * `identity` - Just the unrefined key material. Use only when it is known to be a secure hash
/// already. The most efficient and iterable over keys.
/// * `twox_64_concat` - TwoX with 64bit + key concatenated. Use only when an untrusted source
/// cannot select and insert key values. Very efficient and iterable over keys.
/// * `blake2_128_concat` - Blake2 with 128bit + key concatenated. Slower but safe to use in all
/// circumstances. Iterable over keys.
///
/// Deprecated hashers, which do not support iteration over keys include:
/// * `twox_128` - TwoX with 128bit.
/// * `twox_256` - TwoX with with 256bit.
/// * `blake2_128_concat` - Blake2 with 128bit + key concatenated.
/// * `blake2_128` - Blake2 with 128bit.
/// * `blake2_256` - Blake2 with 256bit.
///
@@ -88,7 +88,7 @@ impl BuilderDef {
}}
},
StorageLineTypeDef::Simple(_) => unreachable!(),
StorageLineTypeDef::Map(map) | StorageLineTypeDef::LinkedMap(map) => {
StorageLineTypeDef::Map(map) => {
let key = &map.key;
quote!{{
#data
@@ -93,7 +93,7 @@ impl GenesisConfigDef {
let typ = match &line.storage_type {
StorageLineTypeDef::Simple(_) => (*value_type).clone(),
StorageLineTypeDef::Map(map) | StorageLineTypeDef::LinkedMap(map) => {
StorageLineTypeDef::Map(map) => {
let key = &map.key;
parse_quote!( Vec<(#key, #value_type)> )
},
@@ -40,7 +40,7 @@ pub fn impl_getters(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStrea
}
}
},
StorageLineTypeDef::Map(map) | StorageLineTypeDef::LinkedMap(map) => {
StorageLineTypeDef::Map(map) => {
let key = &map.key;
let value = &map.value;
quote!{
@@ -41,20 +41,7 @@ fn storage_line_metadata_type(scrate: &TokenStream, line: &StorageLineDefExt) ->
hasher: #scrate::metadata::#hasher,
key: #scrate::metadata::DecodeDifferent::Encode(#key),
value: #scrate::metadata::DecodeDifferent::Encode(#value_type),
is_linked: false,
}
}
},
StorageLineTypeDef::LinkedMap(map) => {
let hasher = map.hasher.into_metadata();
let key = &map.key;
let key = clean_type_string(&quote!(#key).to_string());
quote!{
#scrate::metadata::StorageEntryType::Map {
hasher: #scrate::metadata::#hasher,
key: #scrate::metadata::DecodeDifferent::Encode(#key),
value: #scrate::metadata::DecodeDifferent::Encode(#value_type),
is_linked: true,
unused: false,
}
}
},
@@ -235,10 +235,6 @@ impl StorageLineDefExt {
ext::type_contains_ident(&map.key, &def.module_runtime_generic)
|| ext::type_contains_ident(&map.value, &def.module_runtime_generic)
}
StorageLineTypeDef::LinkedMap(map) => {
ext::type_contains_ident(&map.key, &def.module_runtime_generic)
|| ext::type_contains_ident(&map.value, &def.module_runtime_generic)
}
StorageLineTypeDef::DoubleMap(map) => {
ext::type_contains_ident(&map.key1, &def.module_runtime_generic)
|| ext::type_contains_ident(&map.key2, &def.module_runtime_generic)
@@ -249,7 +245,6 @@ impl StorageLineDefExt {
let query_type = match &storage_def.storage_type {
StorageLineTypeDef::Simple(value) => value.clone(),
StorageLineTypeDef::Map(map) => map.value.clone(),
StorageLineTypeDef::LinkedMap(map) => map.value.clone(),
StorageLineTypeDef::DoubleMap(map) => map.value.clone(),
};
let is_option = ext::extract_type_option(&query_type).is_some();
@@ -291,10 +286,6 @@ impl StorageLineDefExt {
let key = &map.key;
quote!( StorageMap<#key, #value_type> )
},
StorageLineTypeDef::LinkedMap(map) => {
let key = &map.key;
quote!( StorageLinkedMap<#key, #value_type> )
},
StorageLineTypeDef::DoubleMap(map) => {
let key1 = &map.key1;
let key2 = &map.key2;
@@ -336,7 +327,6 @@ impl StorageLineDefExt {
pub enum StorageLineTypeDef {
Map(MapDef),
LinkedMap(MapDef),
DoubleMap(DoubleMapDef),
Simple(syn::Type),
}
@@ -372,6 +362,7 @@ pub enum HasherKind {
Twox256,
Twox128,
Twox64Concat,
Identity,
}
impl HasherKind {
@@ -383,6 +374,7 @@ impl HasherKind {
HasherKind::Twox256 => quote!( Twox256 ),
HasherKind::Twox128 => quote!( Twox128 ),
HasherKind::Twox64Concat => quote!( Twox64Concat ),
HasherKind::Identity => quote!( Identity ),
}
}
@@ -394,6 +386,7 @@ impl HasherKind {
HasherKind::Twox256 => quote!( StorageHasher::Twox256 ),
HasherKind::Twox128 => quote!( StorageHasher::Twox128 ),
HasherKind::Twox64Concat => quote!( StorageHasher::Twox64Concat ),
HasherKind::Identity => quote!( StorageHasher::Identity ),
}
}
}
@@ -420,7 +413,6 @@ pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStr
use #scrate::{
StorageValue as _,
StorageMap as _,
StorageLinkedMap as _,
StorageDoubleMap as _,
StoragePrefixedMap as _,
};
@@ -27,15 +27,18 @@ mod keyword {
syn::custom_keyword!(build);
syn::custom_keyword!(get);
syn::custom_keyword!(map);
syn::custom_keyword!(linked_map);
syn::custom_keyword!(double_map);
syn::custom_keyword!(blake2_256);
syn::custom_keyword!(blake2_128);
syn::custom_keyword!(opaque_blake2_256);
syn::custom_keyword!(opaque_blake2_128);
syn::custom_keyword!(blake2_128_concat);
syn::custom_keyword!(twox_256);
syn::custom_keyword!(twox_128);
syn::custom_keyword!(opaque_twox_256);
syn::custom_keyword!(opaque_twox_128);
syn::custom_keyword!(twox_64_concat);
syn::custom_keyword!(identity);
syn::custom_keyword!(hasher);
syn::custom_keyword!(tainted);
syn::custom_keyword!(natural);
syn::custom_keyword!(prehashed);
}
/// Specific `Opt` to implement structure with optional parsing
@@ -194,7 +197,6 @@ impl_parse_for_opt!(DeclStorageBuild => keyword::build);
#[derive(ToTokens, Debug)]
enum DeclStorageType {
Map(DeclStorageMap),
LinkedMap(DeclStorageLinkedMap),
DoubleMap(DeclStorageDoubleMap),
Simple(syn::Type),
}
@@ -203,8 +205,6 @@ impl syn::parse::Parse for DeclStorageType {
fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
if input.peek(keyword::map) {
Ok(Self::Map(input.parse()?))
} else if input.peek(keyword::linked_map) {
Ok(Self::LinkedMap(input.parse()?))
} else if input.peek(keyword::double_map) {
Ok(Self::DoubleMap(input.parse()?))
} else {
@@ -222,15 +222,6 @@ struct DeclStorageMap {
pub value: syn::Type,
}
#[derive(Parse, ToTokens, Debug)]
struct DeclStorageLinkedMap {
pub map_keyword: keyword::linked_map,
pub hasher: Opt<SetHasher>,
pub key: syn::Type,
pub ass_keyword: Token![=>],
pub value: syn::Type,
}
#[derive(Parse, ToTokens, Debug)]
struct DeclStorageDoubleMap {
pub map_keyword: keyword::double_map,
@@ -245,29 +236,38 @@ struct DeclStorageDoubleMap {
#[derive(ToTokens, Debug)]
enum Hasher {
Blake2_256(keyword::blake2_256),
Blake2_128(keyword::blake2_128),
Blake2_256(keyword::opaque_blake2_256),
Blake2_128(keyword::opaque_blake2_128),
Blake2_128Concat(keyword::blake2_128_concat),
Twox256(keyword::twox_256),
Twox128(keyword::twox_128),
Twox256(keyword::opaque_twox_256),
Twox128(keyword::opaque_twox_128),
Twox64Concat(keyword::twox_64_concat),
Identity(keyword::identity),
}
impl syn::parse::Parse for Hasher {
fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(keyword::blake2_256) {
if lookahead.peek(keyword::opaque_blake2_256) {
Ok(Self::Blake2_256(input.parse()?))
} else if lookahead.peek(keyword::blake2_128) {
} else if lookahead.peek(keyword::opaque_blake2_128) {
Ok(Self::Blake2_128(input.parse()?))
} else if lookahead.peek(keyword::blake2_128_concat) {
Ok(Self::Blake2_128Concat(input.parse()?))
} else if lookahead.peek(keyword::twox_256) {
} else if lookahead.peek(keyword::opaque_twox_256) {
Ok(Self::Twox256(input.parse()?))
} else if lookahead.peek(keyword::twox_128) {
} else if lookahead.peek(keyword::opaque_twox_128) {
Ok(Self::Twox128(input.parse()?))
} else if lookahead.peek(keyword::twox_64_concat) {
Ok(Self::Twox64Concat(input.parse()?))
} else if lookahead.peek(keyword::identity) {
Ok(Self::Identity(input.parse()?))
} else if lookahead.peek(keyword::tainted) {
Ok(Self::Blake2_128Concat(input.parse()?))
} else if lookahead.peek(keyword::natural) {
Ok(Self::Twox64Concat(input.parse()?))
} else if lookahead.peek(keyword::prehashed) {
Ok(Self::Identity(input.parse()?))
} else {
Err(lookahead.error())
}
@@ -313,6 +313,7 @@ impl From<Hasher> for super::HasherKind {
Hasher::Twox256(_) => super::HasherKind::Twox256,
Hasher::Twox128(_) => super::HasherKind::Twox128,
Hasher::Twox64Concat(_) => super::HasherKind::Twox64Concat,
Hasher::Identity(_) => super::HasherKind::Identity,
}
}
}
@@ -464,7 +465,7 @@ fn parse_storage_line_defs(
let span = line.storage_type.span();
let no_hasher_error = || syn::Error::new(
span,
"Default hasher has been removed, use explicit hasher(blake2_256) instead."
"Default hasher has been removed, use explicit hasher(blake2_128_concat) instead."
);
let storage_type = match line.storage_type {
@@ -475,13 +476,6 @@ fn parse_storage_line_defs(
value: map.value,
}
),
DeclStorageType::LinkedMap(map) => super::StorageLineTypeDef::LinkedMap(
super::MapDef {
hasher: map.hasher.inner.ok_or_else(no_hasher_error)?.into(),
key: map.key,
value: map.value,
}
),
DeclStorageType::DoubleMap(map) => super::StorageLineTypeDef::DoubleMap(
super::DoubleMapDef {
hasher1: map.hasher1.inner.ok_or_else(no_hasher_error)?.into(),
@@ -158,47 +158,6 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre
}
)
},
StorageLineTypeDef::LinkedMap(map) => {
let hasher = map.hasher.to_storage_hasher_struct();
let head_prefix_str = syn::LitStr::new(
&format!("HeadOf{}", line.name.to_string()),
line.name.span(),
);
quote!(
impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct
#optional_storage_where_clause
{
type Query = #query_type;
type KeyFormat = Self;
fn from_optional_value_to_query(v: Option<#value_type>) -> Self::Query {
#from_optional_value_to_query
}
fn from_query_to_optional_value(v: Self::Query) -> Option<#value_type> {
#from_query_to_optional_value
}
}
impl<#impl_trait> #scrate::storage::generator::LinkedMapKeyFormat for #storage_struct {
type Hasher = #scrate::#hasher;
fn module_prefix() -> &'static [u8] {
#instance_or_inherent::PREFIX.as_bytes()
}
fn storage_prefix() -> &'static [u8] {
#storage_name_str.as_bytes()
}
fn head_prefix() -> &'static [u8] {
#head_prefix_str.as_bytes()
}
}
)
},
StorageLineTypeDef::DoubleMap(map) => {
let hasher1 = map.hasher1.to_storage_hasher_struct();
let hasher2 = map.hasher2.to_storage_hasher_struct();
+31
View File
@@ -28,6 +28,7 @@ pub trait Hashable: Sized {
fn twox_128(&self) -> [u8; 16];
fn twox_256(&self) -> [u8; 32];
fn twox_64_concat(&self) -> Vec<u8>;
fn identity(&self) -> Vec<u8>;
}
impl<T: Codec> Hashable for T {
@@ -49,6 +50,7 @@ impl<T: Codec> Hashable for T {
fn twox_64_concat(&self) -> Vec<u8> {
self.using_encoded(Twox64Concat::hash)
}
fn identity(&self) -> Vec<u8> { self.encode() }
}
/// Hasher to use to hash keys to insert to storage.
@@ -57,6 +59,25 @@ pub trait StorageHasher: 'static {
fn hash(x: &[u8]) -> Self::Output;
}
/// Hasher to use to hash keys to insert to storage.
pub trait ReversibleStorageHasher: StorageHasher {
fn reverse(x: &[u8]) -> &[u8];
}
/// Store the key directly.
pub struct Identity;
impl StorageHasher for Identity {
type Output = Vec<u8>;
fn hash(x: &[u8]) -> Vec<u8> {
x.to_vec()
}
}
impl ReversibleStorageHasher for Identity {
fn reverse(x: &[u8]) -> &[u8] {
x
}
}
/// Hash storage keys with `concat(twox64(key), key)`
pub struct Twox64Concat;
impl StorageHasher for Twox64Concat {
@@ -69,6 +90,11 @@ impl StorageHasher for Twox64Concat {
.collect::<Vec<_>>()
}
}
impl ReversibleStorageHasher for Twox64Concat {
fn reverse(x: &[u8]) -> &[u8] {
&x[8..]
}
}
/// Hash storage keys with `concat(blake2_128(key), key)`
pub struct Blake2_128Concat;
@@ -82,6 +108,11 @@ impl StorageHasher for Blake2_128Concat {
.collect::<Vec<_>>()
}
}
impl ReversibleStorageHasher for Blake2_128Concat {
fn reverse(x: &[u8]) -> &[u8] {
&x[16..]
}
}
/// Hash storage keys with blake2 128
pub struct Blake2_128;
+53 -53
View File
@@ -67,11 +67,12 @@ pub mod traits;
pub mod weights;
pub use self::hash::{
Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat, Blake2_128Concat, Hashable,
Twox256, Twox128, Blake2_256, Blake2_128, Identity, Twox64Concat, Blake2_128Concat, Hashable,
StorageHasher
};
pub use self::storage::{
StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap, StoragePrefixedMap
StorageValue, StorageMap, StorageDoubleMap, StoragePrefixedMap, IterableStorageMap,
IterableStorageDoubleMap,
};
pub use self::dispatch::{Parameter, Callable, IsSubType};
pub use sp_runtime::{self, ConsensusEngineId, print, traits::Printable};
@@ -253,24 +254,24 @@ mod tests {
decl_storage! {
trait Store for Module<T: Trait> as Test {
pub Data get(fn data) build(|_| vec![(15u32, 42u64)]):
linked_map hasher(twox_64_concat) u32 => u64;
pub OptionLinkedMap: linked_map hasher(blake2_256) u32 => Option<u32>;
map hasher(twox_64_concat) u32 => u64;
pub OptionLinkedMap: map hasher(blake2_128_concat) u32 => Option<u32>;
pub GenericData get(fn generic_data):
linked_map hasher(twox_128) T::BlockNumber => T::BlockNumber;
map hasher(identity) T::BlockNumber => T::BlockNumber;
pub GenericData2 get(fn generic_data2):
linked_map hasher(blake2_256) T::BlockNumber => Option<T::BlockNumber>;
map hasher(blake2_128_concat) T::BlockNumber => Option<T::BlockNumber>;
pub GetterNoFnKeyword get(no_fn): Option<u32>;
pub DataDM config(test_config) build(|_| vec![(15u32, 16u32, 42u64)]):
double_map hasher(twox_64_concat) u32, hasher(blake2_256) u32 => u64;
double_map hasher(twox_64_concat) u32, hasher(blake2_128_concat) u32 => u64;
pub GenericDataDM:
double_map hasher(blake2_256) T::BlockNumber, hasher(twox_128) T::BlockNumber
double_map hasher(blake2_128_concat) T::BlockNumber, hasher(identity) T::BlockNumber
=> T::BlockNumber;
pub GenericData2DM:
double_map hasher(blake2_256) T::BlockNumber, hasher(twox_256) T::BlockNumber
double_map hasher(blake2_128_concat) T::BlockNumber, hasher(twox_64_concat) T::BlockNumber
=> Option<T::BlockNumber>;
pub AppendableDM:
double_map hasher(blake2_256) u32, hasher(blake2_256) T::BlockNumber => Vec<u32>;
double_map hasher(blake2_128_concat) u32, hasher(blake2_128_concat) T::BlockNumber => Vec<u32>;
}
}
@@ -286,8 +287,16 @@ mod tests {
type Map = Data;
trait Sorted { fn sorted(self) -> Self; }
impl<T: Ord> Sorted for Vec<T> {
fn sorted(mut self) -> Self {
self.sort();
self
}
}
#[test]
fn linked_map_issue_3318() {
fn map_issue_3318() {
new_test_ext().execute_with(|| {
OptionLinkedMap::insert(1, 1);
assert_eq!(OptionLinkedMap::get(1), Some(1));
@@ -297,31 +306,31 @@ mod tests {
}
#[test]
fn linked_map_swap_works() {
fn map_swap_works() {
new_test_ext().execute_with(|| {
OptionLinkedMap::insert(0, 0);
OptionLinkedMap::insert(1, 1);
OptionLinkedMap::insert(2, 2);
OptionLinkedMap::insert(3, 3);
let collect = || OptionLinkedMap::enumerate().collect::<Vec<_>>();
assert_eq!(collect(), vec![(3, 3), (2, 2), (1, 1), (0, 0)]);
let collect = || OptionLinkedMap::iter().collect::<Vec<_>>().sorted();
assert_eq!(collect(), vec![(0, 0), (1, 1), (2, 2), (3, 3)]);
// Two existing
OptionLinkedMap::swap(1, 2);
assert_eq!(collect(), vec![(3, 3), (2, 1), (1, 2), (0, 0)]);
assert_eq!(collect(), vec![(0, 0), (1, 2), (2, 1), (3, 3)]);
// Back to normal
OptionLinkedMap::swap(2, 1);
assert_eq!(collect(), vec![(3, 3), (2, 2), (1, 1), (0, 0)]);
assert_eq!(collect(), vec![(0, 0), (1, 1), (2, 2), (3, 3)]);
// Left existing
OptionLinkedMap::swap(2, 5);
assert_eq!(collect(), vec![(5, 2), (3, 3), (1, 1), (0, 0)]);
assert_eq!(collect(), vec![(0, 0), (1, 1), (3, 3), (5, 2)]);
// Right existing
OptionLinkedMap::swap(5, 2);
assert_eq!(collect(), vec![(2, 2), (3, 3), (1, 1), (0, 0)]);
assert_eq!(collect(), vec![(0, 0), (1, 1), (2, 2), (3, 3)]);
});
}
@@ -356,7 +365,7 @@ mod tests {
}
#[test]
fn linked_map_basic_insert_remove_should_work() {
fn map_basic_insert_remove_should_work() {
new_test_ext().execute_with(|| {
// initialized during genesis
assert_eq!(Map::get(&15u32), 42u64);
@@ -382,54 +391,45 @@ mod tests {
}
#[test]
fn linked_map_enumeration_and_head_should_work() {
fn map_iteration_should_work() {
new_test_ext().execute_with(|| {
assert_eq!(Map::head(), Some(15));
assert_eq!(Map::enumerate().collect::<Vec<_>>(), vec![(15, 42)]);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(15, 42)]);
// insert / remove
let key = 17u32;
Map::insert(key, 4u64);
assert_eq!(Map::head(), Some(key));
assert_eq!(Map::enumerate().collect::<Vec<_>>(), vec![(key, 4), (15, 42)]);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(15, 42), (key, 4)]);
assert_eq!(Map::take(&15), 42u64);
assert_eq!(Map::take(&key), 4u64);
assert_eq!(Map::head(), None);
assert_eq!(Map::enumerate().collect::<Vec<_>>(), vec![]);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![]);
// Add couple of more elements
Map::insert(key, 42u64);
assert_eq!(Map::head(), Some(key));
assert_eq!(Map::enumerate().collect::<Vec<_>>(), vec![(key, 42)]);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(key, 42)]);
Map::insert(key + 1, 43u64);
assert_eq!(Map::head(), Some(key + 1));
assert_eq!(Map::enumerate().collect::<Vec<_>>(), vec![(key + 1, 43), (key, 42)]);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(key, 42), (key + 1, 43)]);
// mutate
let key = key + 2;
Map::mutate(&key, |val| {
*val = 15;
});
assert_eq!(Map::enumerate().collect::<Vec<_>>(), vec![(key, 15), (key - 1, 43), (key - 2, 42)]);
assert_eq!(Map::head(), Some(key));
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(key - 2, 42), (key - 1, 43), (key, 15)]);
Map::mutate(&key, |val| {
*val = 17;
});
assert_eq!(Map::enumerate().collect::<Vec<_>>(), vec![(key, 17), (key - 1, 43), (key - 2, 42)]);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(key - 2, 42), (key - 1, 43), (key, 17)]);
// remove first
Map::remove(&key);
assert_eq!(Map::head(), Some(key - 1));
assert_eq!(Map::enumerate().collect::<Vec<_>>(), vec![(key - 1, 43), (key - 2, 42)]);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(key - 2, 42), (key - 1, 43)]);
// remove last from the list
Map::remove(&(key - 2));
assert_eq!(Map::head(), Some(key - 1));
assert_eq!(Map::enumerate().collect::<Vec<_>>(), vec![(key - 1, 43)]);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(key - 1, 43)]);
// remove the last element
Map::remove(&(key - 1));
assert_eq!(Map::head(), None);
assert_eq!(Map::enumerate().collect::<Vec<_>>(), vec![]);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![]);
});
}
@@ -498,7 +498,7 @@ mod tests {
hasher: StorageHasher::Twox64Concat,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("u64"),
is_linked: true,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructData(PhantomData::<Test>))
@@ -509,10 +509,10 @@ mod tests {
name: DecodeDifferent::Encode("OptionLinkedMap"),
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("u32"),
is_linked: true,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructOptionLinkedMap(PhantomData::<Test>))
@@ -523,10 +523,10 @@ mod tests {
name: DecodeDifferent::Encode("GenericData"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Map{
hasher: StorageHasher::Twox128,
hasher: StorageHasher::Identity,
key: DecodeDifferent::Encode("T::BlockNumber"),
value: DecodeDifferent::Encode("T::BlockNumber"),
is_linked: true
unused: false
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructGenericData(PhantomData::<Test>))
@@ -537,10 +537,10 @@ mod tests {
name: DecodeDifferent::Encode("GenericData2"),
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map{
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key: DecodeDifferent::Encode("T::BlockNumber"),
value: DecodeDifferent::Encode("T::BlockNumber"),
is_linked: true
unused: false
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructGenericData2(PhantomData::<Test>))
@@ -564,7 +564,7 @@ mod tests {
key1: DecodeDifferent::Encode("u32"),
key2: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("u64"),
key2_hasher: StorageHasher::Blake2_256,
key2_hasher: StorageHasher::Blake2_128Concat,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructDataDM(PhantomData::<Test>))
@@ -575,11 +575,11 @@ mod tests {
name: DecodeDifferent::Encode("GenericDataDM"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::DoubleMap{
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key1: DecodeDifferent::Encode("T::BlockNumber"),
key2: DecodeDifferent::Encode("T::BlockNumber"),
value: DecodeDifferent::Encode("T::BlockNumber"),
key2_hasher: StorageHasher::Twox128,
key2_hasher: StorageHasher::Identity,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructGenericDataDM(PhantomData::<Test>))
@@ -590,11 +590,11 @@ mod tests {
name: DecodeDifferent::Encode("GenericData2DM"),
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::DoubleMap{
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key1: DecodeDifferent::Encode("T::BlockNumber"),
key2: DecodeDifferent::Encode("T::BlockNumber"),
value: DecodeDifferent::Encode("T::BlockNumber"),
key2_hasher: StorageHasher::Twox256,
key2_hasher: StorageHasher::Twox64Concat,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructGenericData2DM(PhantomData::<Test>))
@@ -605,11 +605,11 @@ mod tests {
name: DecodeDifferent::Encode("AppendableDM"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::DoubleMap{
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key1: DecodeDifferent::Encode("u32"),
key2: DecodeDifferent::Encode("T::BlockNumber"),
value: DecodeDifferent::Encode("Vec<u32>"),
key2_hasher: StorageHasher::Blake2_256,
key2_hasher: StorageHasher::Blake2_128Concat,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructGenericData2DM(PhantomData::<Test>))
@@ -16,8 +16,9 @@
use sp_std::prelude::*;
use sp_std::borrow::Borrow;
use codec::{Ref, FullCodec, FullEncode, Encode, EncodeLike, EncodeAppend};
use crate::{storage::{self, unhashed}, hash::{StorageHasher, Twox128}, traits::Len};
use codec::{Ref, FullCodec, FullEncode, Decode, Encode, EncodeLike, EncodeAppend};
use crate::{storage::{self, unhashed}, traits::Len};
use crate::hash::{StorageHasher, Twox128, ReversibleStorageHasher};
/// Generator for `StorageDoubleMap` used by `decl_storage`.
///
@@ -55,6 +56,22 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
/// Storage prefix. Used for generating final key.
fn storage_prefix() -> &'static [u8];
/// The full prefix; just the hash of `module_prefix` concatenated to the hash of
/// `storage_prefix`.
fn prefix_hash() -> Vec<u8> {
let module_prefix_hashed = Twox128::hash(Self::module_prefix());
let storage_prefix_hashed = Twox128::hash(Self::storage_prefix());
let mut result = Vec::with_capacity(
module_prefix_hashed.len() + storage_prefix_hashed.len()
);
result.extend_from_slice(&module_prefix_hashed[..]);
result.extend_from_slice(&storage_prefix_hashed[..]);
result
}
/// Convert an optional value retrieved from storage to the type queried.
fn from_optional_value_to_query(v: Option<V>) -> Self::Query;
@@ -62,8 +79,7 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
fn from_query_to_optional_value(v: Self::Query) -> Option<V>;
/// Generate the first part of the key used in top storage.
fn storage_double_map_final_key1<KArg1>(k1: KArg1) -> Vec<u8>
where
fn storage_double_map_final_key1<KArg1>(k1: KArg1) -> Vec<u8> where
KArg1: EncodeLike<K1>,
{
let module_prefix_hashed = Twox128::hash(Self::module_prefix());
@@ -82,19 +98,32 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
}
/// Generate the full key used in top storage.
fn storage_double_map_final_key<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Vec<u8>
where
fn storage_double_map_final_key<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Vec<u8> where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
let mut final_key = Self::storage_double_map_final_key1(k1);
final_key.extend_from_slice(k2.using_encoded(Self::Hasher2::hash).as_ref());
let module_prefix_hashed = Twox128::hash(Self::module_prefix());
let storage_prefix_hashed = Twox128::hash(Self::storage_prefix());
let key1_hashed = k1.borrow().using_encoded(Self::Hasher1::hash);
let key2_hashed = k2.borrow().using_encoded(Self::Hasher2::hash);
let mut final_key = Vec::with_capacity(
module_prefix_hashed.len()
+ storage_prefix_hashed.len()
+ key1_hashed.as_ref().len()
+ key2_hashed.as_ref().len()
);
final_key.extend_from_slice(&module_prefix_hashed[..]);
final_key.extend_from_slice(&storage_prefix_hashed[..]);
final_key.extend_from_slice(key1_hashed.as_ref());
final_key.extend_from_slice(key2_hashed.as_ref());
final_key
}
}
impl<K1, K2, V, G> storage::StorageDoubleMap<K1, K2, V> for G
where
impl<K1, K2, V, G> storage::StorageDoubleMap<K1, K2, V> for G where
K1: FullEncode,
K2: FullEncode,
V: FullCodec,
@@ -102,32 +131,28 @@ where
{
type Query = G::Query;
fn hashed_key_for<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Vec<u8>
where
fn hashed_key_for<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Vec<u8> where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
Self::storage_double_map_final_key(k1, k2)
}
fn contains_key<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> bool
where
fn contains_key<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> bool where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
unhashed::exists(&Self::storage_double_map_final_key(k1, k2))
}
fn get<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Self::Query
where
fn get<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Self::Query where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
G::from_optional_value_to_query(unhashed::get(&Self::storage_double_map_final_key(k1, k2)))
}
fn take<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Self::Query
where
fn take<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Self::Query where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
@@ -137,8 +162,12 @@ where
G::from_optional_value_to_query(value)
}
fn swap<XKArg1, XKArg2, YKArg1, YKArg2>(x_k1: XKArg1, x_k2: XKArg2, y_k1: YKArg1, y_k2: YKArg2)
where
fn swap<XKArg1, XKArg2, YKArg1, YKArg2>(
x_k1: XKArg1,
x_k2: XKArg2,
y_k1: YKArg1,
y_k2: YKArg2
) where
XKArg1: EncodeLike<K1>,
XKArg2: EncodeLike<K2>,
YKArg1: EncodeLike<K1>,
@@ -160,8 +189,7 @@ where
}
}
fn insert<KArg1, KArg2, VArg>(k1: KArg1, k2: KArg2, val: VArg)
where
fn insert<KArg1, KArg2, VArg>(k1: KArg1, k2: KArg2, val: VArg) where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
VArg: EncodeLike<V>,
@@ -169,8 +197,7 @@ where
unhashed::put(&Self::storage_double_map_final_key(k1, k2), &val.borrow())
}
fn remove<KArg1, KArg2>(k1: KArg1, k2: KArg2)
where
fn remove<KArg1, KArg2>(k1: KArg1, k2: KArg2) where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
@@ -181,8 +208,8 @@ where
unhashed::kill_prefix(Self::storage_double_map_final_key1(k1).as_ref())
}
fn iter_prefix<KArg1>(k1: KArg1) -> storage::PrefixIterator<V>
where KArg1: ?Sized + EncodeLike<K1>
fn iter_prefix<KArg1>(k1: KArg1) -> storage::PrefixIterator<V> where
KArg1: ?Sized + EncodeLike<K1>
{
let prefix = Self::storage_double_map_final_key1(k1);
storage::PrefixIterator::<V> {
@@ -192,8 +219,7 @@ where
}
}
fn mutate<KArg1, KArg2, R, F>(k1: KArg1, k2: KArg2, f: F) -> R
where
fn mutate<KArg1, KArg2, R, F>(k1: KArg1, k2: KArg2, f: F) -> R where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
F: FnOnce(&mut Self::Query) -> R,
@@ -213,8 +239,7 @@ where
k1: KArg1,
k2: KArg2,
items: Items,
) -> Result<(), &'static str>
where
) -> Result<(), &'static str> where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
Item: Encode,
@@ -246,8 +271,7 @@ where
k1: KArg1,
k2: KArg2,
items: Items,
)
where
) where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
Item: Encode,
@@ -260,10 +284,10 @@ where
.unwrap_or_else(|_| Self::insert(k1, k2, items));
}
fn decode_len<KArg1, KArg2>(key1: KArg1, key2: KArg2) -> Result<usize, &'static str>
where KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
V: codec::DecodeLength + Len,
fn decode_len<KArg1, KArg2>(key1: KArg1, key2: KArg2) -> Result<usize, &'static str> where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
V: codec::DecodeLength + Len,
{
let final_key = Self::storage_double_map_final_key(key1, key2);
if let Some(v) = unhashed::get_raw(&final_key) {
@@ -276,6 +300,135 @@ where
Ok(len)
}
}
fn migrate_keys<
OldHasher1: StorageHasher,
OldHasher2: StorageHasher,
KeyArg1: EncodeLike<K1>,
KeyArg2: EncodeLike<K2>,
>(key1: KeyArg1, key2: KeyArg2) -> Option<V> {
let old_key = {
let module_prefix_hashed = Twox128::hash(Self::module_prefix());
let storage_prefix_hashed = Twox128::hash(Self::storage_prefix());
let key1_hashed = key1.borrow().using_encoded(OldHasher1::hash);
let key2_hashed = key2.borrow().using_encoded(OldHasher2::hash);
let mut final_key = Vec::with_capacity(
module_prefix_hashed.len()
+ storage_prefix_hashed.len()
+ key1_hashed.as_ref().len()
+ key2_hashed.as_ref().len()
);
final_key.extend_from_slice(&module_prefix_hashed[..]);
final_key.extend_from_slice(&storage_prefix_hashed[..]);
final_key.extend_from_slice(key1_hashed.as_ref());
final_key.extend_from_slice(key2_hashed.as_ref());
final_key
};
unhashed::take(old_key.as_ref()).map(|value| {
unhashed::put(Self::storage_double_map_final_key(key1, key2).as_ref(), &value);
value
})
}
}
/// Utility to iterate through items in a storage map.
pub struct MapIterator<K, V, Hasher> {
prefix: Vec<u8>,
previous_key: Vec<u8>,
drain: bool,
_phantom: ::sp_std::marker::PhantomData<(K, V, Hasher)>,
}
impl<
K: Decode + Sized,
V: Decode + Sized,
Hasher: ReversibleStorageHasher
> Iterator for MapIterator<K, V, Hasher> {
type Item = (K, V);
fn next(&mut self) -> Option<(K, V)> {
loop {
let maybe_next = sp_io::storage::next_key(&self.previous_key)
.filter(|n| n.starts_with(&self.prefix));
break match maybe_next {
Some(next) => {
self.previous_key = next;
match unhashed::get::<V>(&self.previous_key) {
Some(value) => {
if self.drain {
unhashed::kill(&self.previous_key)
}
let mut key_material = Hasher::reverse(&self.previous_key[self.prefix.len()..]);
match K::decode(&mut key_material) {
Ok(key) => Some((key, value)),
Err(_) => continue,
}
}
None => continue,
}
}
None => None,
}
}
}
}
impl<
K1: FullCodec,
K2: FullCodec,
V: FullCodec,
G: StorageDoubleMap<K1, K2, V>,
> storage::IterableStorageDoubleMap<K1, K2, V> for G where
G::Hasher1: ReversibleStorageHasher,
G::Hasher2: ReversibleStorageHasher
{
type Iterator = MapIterator<K2, V, G::Hasher2>;
/// Enumerate all elements in the map.
fn iter(k1: impl EncodeLike<K1>) -> Self::Iterator {
let prefix = G::storage_double_map_final_key1(k1);
Self::Iterator {
prefix: prefix.clone(),
previous_key: prefix,
drain: false,
_phantom: Default::default(),
}
}
/// Enumerate all elements in the map.
fn drain(k1: impl EncodeLike<K1>) -> Self::Iterator {
let prefix = G::storage_double_map_final_key1(k1);
Self::Iterator {
prefix: prefix.clone(),
previous_key: prefix,
drain: true,
_phantom: Default::default(),
}
}
fn translate<O: Decode, F: Fn(O) -> Option<V>>(f: F) {
let prefix = G::prefix_hash();
let mut previous_key = prefix.clone();
loop {
match sp_io::storage::next_key(&previous_key).filter(|n| n.starts_with(&prefix)) {
Some(next) => {
previous_key = next;
let maybe_value = unhashed::get::<O>(&previous_key);
match maybe_value {
Some(value) => match f(value) {
Some(new) => unhashed::put::<V>(&previous_key, &new),
None => unhashed::kill(&previous_key),
},
None => continue,
}
}
None => return,
}
}
}
}
#[cfg(test)]
@@ -1,499 +0,0 @@
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use codec::{FullCodec, Encode, Decode, EncodeLike, Ref};
use crate::{storage::{self, unhashed}, hash::{StorageHasher, Twox128}, traits::Len};
use sp_std::{prelude::*, marker::PhantomData};
/// Generator for `StorageLinkedMap` used by `decl_storage`.
///
/// By default final key generation rely on `KeyFormat`.
pub trait StorageLinkedMap<K: FullCodec, V: FullCodec> {
/// The type that get/take returns.
type Query;
/// The family of key formats used for this map.
type KeyFormat: KeyFormat;
/// Convert an optional value retrieved from storage to the type queried.
fn from_optional_value_to_query(v: Option<V>) -> Self::Query;
/// Convert a query to an optional value into storage.
fn from_query_to_optional_value(v: Self::Query) -> Option<V>;
/// Generate the full key used in top storage.
fn storage_linked_map_final_key<KeyArg>(key: KeyArg) -> Vec<u8>
where
KeyArg: EncodeLike<K>,
{
<Self::KeyFormat as KeyFormat>::storage_linked_map_final_key::<KeyArg>(&key)
}
/// Generate the hashed key for head
fn storage_linked_map_final_head_key() -> Vec<u8> {
<Self::KeyFormat as KeyFormat>::storage_linked_map_final_head_key()
}
}
/// A type-abstracted key format used for a family of linked-map types.
///
/// # Default mapping of keys to a storage path
///
/// The key for the head of the map is stored at one fixed path:
/// ```nocompile
/// Twox128(module_prefix) ++ Twox128(head_prefix)
/// ```
///
/// For each key, the value stored under that key is appended with a
/// [`Linkage`](struct.Linkage.html) (which hold previous and next key) at the path:
/// ```nocompile
/// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key))
/// ```
///
/// Enumeration is done by getting the head of the linked map and then iterating getting the
/// value and linkage stored at the key until the found linkage has no next key.
///
/// # Warning
///
/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as
/// `blake2_256` must be used. Otherwise, other values in storage can be compromised.
pub trait KeyFormat {
/// Hasher. Used for generating final key and final head key.
type Hasher: StorageHasher;
/// Module prefix. Used for generating final key.
fn module_prefix() -> &'static [u8];
/// Storage prefix. Used for generating final key.
fn storage_prefix() -> &'static [u8];
/// Storage prefix. Used for generating final head key.
fn head_prefix() -> &'static [u8];
/// Generate the full key used in top storage.
fn storage_linked_map_final_key<K>(key: &K) -> Vec<u8>
where
K: Encode,
{
let module_prefix_hashed = Twox128::hash(Self::module_prefix());
let storage_prefix_hashed = Twox128::hash(Self::storage_prefix());
let key_hashed = key.using_encoded(Self::Hasher::hash);
let mut final_key = Vec::with_capacity(
module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.as_ref().len()
);
final_key.extend_from_slice(&module_prefix_hashed[..]);
final_key.extend_from_slice(&storage_prefix_hashed[..]);
final_key.extend_from_slice(key_hashed.as_ref());
final_key
}
/// Generate the full key used in top storage to store the head of the linked map.
fn storage_linked_map_final_head_key() -> Vec<u8> {
[
Twox128::hash(Self::module_prefix()),
Twox128::hash(Self::head_prefix()),
].concat()
}
}
/// Linkage data of an element (it's successor and predecessor)
#[derive(Encode, Decode)]
pub struct Linkage<Key> {
/// Previous element key in storage (None for the first element)
pub previous: Option<Key>,
/// Next element key in storage (None for the last element)
pub next: Option<Key>,
}
impl<Key> Default for Linkage<Key> {
fn default() -> Self {
Self {
previous: None,
next: None,
}
}
}
// Encode like a linkage.
#[derive(Encode)]
struct EncodeLikeLinkage<PKey: EncodeLike<Key>, NKey: EncodeLike<Key>, Key: Encode> {
// Previous element key in storage (None for the first element)
previous: Option<PKey>,
// Next element key in storage (None for the last element)
next: Option<NKey>,
// The key of the linkage this type encode to
phantom: core::marker::PhantomData<Key>,
}
/// A key-value pair iterator for enumerable map.
pub struct Enumerator<K, V, F> {
next: Option<K>,
_phantom: PhantomData<(V, F)>,
}
impl<K, V, F> Enumerator<K, V, F> {
/// Create an explicit enumerator for testing.
#[cfg(test)]
pub fn from_head(head: K) -> Self {
Enumerator {
next: Some(head),
_phantom: Default::default(),
}
}
}
impl<K, V, F> Iterator for Enumerator<K, V, F>
where
K: FullCodec,
V: FullCodec,
F: KeyFormat,
{
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
let next = self.next.take()?;
let (val, linkage): (V, Linkage<K>) = {
let next_full_key = F::storage_linked_map_final_key(&next);
match read_with_linkage::<K, V>(next_full_key.as_ref()) {
Some(value) => value,
None => {
// TODO #3700: error should be handleable.
runtime_print!(
"ERROR: Corrupted state: linked map {:?}{:?}: \
next value doesn't exist at {:?}",
F::module_prefix(), F::storage_prefix(), next_full_key,
);
return None
}
}
};
self.next = linkage.next;
Some((next, val))
}
}
/// Update linkage when this element is removed.
///
/// Takes care of updating previous and next elements points
/// as well as updates head if the element is first or last.
fn remove_linkage<K, V, F>(linkage: Linkage<K>)
where
K: FullCodec,
V: FullCodec,
F: KeyFormat,
{
let next_key = linkage.next.as_ref().map(|k| F::storage_linked_map_final_key(k));
let prev_key = linkage.previous.as_ref().map(|k| F::storage_linked_map_final_key(k));
if let Some(prev_key) = prev_key {
// Retrieve previous element and update `next`
if let Some(mut res) = read_with_linkage::<K, V>(prev_key.as_ref()) {
res.1.next = linkage.next;
unhashed::put(prev_key.as_ref(), &res);
} else {
// TODO #3700: error should be handleable.
runtime_print!(
"ERROR: Corrupted state: linked map {:?}{:?}: \
previous value doesn't exist at {:?}",
F::module_prefix(), F::storage_prefix(), prev_key,
);
}
} else {
// we were first so let's update the head
write_head::<&K, K, F>(linkage.next.as_ref());
}
if let Some(next_key) = next_key {
// Update previous of next element
if let Some(mut res) = read_with_linkage::<K, V>(next_key.as_ref()) {
res.1.previous = linkage.previous;
unhashed::put(next_key.as_ref(), &res);
} else {
// TODO #3700: error should be handleable.
runtime_print!(
"ERROR: Corrupted state: linked map {:?}{:?}: \
next value doesn't exist at {:?}",
F::module_prefix(), F::storage_prefix(), next_key,
);
}
}
}
/// Read the contained data and its linkage.
pub(super) fn read_with_linkage<K, V>(key: &[u8]) -> Option<(V, Linkage<K>)>
where
K: Decode,
V: Decode,
{
unhashed::get(key)
}
/// Generate linkage for newly inserted element.
///
/// Takes care of updating head and previous head's pointer.
pub(super) fn new_head_linkage<KeyArg, K, V, F>(key: KeyArg) -> Linkage<K>
where
KeyArg: EncodeLike<K>,
K: FullCodec,
V: FullCodec,
F: KeyFormat,
{
if let Some(head) = read_head::<K, F>() {
// update previous head predecessor
{
let head_key = F::storage_linked_map_final_key(&head);
if let Some((data, linkage)) = read_with_linkage::<K, V>(head_key.as_ref()) {
let new_linkage = EncodeLikeLinkage::<_, _, K> {
previous: Some(Ref::from(&key)),
next: linkage.next.as_ref(),
phantom: Default::default(),
};
unhashed::put(head_key.as_ref(), &(data, new_linkage));
} else {
// TODO #3700: error should be handleable.
runtime_print!(
"ERROR: Corrupted state: linked map {:?}{:?}: \
head value doesn't exist at {:?}",
F::module_prefix(), F::storage_prefix(), head_key,
);
// Thus we consider we are first - update the head and produce empty linkage
write_head::<_, _, F>(Some(key));
return Linkage::default();
}
}
// update to current head
write_head::<_, _, F>(Some(key));
// return linkage with pointer to previous head
let mut linkage = Linkage::default();
linkage.next = Some(head);
linkage
} else {
// we are first - update the head and produce empty linkage
write_head::<_, _, F>(Some(key));
Linkage::default()
}
}
/// Read current head pointer.
pub(crate) fn read_head<K, F>() -> Option<K>
where
K: Decode,
F: KeyFormat,
{
unhashed::get(F::storage_linked_map_final_head_key().as_ref())
}
/// Overwrite current head pointer.
///
/// If `None` is given head is removed from storage.
pub(super) fn write_head<KeyArg, K, F>(head: Option<KeyArg>)
where
KeyArg: EncodeLike<K>,
K: FullCodec,
F: KeyFormat,
{
match head.as_ref() {
Some(head) => unhashed::put(F::storage_linked_map_final_head_key().as_ref(), head),
None => unhashed::kill(F::storage_linked_map_final_head_key().as_ref()),
}
}
impl<K, V, G> storage::StorageLinkedMap<K, V> for G
where
K: FullCodec,
V: FullCodec,
G: StorageLinkedMap<K, V>,
{
type Query = G::Query;
type Enumerator = Enumerator<K, V, G::KeyFormat>;
fn contains_key<KeyArg: EncodeLike<K>>(key: KeyArg) -> bool {
unhashed::exists(Self::storage_linked_map_final_key(key).as_ref())
}
fn get<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query {
let val = unhashed::get(Self::storage_linked_map_final_key(key).as_ref());
G::from_optional_value_to_query(val)
}
fn swap<KeyArg1: EncodeLike<K>, KeyArg2: EncodeLike<K>>(key1: KeyArg1, key2: KeyArg2) {
let final_key1 = Self::storage_linked_map_final_key(Ref::from(&key1));
let final_key2 = Self::storage_linked_map_final_key(Ref::from(&key2));
let full_value_1 = read_with_linkage::<K, V>(final_key1.as_ref());
let full_value_2 = read_with_linkage::<K, V>(final_key2.as_ref());
match (full_value_1, full_value_2) {
// Just keep linkage in order and only swap values.
(Some((value1, linkage1)), Some((value2, linkage2))) => {
unhashed::put(final_key1.as_ref(), &(value2, linkage1));
unhashed::put(final_key2.as_ref(), &(value1, linkage2));
}
// Remove key and insert the new one.
(Some((value, _linkage)), None) => {
Self::remove(key1);
let linkage = new_head_linkage::<_, _, V, G::KeyFormat>(key2);
unhashed::put(final_key2.as_ref(), &(value, linkage));
}
// Remove key and insert the new one.
(None, Some((value, _linkage))) => {
Self::remove(key2);
let linkage = new_head_linkage::<_, _, V, G::KeyFormat>(key1);
unhashed::put(final_key1.as_ref(), &(value, linkage));
}
// No-op.
(None, None) => (),
}
}
fn insert<KeyArg: EncodeLike<K>, ValArg: EncodeLike<V>>(key: KeyArg, val: ValArg) {
let final_key = Self::storage_linked_map_final_key(Ref::from(&key));
let linkage = match read_with_linkage::<_, V>(final_key.as_ref()) {
// overwrite but reuse existing linkage
Some((_data, linkage)) => linkage,
// create new linkage
None => new_head_linkage::<_, _, V, G::KeyFormat>(key),
};
unhashed::put(final_key.as_ref(), &(val, linkage))
}
fn remove<KeyArg: EncodeLike<K>>(key: KeyArg) {
G::take(key);
}
fn mutate<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R {
let final_key = Self::storage_linked_map_final_key(Ref::from(&key));
let (mut val, _linkage) = read_with_linkage::<K, V>(final_key.as_ref())
.map(|(data, linkage)| (G::from_optional_value_to_query(Some(data)), Some(linkage)))
.unwrap_or_else(|| (G::from_optional_value_to_query(None), None));
let ret = f(&mut val);
match G::from_query_to_optional_value(val) {
Some(ref val) => G::insert(key, val),
None => G::remove(key),
}
ret
}
fn take<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query {
let final_key = Self::storage_linked_map_final_key(key);
let full_value: Option<(V, Linkage<K>)> = unhashed::take(final_key.as_ref());
let value = full_value.map(|(data, linkage)| {
remove_linkage::<K, V, G::KeyFormat>(linkage);
data
});
G::from_optional_value_to_query(value)
}
fn enumerate() -> Self::Enumerator {
Enumerator::<_, _, G::KeyFormat> {
next: read_head::<_, G::KeyFormat>(),
_phantom: Default::default(),
}
}
fn head() -> Option<K> {
read_head::<_, G::KeyFormat>()
}
fn decode_len<KeyArg: EncodeLike<K>>(key: KeyArg) -> Result<usize, &'static str>
where V: codec::DecodeLength + Len
{
let key = Self::storage_linked_map_final_key(key);
if let Some(v) = unhashed::get_raw(key.as_ref()) {
<V as codec::DecodeLength>::len(&v).map_err(|e| e.what())
} else {
let len = G::from_query_to_optional_value(G::from_optional_value_to_query(None))
.map(|v| v.len())
.unwrap_or(0);
Ok(len)
}
}
/// The translation happens in-place, new keys are inserted at the same time as old keys are
/// removed, thus new keys must not collide with still remaining old keys.
fn translate<K2, V2, TK, TV>(translate_key: TK, translate_val: TV) -> Result<(), Option<K2>>
where K2: FullCodec + Clone, V2: Decode, TK: Fn(K2) -> K, TV: Fn(V2) -> V
{
let head_key = read_head::<K2, G::KeyFormat>().ok_or(None)?;
let mut last_key = None;
let mut current_key = head_key.clone();
write_head::<&K, K, G::KeyFormat>(Some(&translate_key(head_key)));
let translate_linkage = |old: Linkage<K2>| -> Linkage<K> {
Linkage {
previous: old.previous.map(&translate_key),
next: old.next.map(&translate_key),
}
};
loop {
let old_raw_key = G::KeyFormat::storage_linked_map_final_key(&current_key);
let x = unhashed::take(old_raw_key.as_ref());
let (val, linkage): (V2, Linkage<K2>) = match x {
Some(v) => v,
None => {
// we failed to read value and linkage. Update the last key's linkage
// to end the map early, since it's impossible to iterate further.
if let Some(last_key) = last_key {
let last_raw_key = G::storage_linked_map_final_key(&last_key);
if let Some((val, mut linkage))
= read_with_linkage::<K, V>(last_raw_key.as_ref())
{
// defensive: should always happen, since it was just written
// in the last iteration of the loop.
linkage.next = None;
unhashed::put(last_raw_key.as_ref(), &(&val, &linkage));
}
}
return Err(Some(current_key));
}
};
let next = linkage.next.clone();
let val = translate_val(val);
let linkage = translate_linkage(linkage);
// and write in the value and linkage under the new key.
let new_key = translate_key(current_key.clone());
let new_raw_key = G::storage_linked_map_final_key(&new_key);
unhashed::put(new_raw_key.as_ref(), &(&val, &linkage));
match next {
None => break,
Some(next) => {
last_key = Some(new_key);
current_key = next
},
}
}
Ok(())
}
}
@@ -17,8 +17,9 @@
#[cfg(not(feature = "std"))]
use sp_std::prelude::*;
use sp_std::borrow::Borrow;
use codec::{FullCodec, FullEncode, Encode, EncodeLike, Ref, EncodeAppend};
use crate::{storage::{self, unhashed}, hash::{StorageHasher, Twox128}, traits::Len};
use codec::{FullCodec, FullEncode, Decode, Encode, EncodeLike, Ref, EncodeAppend};
use crate::{storage::{self, unhashed}, traits::Len};
use crate::hash::{StorageHasher, Twox128, ReversibleStorageHasher};
/// Generator for `StorageMap` used by `decl_storage`.
///
@@ -44,6 +45,22 @@ pub trait StorageMap<K: FullEncode, V: FullCodec> {
/// Storage prefix. Used for generating final key.
fn storage_prefix() -> &'static [u8];
/// The full prefix; just the hash of `module_prefix` concatenated to the hash of
/// `storage_prefix`.
fn prefix_hash() -> Vec<u8> {
let module_prefix_hashed = Twox128::hash(Self::module_prefix());
let storage_prefix_hashed = Twox128::hash(Self::storage_prefix());
let mut result = Vec::with_capacity(
module_prefix_hashed.len() + storage_prefix_hashed.len()
);
result.extend_from_slice(&module_prefix_hashed[..]);
result.extend_from_slice(&storage_prefix_hashed[..]);
result
}
/// Convert an optional value retrieved from storage to the type queried.
fn from_optional_value_to_query(v: Option<V>) -> Self::Query;
@@ -51,8 +68,7 @@ pub trait StorageMap<K: FullEncode, V: FullCodec> {
fn from_query_to_optional_value(v: Self::Query) -> Option<V>;
/// Generate the full key used in top storage.
fn storage_map_final_key<KeyArg>(key: KeyArg) -> Vec<u8>
where
fn storage_map_final_key<KeyArg>(key: KeyArg) -> Vec<u8> where
KeyArg: EncodeLike<K>,
{
let module_prefix_hashed = Twox128::hash(Self::module_prefix());
@@ -71,6 +87,107 @@ pub trait StorageMap<K: FullEncode, V: FullCodec> {
}
}
/// Utility to iterate through items in a storage map.
pub struct StorageMapIterator<K, V, Hasher> {
prefix: Vec<u8>,
previous_key: Vec<u8>,
drain: bool,
_phantom: ::sp_std::marker::PhantomData<(K, V, Hasher)>,
}
impl<
K: Decode + Sized,
V: Decode + Sized,
Hasher: ReversibleStorageHasher
> Iterator for StorageMapIterator<K, V, Hasher> {
type Item = (K, V);
fn next(&mut self) -> Option<(K, V)> {
loop {
let maybe_next = sp_io::storage::next_key(&self.previous_key)
.filter(|n| n.starts_with(&self.prefix));
break match maybe_next {
Some(next) => {
self.previous_key = next;
match unhashed::get::<V>(&self.previous_key) {
Some(value) => {
if self.drain {
unhashed::kill(&self.previous_key)
}
let mut key_material = Hasher::reverse(&self.previous_key[self.prefix.len()..]);
match K::decode(&mut key_material) {
Ok(key) => Some((key, value)),
Err(_) => continue,
}
}
None => continue,
}
}
None => None,
}
}
}
}
impl<
K: FullCodec,
V: FullCodec,
G: StorageMap<K, V>,
> storage::IterableStorageMap<K, V> for G where
G::Hasher: ReversibleStorageHasher
{
type Iterator = StorageMapIterator<K, V, G::Hasher>;
/// Enumerate all elements in the map.
fn iter() -> Self::Iterator {
let prefix = G::prefix_hash();
Self::Iterator {
prefix: prefix.clone(),
previous_key: prefix,
drain: false,
_phantom: Default::default(),
}
}
/// Enumerate all elements in the map.
fn drain() -> Self::Iterator {
let prefix = G::prefix_hash();
Self::Iterator {
prefix: prefix.clone(),
previous_key: prefix,
drain: true,
_phantom: Default::default(),
}
}
fn translate<O: Decode, F: Fn(K, O) -> Option<V>>(f: F) {
let prefix = G::prefix_hash();
let mut previous_key = prefix.clone();
loop {
match sp_io::storage::next_key(&previous_key).filter(|n| n.starts_with(&prefix)) {
Some(next) => {
previous_key = next;
let maybe_value = unhashed::get::<O>(&previous_key);
match maybe_value {
Some(value) => {
let mut key_material = G::Hasher::reverse(&previous_key[prefix.len()..]);
match K::decode(&mut key_material) {
Ok(key) => match f(key, value) {
Some(new) => unhashed::put::<V>(&previous_key, &new),
None => unhashed::kill(&previous_key),
},
Err(_) => continue,
}
}
None => continue,
}
}
None => return,
}
}
}
}
impl<K: FullEncode, V: FullCodec, G: StorageMap<K, V>> storage::StorageMap<K, V> for G {
type Query = G::Query;
@@ -228,4 +345,26 @@ impl<K: FullEncode, V: FullCodec, G: StorageMap<K, V>> storage::StorageMap<K, V>
Ok(len)
}
}
fn migrate_key<OldHasher: StorageHasher, KeyArg: EncodeLike<K>>(key: KeyArg) -> Option<V> {
let old_key = {
let module_prefix_hashed = Twox128::hash(Self::module_prefix());
let storage_prefix_hashed = Twox128::hash(Self::storage_prefix());
let key_hashed = key.borrow().using_encoded(OldHasher::hash);
let mut final_key = Vec::with_capacity(
module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.as_ref().len()
);
final_key.extend_from_slice(&module_prefix_hashed[..]);
final_key.extend_from_slice(&storage_prefix_hashed[..]);
final_key.extend_from_slice(key_hashed.as_ref());
final_key
};
unhashed::take(old_key.as_ref()).map(|value| {
unhashed::put(Self::storage_map_final_key(key).as_ref(), &value);
value
})
}
}
@@ -23,23 +23,20 @@
//!
//! This is internal api and is subject to change.
mod linked_map;
mod map;
mod double_map;
mod value;
pub use linked_map::{StorageLinkedMap, Enumerator, Linkage, KeyFormat as LinkedMapKeyFormat};
pub use map::StorageMap;
pub use double_map::StorageDoubleMap;
pub use value::StorageValue;
#[cfg(test)]
#[allow(dead_code)]
mod tests {
use sp_io::TestExternalities;
use codec::{Encode, Decode};
use crate::storage::{unhashed, generator::{StorageValue, StorageLinkedMap}};
use codec::Encode;
use crate::storage::{unhashed, generator::StorageValue, IterableStorageMap};
struct Runtime {}
pub trait Trait {
@@ -56,16 +53,10 @@ mod tests {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
}
#[derive(Encode, Decode, Clone, Debug, Eq, PartialEq)]
struct NumberNumber {
a: u32,
b: u32,
}
crate::decl_storage! {
trait Store for Module<T: Trait> as Runtime {
Value get(fn value) config(): (u64, u64);
NumberMap: linked_map hasher(blake2_256) NumberNumber => u64;
NumberMap: map hasher(identity) u32 => u64;
}
}
@@ -89,41 +80,25 @@ mod tests {
}
#[test]
fn linked_map_translate_works() {
use super::linked_map::{self, Enumerator, KeyFormat};
type Format = <NumberMap as StorageLinkedMap<NumberNumber, u64>>::KeyFormat;
fn map_translate_works() {
let t = GenesisConfig::default().build_storage().unwrap();
TestExternalities::new(t).execute_with(|| {
// start with a map of u32 -> u32.
for i in 0u32..100u32 {
let final_key = <Format as KeyFormat>::storage_linked_map_final_key(&i);
let linkage = linked_map::new_head_linkage::<_, u32, u32, Format>(&i);
unhashed::put(final_key.as_ref(), &(&i, linkage));
unhashed::put(&NumberMap::hashed_key_for(&i), &(i as u64));
}
let head = linked_map::read_head::<u32, Format>().unwrap();
assert_eq!(
Enumerator::<u32, u32, Format>::from_head(head).collect::<Vec<_>>(),
(0..100).rev().map(|x| (x, x)).collect::<Vec<_>>(),
NumberMap::iter().collect::<Vec<_>>(),
(0..100).map(|x| (x as u32, x as u64)).collect::<Vec<_>>(),
);
// do translation.
NumberMap::translate(
|k: u32| NumberNumber { a: k, b: k },
|v: u32| (v as u64) << 32 | v as u64,
).unwrap();
NumberMap::translate(|k: u32, v: u64| if k % 2 == 0 { Some((k as u64) << 32 | v) } else { None });
assert!(linked_map::read_head::<NumberNumber, Format>().is_some());
assert_eq!(
NumberMap::enumerate().collect::<Vec<_>>(),
(0..100u32).rev().map(|x| (
NumberNumber { a: x, b: x },
(x as u64) << 32 | x as u64,
)).collect::<Vec<_>>(),
NumberMap::iter().collect::<Vec<_>>(),
(0..50u32).map(|x| x * 2).map(|x| (x, (x as u64) << 32 | x as u64)).collect::<Vec<_>>(),
);
})
}
+63 -70
View File
@@ -202,78 +202,60 @@ pub trait StorageMap<K: FullEncode, V: FullCodec> {
/// function for this purpose.
fn decode_len<KeyArg: EncodeLike<K>>(key: KeyArg) -> Result<usize, &'static str>
where V: codec::DecodeLength + Len;
/// Migrate an item with the given `key` from a defunct `OldHasher` to the current hasher.
///
/// If the key doesn't exist, then it's a no-op. If it does, then it returns its value.
fn migrate_key<OldHasher: StorageHasher, KeyArg: EncodeLike<K>>(key: KeyArg) -> Option<V>;
/// Migrate an item with the given `key` from a `blake2_256` hasher to the current hasher.
///
/// If the key doesn't exist, then it's a no-op. If it does, then it returns its value.
fn migrate_key_from_blake<KeyArg: EncodeLike<K>>(key: KeyArg) -> Option<V> {
Self::migrate_key::<crate::hash::Blake2_256, KeyArg>(key)
}
}
/// A strongly-typed linked map in storage.
///
/// Similar to `StorageMap` but allows to enumerate other elements and doesn't implement append.
///
/// Details on implementation can be found at
/// [`generator::StorageLinkedMap`]
pub trait StorageLinkedMap<K: FullCodec, V: FullCodec> {
/// The type that get/take return.
type Query;
/// A strongly-typed map in storage whose keys and values can be iterated over.
pub trait IterableStorageMap<K: FullEncode, V: FullCodec>: StorageMap<K, V> {
/// The type that iterates over all `(key, value)`.
type Enumerator: Iterator<Item = (K, V)>;
type Iterator: Iterator<Item = (K, V)>;
/// Does the value (explicitly) exist in storage?
fn contains_key<KeyArg: EncodeLike<K>>(key: KeyArg) -> bool;
/// Enumerate all elements in the map in no particular order. If you alter the map while doing
/// this, you'll get undefined results.
fn iter() -> Self::Iterator;
/// Load the value associated with the given key from the map.
fn get<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query;
/// Remove all elements from the map and iterate through them in no particular order. If you
/// add elements to the map while doing this, you'll get undefined results.
fn drain() -> Self::Iterator;
/// Swap the values of two keys.
fn swap<KeyArg1: EncodeLike<K>, KeyArg2: EncodeLike<K>>(key1: KeyArg1, key2: KeyArg2);
/// Translate the values of all elements by a function `f`, in the map in no particular order.
/// By returning `None` from `f` for an element, you'll remove it from the map.
fn translate<O: Decode, F: Fn(K, O) -> Option<V>>(f: F);
}
/// Store a value to be associated with the given key from the map.
fn insert<KeyArg: EncodeLike<K>, ValArg: EncodeLike<V>>(key: KeyArg, val: ValArg);
/// A strongly-typed double map in storage whose secondary keys and values can be iterated over.
pub trait IterableStorageDoubleMap<
K1: FullCodec,
K2: FullCodec,
V: FullCodec
>: StorageDoubleMap<K1, K2, V> {
/// The type that iterates over all `(key, value)`.
type Iterator: Iterator<Item = (K2, V)>;
/// Remove the value under a key.
fn remove<KeyArg: EncodeLike<K>>(key: KeyArg);
/// Enumerate all elements in the map with first key `k1` in no particular order. If you add or
/// remove values whose first key is `k1` to the map while doing this, you'll get undefined
/// results.
fn iter(k1: impl EncodeLike<K1>) -> Self::Iterator;
/// Mutate the value under a key.
fn mutate<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R;
/// Remove all elements from the map with first key `k1` and iterate through them in no
/// particular order. If you add elements with first key `k1` to the map while doing this,
/// you'll get undefined results.
fn drain(k1: impl EncodeLike<K1>) -> Self::Iterator;
/// Take the value under a key.
fn take<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query;
/// Return current head element.
fn head() -> Option<K>;
/// Enumerate all elements in the map.
fn enumerate() -> Self::Enumerator;
/// Read the length of the value in a fast way, without decoding the entire value.
///
/// `T` is required to implement `Codec::DecodeLength`.
///
/// Note that `0` is returned as the default value if no encoded value exists at the given key.
/// Therefore, this function cannot be used as a sign of _existence_. use the `::contains_key()`
/// function for this purpose.
fn decode_len<KeyArg: EncodeLike<K>>(key: KeyArg) -> Result<usize, &'static str>
where V: codec::DecodeLength + Len;
/// Translate the keys and values from some previous `(K2, V2)` to the current type.
///
/// `TK` translates keys from the old type, and `TV` translates values.
///
/// Returns `Err` if the map could not be interpreted as the old type, and Ok if it could.
/// The `Err` contains the first key which could not be migrated, or `None` if the
/// head of the list could not be read.
///
/// # Warning
///
/// This function must be used with care, before being updated the storage still contains the
/// old type, thus other calls (such as `get`) will fail at decoding it.
///
/// # Usage
///
/// This would typically be called inside the module implementation of on_runtime_upgrade, while
/// ensuring **no usage of this storage are made before the call to `on_runtime_upgrade`**. (More
/// precisely prior initialized modules doesn't make use of this storage).
fn translate<K2, V2, TK, TV>(translate_key: TK, translate_val: TV) -> Result<(), Option<K2>>
where K2: FullCodec + Clone, V2: Decode, TK: Fn(K2) -> K, TV: Fn(V2) -> V;
/// Translate the values of all elements by a function `f`, in the map in no particular order.
/// By returning `None` from `f` for an element, you'll remove it from the map.
fn translate<O: Decode, F: Fn(O) -> Option<V>>(f: F);
}
/// An implementation of a map with a two keys.
@@ -377,6 +359,17 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
V: codec::DecodeLength + Len;
/// Migrate an item with the given `key1` and `key2` from defunct `OldHasher1` and
/// `OldHasher2` to the current hashers.
///
/// If the key doesn't exist, then it's a no-op. If it does, then it returns its value.
fn migrate_keys<
OldHasher1: StorageHasher,
OldHasher2: StorageHasher,
KeyArg1: EncodeLike<K1>,
KeyArg2: EncodeLike<K2>,
>(key1: KeyArg1, key2: KeyArg2) -> Option<V>;
}
/// Iterator for prefixed map.
@@ -440,7 +433,7 @@ pub trait StoragePrefixedMap<Value: FullCodec> {
}
/// Iter over all value of the storage.
fn iter() -> PrefixIterator<Value> {
fn iter_values() -> PrefixIterator<Value> {
let prefix = Self::final_prefix();
PrefixIterator {
prefix: prefix.to_vec(),
@@ -535,26 +528,26 @@ mod test {
assert_eq!(MyStorage::final_prefix().to_vec(), k);
// test iteration
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![]);
assert_eq!(MyStorage::iter_values().collect::<Vec<_>>(), vec![]);
unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u64);
unhashed::put(&[&k[..], &vec![1, 1][..]].concat(), &2u64);
unhashed::put(&[&k[..], &vec![8][..]].concat(), &3u64);
unhashed::put(&[&k[..], &vec![10][..]].concat(), &4u64);
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![1, 2, 3, 4]);
assert_eq!(MyStorage::iter_values().collect::<Vec<_>>(), vec![1, 2, 3, 4]);
// test removal
MyStorage::remove_all();
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![]);
assert_eq!(MyStorage::iter_values().collect::<Vec<_>>(), vec![]);
// test migration
unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u32);
unhashed::put(&[&k[..], &vec![8][..]].concat(), &2u32);
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![]);
assert_eq!(MyStorage::iter_values().collect::<Vec<_>>(), vec![]);
MyStorage::translate_values(|v: u32| v as u64).unwrap();
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![1, 2]);
assert_eq!(MyStorage::iter_values().collect::<Vec<_>>(), vec![1, 2]);
MyStorage::remove_all();
// test migration 2
@@ -564,9 +557,9 @@ mod test {
unhashed::put(&[&k[..], &vec![10][..]].concat(), &4u32);
// (contains some value that successfully decoded to u64)
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![1, 2, 3]);
assert_eq!(MyStorage::iter_values().collect::<Vec<_>>(), vec![1, 2, 3]);
assert_eq!(MyStorage::translate_values(|v: u128| v as u64), Err(2));
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![1, 3]);
assert_eq!(MyStorage::iter_values().collect::<Vec<_>>(), vec![1, 3]);
MyStorage::remove_all();
// test that other values are not modified.
+7 -1
View File
@@ -26,10 +26,16 @@ use sp_runtime::{
ConsensusEngineId, DispatchResult, DispatchError,
traits::{MaybeSerializeDeserialize, AtLeast32Bit, Saturating, TrailingZeroInput},
};
use crate::dispatch::Parameter;
use crate::storage::StorageMap;
/// Migrate a given account.
#[impl_trait_for_tuples::impl_for_tuples(30)]
pub trait MigrateAccount<A> {
/// Migrate the `account`.
fn migrate_account(account: &A);
}
/// An abstraction of a value stored within storage, but possibly as part of a larger composite
/// item.
pub trait StoredMap<K, T> {
@@ -37,10 +37,10 @@ mod tests {
// non-getters: pub / $default
/// Hello, this is doc!
U32 : Option<u32>;
pub PUBU32 : Option<u32>;
U32MYDEF : Option<u32>;
pub PUBU32MYDEF : Option<u32>;
U32: Option<u32>;
pub PUBU32: Option<u32>;
U32MYDEF: Option<u32>;
pub PUBU32MYDEF: Option<u32>;
// getters: pub / $default
// we need at least one type which uses T, otherwise GenesisConfig will complain.
@@ -59,31 +59,23 @@ mod tests {
GetOptU32WithBuilderNone get(fn opt_u32_with_builder_none) build(|_| None): Option<u32>;
// map non-getters: pub / $default
MAPU32 : map hasher(blake2_256) u32 => Option<String>;
pub PUBMAPU32 : map hasher(blake2_256) u32 => Option<String>;
MAPU32MYDEF : map hasher(blake2_256) u32 => Option<String>;
pub PUBMAPU32MYDEF : map hasher(blake2_256) u32 => Option<String>;
MAPU32: map hasher(blake2_128_concat) u32 => Option<String>;
pub PUBMAPU32: map hasher(blake2_128_concat) u32 => Option<String>;
MAPU32MYDEF: map hasher(blake2_128_concat) u32 => Option<String>;
pub PUBMAPU32MYDEF: map hasher(blake2_128_concat) u32 => Option<String>;
// map getters: pub / $default
GETMAPU32 get(fn map_u32_getter): map hasher(blake2_256) u32 => String;
pub PUBGETMAPU32 get(fn pub_map_u32_getter): map hasher(blake2_256) u32 => String;
GETMAPU32 get(fn map_u32_getter): map hasher(blake2_128_concat) u32 => String;
pub PUBGETMAPU32 get(fn pub_map_u32_getter): map hasher(blake2_128_concat) u32 => String;
GETMAPU32MYDEF get(fn map_u32_getter_mydef):
map hasher(blake2_256) u32 => String = "map".into();
map hasher(blake2_128_concat) u32 => String = "map".into();
pub PUBGETMAPU32MYDEF get(fn pub_map_u32_getter_mydef):
map hasher(blake2_256) u32 => String = "pubmap".into();
// linked map
LINKEDMAPU32 : linked_map hasher(blake2_256) u32 => Option<String>;
pub PUBLINKEDMAPU32MYDEF : linked_map hasher(blake2_256) u32 => Option<String>;
GETLINKEDMAPU32 get(fn linked_map_u32_getter):
linked_map hasher(blake2_256) u32 => String;
pub PUBGETLINKEDMAPU32MYDEF get(fn pub_linked_map_u32_getter_mydef):
linked_map hasher(blake2_256) u32 => String = "pubmap".into();
map hasher(blake2_128_concat) u32 => String = "pubmap".into();
COMPLEXTYPE1: ::std::vec::Vec<<T as Trait>::Origin>;
COMPLEXTYPE2: (Vec<Vec<(u16,Box<( )>)>>, u32);
COMPLEXTYPE3: [u32;25];
COMPLEXTYPE2: (Vec<Vec<(u16, Box<()>)>>, u32);
COMPLEXTYPE3: [u32; 25];
}
add_extra_genesis {
build(|_| {});
@@ -249,10 +241,10 @@ mod tests {
name: DecodeDifferent::Encode("MAPU32"),
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructMAPU32(PhantomData::<TraitImpl>))
@@ -263,10 +255,10 @@ mod tests {
name: DecodeDifferent::Encode("PUBMAPU32"),
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructPUBMAPU32(PhantomData::<TraitImpl>))
@@ -277,10 +269,10 @@ mod tests {
name: DecodeDifferent::Encode("MAPU32MYDEF"),
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructMAPU32MYDEF(PhantomData::<TraitImpl>))
@@ -291,10 +283,10 @@ mod tests {
name: DecodeDifferent::Encode("PUBMAPU32MYDEF"),
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructPUBMAPU32MYDEF(PhantomData::<TraitImpl>))
@@ -305,10 +297,10 @@ mod tests {
name: DecodeDifferent::Encode("GETMAPU32"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructGETMAPU32(PhantomData::<TraitImpl>))
@@ -319,10 +311,10 @@ mod tests {
name: DecodeDifferent::Encode("PUBGETMAPU32"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructPUBGETMAPU32(PhantomData::<TraitImpl>))
@@ -333,10 +325,10 @@ mod tests {
name: DecodeDifferent::Encode("GETMAPU32MYDEF"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructGETMAPU32MYDEF(PhantomData::<TraitImpl>))
@@ -347,72 +339,16 @@ mod tests {
name: DecodeDifferent::Encode("PUBGETMAPU32MYDEF"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Blake2_128Concat,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructPUBGETMAPU32MYDEF(PhantomData::<TraitImpl>))
),
documentation: DecodeDifferent::Encode(&[]),
},
StorageEntryMetadata {
name: DecodeDifferent::Encode("LINKEDMAPU32"),
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: true,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructLINKEDMAPU32(PhantomData::<TraitImpl>))
),
documentation: DecodeDifferent::Encode(&[]),
},
StorageEntryMetadata {
name: DecodeDifferent::Encode("PUBLINKEDMAPU32MYDEF"),
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: true,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructPUBLINKEDMAPU32MYDEF(PhantomData::<TraitImpl>))
),
documentation: DecodeDifferent::Encode(&[]),
},
StorageEntryMetadata {
name: DecodeDifferent::Encode("GETLINKEDMAPU32"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: true,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructGETLINKEDMAPU32(PhantomData::<TraitImpl>))
),
documentation: DecodeDifferent::Encode(&[]),
},
StorageEntryMetadata {
name: DecodeDifferent::Encode("PUBGETLINKEDMAPU32MYDEF"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: true,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(&__GetByteStructPUBGETLINKEDMAPU32MYDEF(PhantomData::<TraitImpl>))
),
documentation: DecodeDifferent::Encode(&[]),
},
StorageEntryMetadata {
name: DecodeDifferent::Encode("COMPLEXTYPE1"),
modifier: StorageEntryModifier::Default,
@@ -562,17 +498,13 @@ mod test_append_and_len {
JustVecWithDefault: Vec<u32> = vec![6, 9];
OptionVec: Option<Vec<u32>>;
MapVec: map hasher(blake2_256) u32 => Vec<u32>;
MapVecWithDefault: map hasher(blake2_256) u32 => Vec<u32> = vec![6, 9];
OptionMapVec: map hasher(blake2_256) u32 => Option<Vec<u32>>;
MapVec: map hasher(blake2_128_concat) u32 => Vec<u32>;
MapVecWithDefault: map hasher(blake2_128_concat) u32 => Vec<u32> = vec![6, 9];
OptionMapVec: map hasher(blake2_128_concat) u32 => Option<Vec<u32>>;
DoubleMapVec: double_map hasher(blake2_256) u32, hasher(blake2_256) u32 => Vec<u32>;
DoubleMapVecWithDefault: double_map hasher(blake2_256) u32, hasher(blake2_256) u32 => Vec<u32> = vec![6, 9];
OptionDoubleMapVec: double_map hasher(blake2_256) u32, hasher(blake2_256) u32 => Option<Vec<u32>>;
LinkedMapVec: linked_map hasher(blake2_256) u32 => Vec<u32>;
LinkedMapVecWithDefault: linked_map hasher(blake2_256) u32 => Vec<u32> = vec![6, 9];
OptionLinkedMapVec: linked_map hasher(blake2_256) u32 => Option<Vec<u32>>;
DoubleMapVec: double_map hasher(blake2_128_concat) u32, hasher(blake2_128_concat) u32 => Vec<u32>;
DoubleMapVecWithDefault: double_map hasher(blake2_128_concat) u32, hasher(blake2_128_concat) u32 => Vec<u32> = vec![6, 9];
OptionDoubleMapVec: double_map hasher(blake2_128_concat) u32, hasher(blake2_128_concat) u32 => Option<Vec<u32>>;
}
}
@@ -644,13 +576,11 @@ mod test_append_and_len {
JustVec::put(&vec![1, 2, 3, 4]);
OptionVec::put(&vec![1, 2, 3, 4, 5]);
MapVec::insert(1, &vec![1, 2, 3, 4, 5, 6]);
LinkedMapVec::insert(2, &vec![1, 2, 3]);
DoubleMapVec::insert(0, 1, &vec![1, 2]);
assert_eq!(JustVec::decode_len().unwrap(), 4);
assert_eq!(OptionVec::decode_len().unwrap(), 5);
assert_eq!(MapVec::decode_len(1).unwrap(), 6);
assert_eq!(LinkedMapVec::decode_len(2).unwrap(), 3);
assert_eq!(DoubleMapVec::decode_len(0, 1).unwrap(), 2);
});
}
@@ -678,16 +608,6 @@ mod test_append_and_len {
assert_eq!(OptionMapVec::get(0), None);
assert_eq!(OptionMapVec::decode_len(0), Ok(0));
// linked map
assert_eq!(LinkedMapVec::get(0), vec![]);
assert_eq!(LinkedMapVec::decode_len(0), Ok(0));
assert_eq!(LinkedMapVecWithDefault::get(0), vec![6, 9]);
assert_eq!(LinkedMapVecWithDefault::decode_len(0), Ok(2));
assert_eq!(OptionLinkedMapVec::get(0), None);
assert_eq!(OptionLinkedMapVec::decode_len(0), Ok(0));
// Double map
assert_eq!(DoubleMapVec::get(0, 0), vec![]);
assert_eq!(DoubleMapVec::decode_len(0, 1), Ok(0));
@@ -16,8 +16,8 @@
use frame_support::storage::unhashed;
use codec::Encode;
use frame_support::{StorageDoubleMap, StorageLinkedMap, StorageMap, StorageValue, StoragePrefixedMap};
use sp_io::{TestExternalities, hashing::{twox_128, blake2_128, blake2_256}};
use frame_support::{StorageDoubleMap, StorageMap, StorageValue, StoragePrefixedMap};
use sp_io::{TestExternalities, hashing::{twox_64, twox_128, blake2_128}};
mod no_instance {
use codec::{Encode, Decode, EncodeLike};
@@ -35,18 +35,15 @@ mod no_instance {
trait Store for Module<T: Trait> as FinalKeysNone {
pub Value config(value): u32;
pub Map: map hasher(blake2_256) u32 => u32;
pub Map2: map hasher(twox_128) u32 => u32;
pub Map: map hasher(blake2_128_concat) u32 => u32;
pub Map2: map hasher(twox_64_concat) u32 => u32;
pub LinkedMap: linked_map hasher(blake2_256) u32 => u32;
pub LinkedMap2: linked_map hasher(twox_128) u32 => u32;
pub DoubleMap: double_map hasher(blake2_256) u32, hasher(blake2_256) u32 => u32;
pub DoubleMap2: double_map hasher(twox_128) u32, hasher(blake2_128) u32 => u32;
pub DoubleMap: double_map hasher(blake2_128_concat) u32, hasher(blake2_128_concat) u32 => u32;
pub DoubleMap2: double_map hasher(twox_64_concat) u32, hasher(twox_64_concat) u32 => u32;
pub TestGenericValue get(fn test_generic_value) config(): Option<T::BlockNumber>;
pub TestGenericDoubleMap get(fn foo2) config(test_generic_double_map):
double_map hasher(blake2_256) u32, hasher(blake2_256) T::BlockNumber => Option<u32>;
double_map hasher(blake2_128_concat) u32, hasher(blake2_128_concat) T::BlockNumber => Option<u32>;
}
}
}
@@ -65,18 +62,15 @@ mod instance {
{
pub Value config(value): u32;
pub Map: map hasher(blake2_256) u32 => u32;
pub Map2: map hasher(twox_128) u32 => u32;
pub Map: map hasher(blake2_128_concat) u32 => u32;
pub Map2: map hasher(twox_64_concat) u32 => u32;
pub LinkedMap: linked_map hasher(blake2_256) u32 => u32;
pub LinkedMap2: linked_map hasher(twox_128) u32 => u32;
pub DoubleMap: double_map hasher(blake2_256) u32, hasher(blake2_256) u32 => u32;
pub DoubleMap2: double_map hasher(twox_128) u32, hasher(blake2_128) u32 => u32;
pub DoubleMap: double_map hasher(blake2_128_concat) u32, hasher(blake2_128_concat) u32 => u32;
pub DoubleMap2: double_map hasher(twox_64_concat) u32, hasher(twox_64_concat) u32 => u32;
pub TestGenericValue get(fn test_generic_value) config(): Option<T::BlockNumber>;
pub TestGenericDoubleMap get(fn foo2) config(test_generic_double_map):
double_map hasher(blake2_256) u32, hasher(blake2_256) T::BlockNumber => Option<u32>;
double_map hasher(blake2_128_concat) u32, hasher(blake2_128_concat) T::BlockNumber => Option<u32>;
}
add_extra_genesis {
// See `decl_storage` limitation.
@@ -85,6 +79,18 @@ mod instance {
}
}
fn twox_64_concat(d: &[u8]) -> Vec<u8> {
let mut v = twox_64(d).to_vec();
v.extend_from_slice(d);
v
}
fn blake2_128_concat(d: &[u8]) -> Vec<u8> {
let mut v = blake2_128(d).to_vec();
v.extend_from_slice(d);
v
}
#[test]
fn final_keys_no_instance() {
TestExternalities::default().execute_with(|| {
@@ -94,41 +100,27 @@ fn final_keys_no_instance() {
no_instance::Map::insert(1, 2);
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"Map")].concat();
k.extend(1u32.using_encoded(blake2_256).to_vec());
k.extend(1u32.using_encoded(blake2_128_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
assert_eq!(&k[..32], &<no_instance::Map>::final_prefix());
no_instance::Map2::insert(1, 2);
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"Map2")].concat();
k.extend(1u32.using_encoded(twox_128).to_vec());
k.extend(1u32.using_encoded(twox_64_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
assert_eq!(&k[..32], &<no_instance::Map2>::final_prefix());
let head = [twox_128(b"FinalKeysNone"), twox_128(b"HeadOfLinkedMap")].concat();
assert_eq!(unhashed::get::<u32>(&head), None);
no_instance::LinkedMap::insert(1, 2);
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"LinkedMap")].concat();
k.extend(1u32.using_encoded(blake2_256).to_vec());
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
assert_eq!(unhashed::get::<u32>(&head), Some(1u32));
no_instance::LinkedMap2::insert(1, 2);
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"LinkedMap2")].concat();
k.extend(1u32.using_encoded(twox_128).to_vec());
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
no_instance::DoubleMap::insert(&1, &2, &3);
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"DoubleMap")].concat();
k.extend(1u32.using_encoded(blake2_256).to_vec());
k.extend(2u32.using_encoded(blake2_256).to_vec());
k.extend(1u32.using_encoded(blake2_128_concat));
k.extend(2u32.using_encoded(blake2_128_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
assert_eq!(&k[..32], &<no_instance::DoubleMap>::final_prefix());
no_instance::DoubleMap2::insert(&1, &2, &3);
let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"DoubleMap2")].concat();
k.extend(1u32.using_encoded(twox_128).to_vec());
k.extend(2u32.using_encoded(blake2_128).to_vec());
k.extend(1u32.using_encoded(twox_64_concat));
k.extend(2u32.using_encoded(twox_64_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
assert_eq!(&k[..32], &<no_instance::DoubleMap2>::final_prefix());
});
@@ -143,41 +135,27 @@ fn final_keys_default_instance() {
<instance::Map<instance::DefaultInstance>>::insert(1, 2);
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"Map")].concat();
k.extend(1u32.using_encoded(blake2_256).to_vec());
k.extend(1u32.using_encoded(blake2_128_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
assert_eq!(&k[..32], &<instance::Map<instance::DefaultInstance>>::final_prefix());
<instance::Map2<instance::DefaultInstance>>::insert(1, 2);
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"Map2")].concat();
k.extend(1u32.using_encoded(twox_128).to_vec());
k.extend(1u32.using_encoded(twox_64_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
assert_eq!(&k[..32], &<instance::Map2<instance::DefaultInstance>>::final_prefix());
let head = [twox_128(b"FinalKeysSome"), twox_128(b"HeadOfLinkedMap")].concat();
assert_eq!(unhashed::get::<u32>(&head), None);
<instance::LinkedMap<instance::DefaultInstance>>::insert(1, 2);
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"LinkedMap")].concat();
k.extend(1u32.using_encoded(blake2_256).to_vec());
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
assert_eq!(unhashed::get::<u32>(&head), Some(1u32));
<instance::LinkedMap2<instance::DefaultInstance>>::insert(1, 2);
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"LinkedMap2")].concat();
k.extend(1u32.using_encoded(twox_128).to_vec());
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
<instance::DoubleMap<instance::DefaultInstance>>::insert(&1, &2, &3);
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"DoubleMap")].concat();
k.extend(1u32.using_encoded(blake2_256).to_vec());
k.extend(2u32.using_encoded(blake2_256).to_vec());
k.extend(1u32.using_encoded(blake2_128_concat));
k.extend(2u32.using_encoded(blake2_128_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
assert_eq!(&k[..32], &<instance::DoubleMap<instance::DefaultInstance>>::final_prefix());
<instance::DoubleMap2<instance::DefaultInstance>>::insert(&1, &2, &3);
let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"DoubleMap2")].concat();
k.extend(1u32.using_encoded(twox_128).to_vec());
k.extend(2u32.using_encoded(blake2_128).to_vec());
k.extend(1u32.using_encoded(twox_64_concat));
k.extend(2u32.using_encoded(twox_64_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
assert_eq!(&k[..32], &<instance::DoubleMap2<instance::DefaultInstance>>::final_prefix());
});
@@ -192,41 +170,27 @@ fn final_keys_instance_2() {
<instance::Map<instance::Instance2>>::insert(1, 2);
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"Map")].concat();
k.extend(1u32.using_encoded(blake2_256).to_vec());
k.extend(1u32.using_encoded(blake2_128_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
assert_eq!(&k[..32], &<instance::Map<instance::Instance2>>::final_prefix());
<instance::Map2<instance::Instance2>>::insert(1, 2);
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"Map2")].concat();
k.extend(1u32.using_encoded(twox_128).to_vec());
k.extend(1u32.using_encoded(twox_64_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
assert_eq!(&k[..32], &<instance::Map2<instance::Instance2>>::final_prefix());
let head = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"HeadOfLinkedMap")].concat();
assert_eq!(unhashed::get::<u32>(&head), None);
<instance::LinkedMap<instance::Instance2>>::insert(1, 2);
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"LinkedMap")].concat();
k.extend(1u32.using_encoded(blake2_256).to_vec());
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
assert_eq!(unhashed::get::<u32>(&head), Some(1u32));
<instance::LinkedMap2<instance::Instance2>>::insert(1, 2);
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"LinkedMap2")].concat();
k.extend(1u32.using_encoded(twox_128).to_vec());
assert_eq!(unhashed::get::<u32>(&k), Some(2u32));
<instance::DoubleMap<instance::Instance2>>::insert(&1, &2, &3);
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"DoubleMap")].concat();
k.extend(1u32.using_encoded(blake2_256).to_vec());
k.extend(2u32.using_encoded(blake2_256).to_vec());
k.extend(1u32.using_encoded(blake2_128_concat));
k.extend(2u32.using_encoded(blake2_128_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
assert_eq!(&k[..32], &<instance::DoubleMap<instance::Instance2>>::final_prefix());
<instance::DoubleMap2<instance::Instance2>>::insert(&1, &2, &3);
let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"DoubleMap2")].concat();
k.extend(1u32.using_encoded(twox_128).to_vec());
k.extend(2u32.using_encoded(blake2_128).to_vec());
k.extend(1u32.using_encoded(twox_64_concat));
k.extend(2u32.using_encoded(twox_64_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
assert_eq!(&k[..32], &<instance::DoubleMap2<instance::Instance2>>::final_prefix());
});
@@ -25,7 +25,7 @@ frame_support::decl_module! {
frame_support::decl_storage! {
trait Store for Module<T: Trait> as Test {
pub AppendableDM config(t): double_map hasher(blake2_256) u32, hasher(blake2_256) T::BlockNumber => Vec<u32>;
pub AppendableDM config(t): double_map hasher(identity) u32, hasher(identity) T::BlockNumber => Vec<u32>;
}
}
+10 -57
View File
@@ -23,7 +23,7 @@ use frame_support::{
DecodeDifferent, StorageMetadata, StorageEntryModifier, StorageEntryType, DefaultByteGetter,
StorageEntryMetadata, StorageHasher,
},
StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap,
StorageValue, StorageMap, StorageDoubleMap,
};
use sp_inherents::{ProvideInherent, InherentData, InherentIdentifier, MakeFatalError};
use sp_core::{H256, sr25519};
@@ -67,8 +67,7 @@ mod module1 {
T::BlockNumber: From<u32> + std::fmt::Display
{
pub Value config(value): T::GenericType;
pub Map: map hasher(blake2_256) u32 => u64;
pub LinkedMap: linked_map hasher(blake2_256) u32 => u64;
pub Map: map hasher(identity) u32 => u64;
}
add_extra_genesis {
@@ -136,9 +135,8 @@ mod module2 {
frame_support::decl_storage! {
trait Store for Module<T: Trait<I>, I: Instance=DefaultInstance> as Module2 {
pub Value config(value): T::Amount;
pub Map config(map): map hasher(blake2_256) u64 => u64;
pub LinkedMap config(linked_map): linked_map hasher(blake2_256) u64 => Vec<u8>;
pub DoubleMap config(double_map): double_map hasher(blake2_256) u64, hasher(blake2_256) u64 => u64;
pub Map config(map): map hasher(identity) u64 => u64;
pub DoubleMap config(double_map): double_map hasher(identity) u64, hasher(identity) u64 => u64;
}
}
@@ -285,13 +283,11 @@ fn new_test_ext() -> sp_io::TestExternalities {
module2: Some(module2::GenesisConfig {
value: 4,
map: vec![(0, 0)],
linked_map: vec![(0, vec![0])],
double_map: vec![(0, 0, 0)],
}),
module2_Instance1: Some(module2::GenesisConfig {
value: 4,
map: vec![(0, 0)],
linked_map: vec![(0, vec![0])],
double_map: vec![(0, 0, 0)],
}),
module2_Instance2: None,
@@ -314,17 +310,13 @@ fn storage_instance_independence() {
module2::Map::<module2::Instance1>::insert(0, 0);
module2::Map::<module2::Instance2>::insert(0, 0);
module2::Map::<module2::Instance3>::insert(0, 0);
module2::LinkedMap::<module2::DefaultInstance>::insert::<_, Vec<u8>>(0, vec![]);
module2::LinkedMap::<module2::Instance1>::insert::<_, Vec<u8>>(0, vec![]);
module2::LinkedMap::<module2::Instance2>::insert::<_, Vec<u8>>(0, vec![]);
module2::LinkedMap::<module2::Instance3>::insert::<_, Vec<u8>>(0, vec![]);
module2::DoubleMap::<module2::DefaultInstance>::insert(&0, &0, &0);
module2::DoubleMap::<module2::Instance1>::insert(&0, &0, &0);
module2::DoubleMap::<module2::Instance2>::insert(&0, &0, &0);
module2::DoubleMap::<module2::Instance3>::insert(&0, &0, &0);
});
// 16 storage values + 4 linked_map head.
assert_eq!(storage.top.len(), 16 + 4);
// 12 storage values.
assert_eq!(storage.top.len(), 12);
}
#[test]
@@ -332,7 +324,6 @@ fn storage_with_instance_basic_operation() {
new_test_ext().execute_with(|| {
type Value = module2::Value<Runtime, module2::Instance1>;
type Map = module2::Map<module2::Instance1>;
type LinkedMap = module2::LinkedMap<module2::Instance1>;
type DoubleMap = module2::DoubleMap<module2::Instance1>;
assert_eq!(Value::exists(), true);
@@ -360,26 +351,6 @@ fn storage_with_instance_basic_operation() {
assert_eq!(Map::contains_key(key), false);
assert_eq!(Map::get(key), 0);
assert_eq!(LinkedMap::contains_key(0), true);
assert_eq!(LinkedMap::contains_key(key), false);
LinkedMap::insert(key, vec![1]);
assert_eq!(LinkedMap::enumerate().count(), 2);
assert_eq!(LinkedMap::get(key), vec![1]);
assert_eq!(LinkedMap::take(key), vec![1]);
assert_eq!(LinkedMap::enumerate().count(), 1);
assert_eq!(LinkedMap::get(key), vec![]);
LinkedMap::mutate(key, |a| *a=vec![2]);
assert_eq!(LinkedMap::enumerate().count(), 2);
assert_eq!(LinkedMap::get(key), vec![2]);
LinkedMap::remove(key);
assert_eq!(LinkedMap::enumerate().count(), 1);
assert_eq!(LinkedMap::contains_key(key), false);
assert_eq!(LinkedMap::get(key), vec![]);
assert_eq!(LinkedMap::contains_key(key), false);
assert_eq!(LinkedMap::enumerate().count(), 1);
LinkedMap::insert(key, &vec![1]);
assert_eq!(LinkedMap::enumerate().count(), 2);
let key1 = 1;
let key2 = 1;
assert_eq!(DoubleMap::contains_key(&0, &0), true);
@@ -416,10 +387,10 @@ const EXPECTED_METADATA: StorageMetadata = StorageMetadata {
name: DecodeDifferent::Encode("Map"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Identity,
key: DecodeDifferent::Encode("u64"),
value: DecodeDifferent::Encode("u64"),
is_linked: false,
unused: false,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(
@@ -430,30 +401,12 @@ const EXPECTED_METADATA: StorageMetadata = StorageMetadata {
),
documentation: DecodeDifferent::Encode(&[]),
},
StorageEntryMetadata {
name: DecodeDifferent::Encode("LinkedMap"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u64"),
value: DecodeDifferent::Encode("Vec<u8>"),
is_linked: true,
},
default: DecodeDifferent::Encode(
DefaultByteGetter(
&module2::__GetByteStructLinkedMap(
std::marker::PhantomData::<(Runtime, module2::Instance2)>
)
)
),
documentation: DecodeDifferent::Encode(&[]),
},
StorageEntryMetadata {
name: DecodeDifferent::Encode("DoubleMap"),
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::DoubleMap {
hasher: StorageHasher::Blake2_256,
key2_hasher: StorageHasher::Blake2_256,
hasher: StorageHasher::Identity,
key2_hasher: StorageHasher::Identity,
key1: DecodeDifferent::Encode("u64"),
key2: DecodeDifferent::Encode("u64"),
value: DecodeDifferent::Encode("u64"),
@@ -109,7 +109,7 @@ mod module {
} else {
vec![]
}
}): map hasher(blake2_256) Role => Option<RoleParameters<T>>;
}): map hasher(blake2_128_concat) Role => Option<RoleParameters<T>>;
/// the roles members can enter into
pub AvailableRoles get(fn available_roles) build(|config: &GenesisConfig| {
@@ -125,11 +125,11 @@ mod module {
/// actor accounts associated with a role
pub AccountIdsByRole get(fn account_ids_by_role):
map hasher(blake2_256) Role => Vec<T::AccountId>;
map hasher(blake2_128_concat) Role => Vec<T::AccountId>;
/// tokens locked until given block number
pub Bondage get(fn bondage):
map hasher(blake2_256) T::AccountId => T::BlockNumber;
map hasher(blake2_128_concat) T::AccountId => T::BlockNumber;
/// First step before enter a role is registering intent with a new account/key.
/// This is done by sending a role_entry_request() from the new account.
+1 -1
View File
@@ -77,7 +77,7 @@ impl system::Trait for Runtime {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
Binary file not shown.
+32 -15
View File
@@ -116,7 +116,7 @@ use frame_support::{
decl_module, decl_event, decl_storage, decl_error, storage, Parameter, ensure, debug,
traits::{
Contains, Get, ModuleToIndex, OnNewAccount, OnKilledAccount, IsDeadAccount, Happened,
StoredMap
StoredMap, MigrateAccount,
},
weights::{Weight, DispatchInfo, DispatchClass, SimpleDispatchInfo, FunctionOf},
};
@@ -126,6 +126,7 @@ use codec::{Encode, Decode, FullCodec, EncodeLike};
use sp_io::TestExternalities;
pub mod offchain;
mod migration;
/// Compute the trie root of a list of extrinsics.
pub fn extrinsics_root<H: Hash, E: codec::Encode>(extrinsics: &[E]) -> H::Output {
@@ -221,6 +222,9 @@ pub trait Trait: 'static + Eq + Clone {
///
/// All resources should be cleaned up associated with the given account.
type OnKilledAccount: OnKilledAccount<Self::AccountId>;
/// Migrate an account.
type MigrateAccount: MigrateAccount<Self::AccountId>;
}
pub type DigestOf<T> = generic::Digest<<T as Trait>::Hash>;
@@ -337,10 +341,8 @@ impl From<sp_version::RuntimeVersion> for LastRuntimeUpgradeInfo {
decl_storage! {
trait Store for Module<T: Trait> as System {
/// The full account information for a particular account ID.
// TODO: should be hasher(twox64_concat) - will need staged migration
// https://github.com/paritytech/substrate/issues/4917
pub Account get(fn account):
map hasher(blake2_256) T::AccountId => AccountInfo<T::Index, T::AccountData>;
map hasher(blake2_128_concat) T::AccountId => AccountInfo<T::Index, T::AccountData>;
/// Total extrinsics count for the current block.
ExtrinsicCount: Option<u32>;
@@ -352,10 +354,8 @@ decl_storage! {
AllExtrinsicsLen: Option<u32>;
/// Map of block numbers to block hashes.
// TODO: should be hasher(twox64_concat) - will need one-off migration
// https://github.com/paritytech/substrate/issues/4917
pub BlockHash get(fn block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]):
map hasher(blake2_256) T::BlockNumber => T::Hash;
map hasher(twox_64_concat) T::BlockNumber => T::Hash;
/// Extrinsics data for the current block (maps an extrinsic's index to its data).
ExtrinsicData get(fn extrinsic_data): map hasher(twox_64_concat) u32 => Vec<u8>;
@@ -393,7 +393,7 @@ decl_storage! {
/// The value has the type `(T::BlockNumber, EventIndex)` because if we used only just
/// the `EventIndex` then in case if the topic has the same contents on the next block
/// no notification will be triggered thus the event might be lost.
EventTopics get(fn event_topics): map hasher(blake2_256) T::Hash => Vec<(T::BlockNumber, EventIndex)>;
EventTopics get(fn event_topics): map hasher(blake2_128_concat) T::Hash => Vec<(T::BlockNumber, EventIndex)>;
/// Stores the `spec_version` and `spec_name` of when the last runtime upgrade happened.
pub LastRuntimeUpgrade build(|_| Some(LastRuntimeUpgradeInfo::from(T::Version::get()))): Option<LastRuntimeUpgradeInfo>;
@@ -452,7 +452,7 @@ decl_error! {
/// Suicide called when the account has non-default composite data.
NonDefaultComposite,
/// There is a non-zero reference count preventing the account from being purged.
NonZeroRefCount
NonZeroRefCount,
}
}
@@ -460,6 +460,15 @@ decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
type Error = Error<T>;
fn on_runtime_upgrade() {
migration::migrate::<T>();
// Remove the old `RuntimeUpgraded` storage entry.
let mut runtime_upgraded_key = sp_io::hashing::twox_128(b"System").to_vec();
runtime_upgraded_key.extend(&sp_io::hashing::twox_128(b"RuntimeUpgraded"));
sp_io::storage::clear(&runtime_upgraded_key);
}
/// A dispatch that will fill the block weight up to the given ratio.
// TODO: This should only be available for testing, rather than in general usage, but
// that's not possible at present (since it's within the decl_module macro).
@@ -569,11 +578,19 @@ decl_module! {
Account::<T>::remove(who);
}
fn on_runtime_upgrade() {
// Remove the old `RuntimeUpgraded` storage entry.
let mut runtime_upgraded_key = sp_io::hashing::twox_128(b"System").to_vec();
runtime_upgraded_key.extend(&sp_io::hashing::twox_128(b"RuntimeUpgraded"));
sp_io::storage::clear(&runtime_upgraded_key);
#[weight = FunctionOf(
|(accounts,): (&Vec<T::AccountId>,)| accounts.len() as u32 * 10_000,
DispatchClass::Normal,
true,
)]
fn migrate_accounts(origin, accounts: Vec<T::AccountId>) {
let _ = ensure_signed(origin)?;
for a in &accounts {
if Account::<T>::migrate_key_from_blake(a).is_some() {
// Inform other modules about the account.
T::MigrateAccount::migrate_account(a);
}
}
}
}
}
@@ -1553,7 +1570,7 @@ mod tests {
type Version = Version;
type ModuleToIndex = ();
type AccountData = u32;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = RecordKilled;
}
+37
View File
@@ -0,0 +1,37 @@
use super::*;
use sp_runtime::traits::SaturatedConversion;
pub fn migrate<T: Trait>() {
// Number is current block - we obviously don't know that hash.
// Number - 1 is the parent block, who hash we record in this block, but then that's already
// with the new storage so we don't migrate it.
// Number - 2 is therefore the most recent block's hash that needs migrating.
if Number::<T>::get() > One::one() {
sp_runtime::print("Migrating BlockHash...");
BlockHash::<T>::migrate_key_from_blake(T::BlockNumber::zero());
let mut n = Number::<T>::get() - One::one() - One::one();
while !n.is_zero() {
sp_runtime::print(n.saturated_into::<u32>());
if BlockHash::<T>::migrate_key_from_blake(n).is_none() {
break;
}
n -= One::one();
}
}
sp_runtime::print("Migrating Accounts...");
let mut count = 0u32;
if let Ok(accounts) = Vec::<T::AccountId>::decode(&mut &include_bytes!("accounts.scale")[..]) {
for a in &accounts {
if Account::<T>::migrate_key_from_blake(a).is_some() {
// Inform other modules about the account.
T::MigrateAccount::migrate_account(a);
count += 1;
if count % 1000 == 0 {
sp_runtime::print(count);
}
}
}
}
sp_runtime::print(count);
}
+1 -1
View File
@@ -278,7 +278,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
@@ -48,8 +48,6 @@ use sp_runtime::{
};
use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo;
mod migration;
type Multiplier = Fixed64;
type BalanceOf<T> =
<<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
@@ -97,10 +95,6 @@ decl_module! {
*fm = T::FeeMultiplierUpdate::convert(*fm)
});
}
fn on_runtime_upgrade() {
migration::on_runtime_upgrade()
}
}
}
@@ -316,7 +310,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
@@ -1,38 +0,0 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Migration code to update storage.
use super::*;
use frame_support::storage::migration::{put_storage_value, take_storage_value};
pub fn on_runtime_upgrade() {
change_name_balances_to_transaction_payment()
}
// Change the storage name used by this pallet from `Balances` to `TransactionPayment`.
//
// Since the format of the storage items themselves have not changed, we do not
// need to keep track of a storage version. If the runtime does not need to be
// upgraded, nothing here will happen anyway.
fn change_name_balances_to_transaction_payment() {
sp_runtime::print("Migrating Transaction Payment.");
if let Some(next_fee_multiplier) = take_storage_value::<Multiplier>(b"Balances", b"NextFeeMultiplier", &[]) {
put_storage_value(b"TransactionPayment", b"NextFeeMultiplier", &[], next_fee_multiplier);
}
}
+21 -4
View File
@@ -200,7 +200,9 @@ decl_storage! {
ProposalCount get(fn proposal_count): ProposalIndex;
/// Proposals that have been made.
Proposals get(fn proposals): map hasher(blake2_256) ProposalIndex => Option<Proposal<T::AccountId, BalanceOf<T>>>;
Proposals get(fn proposals):
map hasher(twox_64_concat) ProposalIndex
=> Option<Proposal<T::AccountId, BalanceOf<T>>>;
/// Proposal indices that have been approved but not yet awarded.
Approvals get(fn approvals): Vec<ProposalIndex>;
@@ -208,12 +210,13 @@ decl_storage! {
/// Tips that are not yet completed. Keyed by the hash of `(reason, who)` from the value.
/// This has the insecure enumerable hash function since the key itself is already
/// guaranteed to be a secure hash.
pub Tips get(fn tips): map hasher(twox_64_concat) T::Hash
pub Tips get(fn tips):
map hasher(twox_64_concat) T::Hash
=> Option<OpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>>;
/// Simple preimage lookup from the reason's hash to the original data. Again, has an
/// insecure enumerable hash since the key is guaranteed to be the result of a secure hash.
pub Reasons get(fn reasons): map hasher(twox_64_concat) T::Hash => Option<Vec<u8>>;
pub Reasons get(fn reasons): map hasher(identity) T::Hash => Option<Vec<u8>>;
}
add_extra_genesis {
build(|_config| {
@@ -280,8 +283,22 @@ decl_error! {
}
}
mod migration {
use super::*;
pub fn migrate<T: Trait>() {
for i in 0..ProposalCount::get() {
Proposals::<T>::migrate_key_from_blake(i);
}
Reasons::<T>::remove_all();
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn on_runtime_upgrade() {
migration::migrate::<T>();
}
/// Fraction of a proposal's value that should be bonded in order to place the proposal.
/// An accepted proposal gets these back. A rejected proposal does not.
const ProposalBond: Permill = T::ProposalBond::get();
@@ -759,7 +776,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
+1 -1
View File
@@ -623,7 +623,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
+10 -6
View File
@@ -53,10 +53,7 @@ use sp_runtime::{DispatchResult, RuntimeDebug, traits::{
StaticLookup, Zero, AtLeast32Bit, MaybeSerializeDeserialize, Convert
}};
use frame_support::{decl_module, decl_event, decl_storage, decl_error, ensure};
use frame_support::traits::{
Currency, LockableCurrency, VestingSchedule, WithdrawReason, LockIdentifier, ExistenceRequirement,
Get,
};
use frame_support::traits::{Currency, LockableCurrency, VestingSchedule, WithdrawReason, LockIdentifier, ExistenceRequirement, Get, MigrateAccount};
use frame_support::weights::SimpleDispatchInfo;
use frame_system::{self as system, ensure_signed};
@@ -118,7 +115,8 @@ decl_storage! {
trait Store for Module<T: Trait> as Vesting {
/// Information regarding the vesting of a given account.
pub Vesting get(fn vesting):
map hasher(blake2_256) T::AccountId => Option<VestingInfo<BalanceOf<T>, T::BlockNumber>>;
map hasher(blake2_128_concat) T::AccountId
=> Option<VestingInfo<BalanceOf<T>, T::BlockNumber>>;
}
add_extra_genesis {
config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber, BalanceOf<T>)>;
@@ -256,6 +254,12 @@ decl_module! {
}
}
impl<T: Trait> MigrateAccount<T::AccountId> for Module<T> {
fn migrate_account(a: &T::AccountId) {
Vesting::<T>::migrate_key_from_blake(a);
}
}
impl<T: Trait> Module<T> {
/// (Re)set or remove the module's currency lock on `who`'s account in accordance with their
/// current unvested amount.
@@ -384,7 +388,7 @@ mod tests {
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
impl pallet_balances::Trait for Test {
+1 -1
View File
@@ -391,7 +391,7 @@ impl frame_system::Trait for Runtime {
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type MigrateAccount = (); type OnNewAccount = ();
type OnKilledAccount = ();
}
+1 -1
View File
@@ -46,7 +46,7 @@ decl_module! {
decl_storage! {
trait Store for Module<T: Trait> as TestRuntime {
ExtrinsicData: map hasher(blake2_256) u32 => Vec<u8>;
ExtrinsicData: map hasher(blake2_128_concat) u32 => Vec<u8>;
// The current block number being processed. Set by `execute_block`.
Number get(fn number): Option<BlockNumber>;
ParentHash get(fn parent_hash): Hash;
+5 -13
View File
@@ -25,7 +25,7 @@ use jsonrpc_client_transports::RpcError;
use codec::{DecodeAll, FullCodec, FullEncode};
use serde::{de::DeserializeOwned, Serialize};
use frame_support::storage::generator::{
StorageDoubleMap, StorageLinkedMap, StorageMap, StorageValue
StorageDoubleMap, StorageMap, StorageValue
};
use sp_storage::{StorageData, StorageKey};
use sc_rpc_api::state::StateClient;
@@ -63,9 +63,9 @@ use sc_rpc_api::state::StateClient;
/// decl_storage! {
/// trait Store for Module<T: Trait> as TestRuntime {
/// pub LastActionId: u64;
/// pub Voxels: map hasher(blake2_256) Loc => Block;
/// pub Actions: linked_map hasher(blake2_256) u64 => Loc;
/// pub Prefab: double_map hasher(blake2_256) u128, hasher(blake2_256) (i8, i8, i8) => Block;
/// pub Voxels: map hasher(blake2_128_concat) Loc => Block;
/// pub Actions: map hasher(blake2_128_concat) u64 => Loc;
/// pub Prefab: double_map hasher(blake2_128_concat) u128, hasher(blake2_128_concat) (i8, i8, i8) => Block;
/// }
/// }
///
@@ -79,7 +79,7 @@ use sc_rpc_api::state::StateClient;
/// let q = StorageQuery::map::<Voxels, _>((0, 0, 0));
/// let _: Option<Block> = q.get(&cl, None).await?;
///
/// let q = StorageQuery::linked_map::<Actions, _>(12);
/// let q = StorageQuery::map::<Actions, _>(12);
/// let _: Option<Loc> = q.get(&cl, None).await?;
///
/// let q = StorageQuery::double_map::<Prefab, _, _>(3, (0, 0, 0));
@@ -111,14 +111,6 @@ impl<V: FullCodec> StorageQuery<V> {
}
}
/// Create a storage query for a value in a StorageLinkedMap.
pub fn linked_map<St: StorageLinkedMap<K, V>, K: FullCodec>(key: K) -> Self {
Self {
key: StorageKey(St::storage_linked_map_final_key(key)),
_spook: PhantomData,
}
}
/// Create a storage query for a value in a StorageDoubleMap.
pub fn double_map<St: StorageDoubleMap<K1, K2, V>, K1: FullEncode, K2: FullEncode>(
key1: K1,