mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 22:51:13 +00:00
Use storage::append in the implementation of the storage types (#5889)
* Start improving `storage_append` * Fix some stuff * Fix compilation * Update docs and add new test * More tests * Test kill + append
This commit is contained in:
@@ -160,7 +160,7 @@ decl_module! {
|
||||
#[weight = 0]
|
||||
pub fn append_member_list(origin) {
|
||||
let who = ensure_signed(origin)?;
|
||||
MyMemberList::<T>::append(&[who])?;
|
||||
MyMemberList::<T>::append(who);
|
||||
}
|
||||
|
||||
/// Encode a vector of accounts to bytes.
|
||||
|
||||
@@ -168,7 +168,7 @@ use sp_runtime::{
|
||||
DispatchResult, DispatchError, RuntimeDebug,
|
||||
traits::{Zero, Hash, Dispatchable, Saturating},
|
||||
};
|
||||
use codec::{Ref, Encode, Decode};
|
||||
use codec::{Encode, Decode};
|
||||
use frame_support::{
|
||||
decl_module, decl_storage, decl_event, decl_error, ensure, Parameter,
|
||||
weights::{Weight, DispatchClass},
|
||||
@@ -553,8 +553,7 @@ decl_module! {
|
||||
PublicPropCount::put(index + 1);
|
||||
<DepositOf<T>>::insert(index, (value, &[&who][..]));
|
||||
|
||||
let new_prop = (index, proposal_hash, who);
|
||||
<PublicProps<T>>::append_or_put(&[Ref::from(&new_prop)][..]);
|
||||
<PublicProps<T>>::append((index, proposal_hash, who));
|
||||
|
||||
Self::deposit_event(RawEvent::Proposed(index, value));
|
||||
}
|
||||
|
||||
@@ -886,7 +886,7 @@ impl<T: Trait> Module<T> {
|
||||
if set_len + 1 == VOTER_SET_SIZE {
|
||||
NextVoterSet::put(next + 1);
|
||||
}
|
||||
<Voters<T>>::append_or_insert(next, &[Some(who.clone())][..])
|
||||
<Voters<T>>::append(next, Some(who.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ use frame_support::{
|
||||
traits::{Get, schedule},
|
||||
weights::{GetDispatchInfo, Weight},
|
||||
};
|
||||
use frame_system::{self as system};
|
||||
use frame_system as system;
|
||||
|
||||
/// Our pallet's configuration trait. All our types and constants go in here. If the
|
||||
/// pallet is dependent on specific other pallets, then their configuration traits
|
||||
@@ -123,7 +123,7 @@ decl_module! {
|
||||
.collect::<Vec<_>>();
|
||||
queued.sort_by_key(|(_, s)| s.priority);
|
||||
let mut result = 0;
|
||||
let unused_items = queued.into_iter()
|
||||
queued.into_iter()
|
||||
.enumerate()
|
||||
.scan(0, |cumulative_weight, (order, (index, s))| {
|
||||
*cumulative_weight += s.call.get_dispatch_info().weight;
|
||||
@@ -141,10 +141,10 @@ decl_module! {
|
||||
}
|
||||
let next = now + period;
|
||||
if let Some(ref id) = s.maybe_id {
|
||||
let next_index = Agenda::<T>::decode_len(now + period).unwrap_or(0) as u32;
|
||||
Lookup::<T>::insert(id, (next, next_index));
|
||||
let next_index = Agenda::<T>::decode_len(now + period).unwrap_or(0);
|
||||
Lookup::<T>::insert(id, (next, next_index as u32));
|
||||
}
|
||||
Agenda::<T>::append_or_insert(next, &[Some(s)][..]);
|
||||
Agenda::<T>::append(next, Some(s));
|
||||
} else {
|
||||
if let Some(ref id) = s.maybe_id {
|
||||
Lookup::<T>::remove(id);
|
||||
@@ -161,11 +161,11 @@ decl_module! {
|
||||
Some(Some(s))
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if !unused_items.is_empty() {
|
||||
let next = now + One::one();
|
||||
Agenda::<T>::append_or_insert(next, &unused_items[..]);
|
||||
}
|
||||
.for_each(|unused| {
|
||||
let next = now + One::one();
|
||||
Agenda::<T>::append(next, unused);
|
||||
});
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,7 @@ impl<T: Trait> schedule::Anon<T::BlockNumber, <T as Trait>::Call> for Module<T>
|
||||
// Remove one from the number of repetitions since we will schedule one now.
|
||||
.map(|(p, c)| (p, c - 1));
|
||||
let s = Some(Scheduled { maybe_id: None, priority, call, maybe_periodic });
|
||||
Agenda::<T>::append_or_insert(when, &[s][..]);
|
||||
Agenda::<T>::append(when, s);
|
||||
(when, Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1)
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ impl<T: Trait> schedule::Named<T::BlockNumber, <T as Trait>::Call> for Module<T>
|
||||
.map(|(p, c)| (p, c - 1));
|
||||
|
||||
let s = Scheduled { maybe_id: Some(id.clone()), priority, call, maybe_periodic };
|
||||
Agenda::<T>::append_or_insert(when, &[Some(s)][..]);
|
||||
Agenda::<T>::append(when, Some(s));
|
||||
let index = Agenda::<T>::decode_len(when).unwrap_or(1) as u32 - 1;
|
||||
let address = (when, index);
|
||||
Lookup::<T>::insert(&id, &address);
|
||||
|
||||
@@ -100,9 +100,7 @@ use frame_support::{
|
||||
weights::Weight,
|
||||
};
|
||||
use frame_system::{self as system, ensure_root, ensure_signed};
|
||||
use sp_runtime::{
|
||||
traits::{AtLeast32Bit, MaybeSerializeDeserialize, Zero, StaticLookup},
|
||||
};
|
||||
use sp_runtime::traits::{AtLeast32Bit, MaybeSerializeDeserialize, Zero, StaticLookup};
|
||||
|
||||
type BalanceOf<T, I> = <<T as Trait<I>>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::Balance;
|
||||
type PoolT<T, I> = Vec<(<T as frame_system::Trait>::AccountId, Option<<T as Trait<I>>::Score>)>;
|
||||
@@ -276,10 +274,7 @@ decl_module! {
|
||||
|
||||
// can be inserted as last element in pool, since entities with
|
||||
// `None` are always sorted to the end.
|
||||
if let Err(e) = <Pool<T, I>>::append(&[(who.clone(), None)]) {
|
||||
T::Currency::unreserve(&who, deposit);
|
||||
Err(e)?
|
||||
}
|
||||
<Pool<T, I>>::append((who.clone(), Option::<<T as Trait<I>>::Score>::None));
|
||||
|
||||
<CandidateExists<T, I>>::insert(&who, true);
|
||||
|
||||
|
||||
@@ -499,8 +499,8 @@ mod tests {
|
||||
let key2 = 18u32;
|
||||
|
||||
DoubleMap::insert(&key1, &key2, &vec![1]);
|
||||
DoubleMap::append(&key1, &key2, &[2, 3]).unwrap();
|
||||
assert_eq!(DoubleMap::get(&key1, &key2), &[1, 2, 3]);
|
||||
DoubleMap::append(&key1, &key2, 2);
|
||||
assert_eq!(DoubleMap::get(&key1, &key2), &[1, 2]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use sp_std::borrow::Borrow;
|
||||
use codec::{Ref, FullCodec, FullEncode, Decode, Encode, EncodeLike, EncodeAppend};
|
||||
use crate::{storage::{self, unhashed}, traits::Len, Never};
|
||||
use codec::{FullCodec, FullEncode, Decode, Encode, EncodeLike};
|
||||
use crate::{storage::{self, unhashed, StorageAppend}, traits::Len, Never};
|
||||
use crate::hash::{StorageHasher, Twox128, ReversibleStorageHasher};
|
||||
|
||||
/// Generator for `StorageDoubleMap` used by `decl_storage`.
|
||||
@@ -245,53 +245,19 @@ impl<K1, K2, V, G> storage::StorageDoubleMap<K1, K2, V> for G where
|
||||
ret
|
||||
}
|
||||
|
||||
fn append<Items, Item, EncodeLikeItem, KArg1, KArg2>(
|
||||
fn append<Item, EncodeLikeItem, KArg1, KArg2>(
|
||||
k1: KArg1,
|
||||
k2: KArg2,
|
||||
items: Items,
|
||||
) -> Result<(), &'static str> where
|
||||
KArg1: EncodeLike<K1>,
|
||||
KArg2: EncodeLike<K2>,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
V: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem>,
|
||||
Items::IntoIter: ExactSizeIterator
|
||||
{
|
||||
let final_key = Self::storage_double_map_final_key(k1, k2);
|
||||
|
||||
let encoded_value = unhashed::get_raw(&final_key)
|
||||
.unwrap_or_else(|| {
|
||||
match G::from_query_to_optional_value(G::from_optional_value_to_query(None)) {
|
||||
Some(value) => value.encode(),
|
||||
None => Vec::new(),
|
||||
}
|
||||
});
|
||||
|
||||
let new_val = V::append_or_new(
|
||||
encoded_value,
|
||||
items,
|
||||
).map_err(|_| "Could not append given item")?;
|
||||
unhashed::put_raw(&final_key, &new_val);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn append_or_insert<Items, Item, EncodeLikeItem, KArg1, KArg2>(
|
||||
k1: KArg1,
|
||||
k2: KArg2,
|
||||
items: Items,
|
||||
item: EncodeLikeItem,
|
||||
) where
|
||||
KArg1: EncodeLike<K1>,
|
||||
KArg2: EncodeLike<K2>,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
V: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<V>,
|
||||
Items::IntoIter: ExactSizeIterator
|
||||
V: StorageAppend<Item>,
|
||||
{
|
||||
Self::append(Ref::from(&k1), Ref::from(&k2), items.clone())
|
||||
.unwrap_or_else(|_| Self::insert(k1, k2, items));
|
||||
let final_key = Self::storage_double_map_final_key(k1, k2);
|
||||
sp_io::storage::append(&final_key, item.encode());
|
||||
}
|
||||
|
||||
fn decode_len<KArg1, KArg2>(key1: KArg1, key2: KArg2) -> Result<usize, &'static str> where
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
#[cfg(not(feature = "std"))]
|
||||
use sp_std::prelude::*;
|
||||
use sp_std::borrow::Borrow;
|
||||
use codec::{FullCodec, FullEncode, Decode, Encode, EncodeLike, Ref, EncodeAppend};
|
||||
use crate::{storage::{self, unhashed}, traits::Len, Never};
|
||||
use codec::{FullCodec, FullEncode, Decode, Encode, EncodeLike};
|
||||
use crate::{storage::{self, unhashed, StorageAppend}, traits::Len, Never};
|
||||
use crate::hash::{StorageHasher, Twox128, ReversibleStorageHasher};
|
||||
|
||||
/// Generator for `StorageMap` used by `decl_storage`.
|
||||
@@ -276,43 +276,15 @@ impl<K: FullEncode, V: FullCodec, G: StorageMap<K, V>> storage::StorageMap<K, V>
|
||||
G::from_optional_value_to_query(value)
|
||||
}
|
||||
|
||||
fn append<Items, Item, EncodeLikeItem, KeyArg>(key: KeyArg, items: Items) -> Result<(), &'static str>
|
||||
fn append<Item, EncodeLikeItem, EncodeLikeKey>(key: EncodeLikeKey, item: EncodeLikeItem)
|
||||
where
|
||||
KeyArg: EncodeLike<K>,
|
||||
EncodeLikeKey: EncodeLike<K>,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
V: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem>,
|
||||
Items::IntoIter: ExactSizeIterator,
|
||||
V: StorageAppend<Item>,
|
||||
{
|
||||
let key = Self::storage_map_final_key(key);
|
||||
let encoded_value = unhashed::get_raw(key.as_ref())
|
||||
.unwrap_or_else(|| {
|
||||
match G::from_query_to_optional_value(G::from_optional_value_to_query(None)) {
|
||||
Some(value) => value.encode(),
|
||||
None => Vec::new(),
|
||||
}
|
||||
});
|
||||
|
||||
let new_val = V::append_or_new(
|
||||
encoded_value,
|
||||
items,
|
||||
).map_err(|_| "Could not append given item")?;
|
||||
unhashed::put_raw(key.as_ref(), &new_val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn append_or_insert<Items, Item, EncodeLikeItem, KeyArg>(key: KeyArg, items: Items)
|
||||
where
|
||||
KeyArg: EncodeLike<K>,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
V: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<V>,
|
||||
Items::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
Self::append(Ref::from(&key), items.clone())
|
||||
.unwrap_or_else(|_| Self::insert(key, items));
|
||||
sp_io::storage::append(&key, item.encode());
|
||||
}
|
||||
|
||||
fn decode_len<KeyArg: EncodeLike<K>>(key: KeyArg) -> Result<usize, &'static str>
|
||||
|
||||
@@ -14,12 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use sp_std::prelude::*;
|
||||
use codec::{FullCodec, Encode, EncodeAppend, EncodeLike, Decode};
|
||||
use codec::{FullCodec, Encode, EncodeLike, Decode};
|
||||
use crate::{
|
||||
Never,
|
||||
storage::{self, unhashed},
|
||||
storage::{self, unhashed, StorageAppend},
|
||||
hash::{Twox128, StorageHasher},
|
||||
traits::Len
|
||||
};
|
||||
@@ -134,55 +132,16 @@ impl<T: FullCodec, G: StorageValue<T>> storage::StorageValue<T> for G {
|
||||
G::from_optional_value_to_query(value)
|
||||
}
|
||||
|
||||
/// Append the given items to the value in the storage.
|
||||
///
|
||||
/// `T` is required to implement `codec::EncodeAppend`.
|
||||
fn append<Items, Item, EncodeLikeItem>(items: Items) -> Result<(), &'static str>
|
||||
fn append<Item, EncodeLikeItem>(item: EncodeLikeItem)
|
||||
where
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
T: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem>,
|
||||
Items::IntoIter: ExactSizeIterator,
|
||||
T: StorageAppend<Item>,
|
||||
{
|
||||
let key = Self::storage_value_final_key();
|
||||
let encoded_value = unhashed::get_raw(&key)
|
||||
.unwrap_or_else(|| {
|
||||
match G::from_query_to_optional_value(G::from_optional_value_to_query(None)) {
|
||||
Some(value) => value.encode(),
|
||||
None => Vec::new(),
|
||||
}
|
||||
});
|
||||
|
||||
let new_val = T::append_or_new(
|
||||
encoded_value,
|
||||
items,
|
||||
).map_err(|_| "Could not append given item")?;
|
||||
unhashed::put_raw(&key, &new_val);
|
||||
Ok(())
|
||||
sp_io::storage::append(&key, item.encode());
|
||||
}
|
||||
|
||||
/// Safely append the given items to the value in the storage. If a codec error occurs, then the
|
||||
/// old (presumably corrupt) value is replaced with the given `items`.
|
||||
///
|
||||
/// `T` is required to implement `codec::EncodeAppend`.
|
||||
fn append_or_put<Items, Item, EncodeLikeItem>(items: Items) where
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
T: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<T>,
|
||||
Items::IntoIter: ExactSizeIterator
|
||||
{
|
||||
Self::append(items.clone()).unwrap_or_else(|_| Self::put(items));
|
||||
}
|
||||
|
||||
/// 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 `::exists()`
|
||||
/// function for this purpose.
|
||||
fn decode_len() -> Result<usize, &'static str> where T: codec::DecodeLength, T: Len {
|
||||
let key = Self::storage_value_final_key();
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Stuff to do with the runtime's storage.
|
||||
|
||||
use sp_std::{prelude::*, marker::PhantomData};
|
||||
use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike, Decode};
|
||||
use codec::{FullCodec, FullEncode, Encode, EncodeLike, Decode};
|
||||
use crate::{traits::Len, hash::{Twox128, StorageHasher}};
|
||||
|
||||
pub mod unhashed;
|
||||
@@ -91,33 +91,18 @@ pub trait StorageValue<T: FullCodec> {
|
||||
|
||||
/// Append the given item to the value in the storage.
|
||||
///
|
||||
/// `T` is required to implement `codec::EncodeAppend`.
|
||||
fn append<Items, Item, EncodeLikeItem>(items: Items) -> Result<(), &'static str>
|
||||
/// `T` is required to implement [`StorageAppend`].
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// If the storage item is not encoded properly, the storage item will be overwritten
|
||||
/// and set to `[item]`. Any default value set for the storage item will be ignored
|
||||
/// on overwrite.
|
||||
fn append<Item, EncodeLikeItem>(item: EncodeLikeItem)
|
||||
where
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
T: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem>,
|
||||
Items::IntoIter: ExactSizeIterator;
|
||||
|
||||
/// Append the given items to the value in the storage.
|
||||
///
|
||||
/// `T` is required to implement `Codec::EncodeAppend`.
|
||||
///
|
||||
/// Upon any failure, it replaces `items` as the new value (assuming that the previous stored
|
||||
/// data is simply corrupt and no longer usable).
|
||||
///
|
||||
/// ### WARNING
|
||||
///
|
||||
/// use with care; if your use-case is not _exactly_ as what this function is doing,
|
||||
/// you should use append and sensibly handle failure within the runtime code if it happens.
|
||||
fn append_or_put<Items, Item, EncodeLikeItem>(items: Items) where
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
T: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<T>,
|
||||
Items::IntoIter: ExactSizeIterator;
|
||||
|
||||
T: StorageAppend<Item>;
|
||||
|
||||
/// Read the length of the value in a fast way, without decoding the entire value.
|
||||
///
|
||||
@@ -176,25 +161,18 @@ pub trait StorageMap<K: FullEncode, V: FullCodec> {
|
||||
/// Append the given items to the value in the storage.
|
||||
///
|
||||
/// `V` is required to implement `codec::EncodeAppend`.
|
||||
fn append<Items, Item, EncodeLikeItem, KeyArg>(key: KeyArg, items: Items) -> Result<(), &'static str> where
|
||||
KeyArg: EncodeLike<K>,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
V: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem>,
|
||||
Items::IntoIter: ExactSizeIterator;
|
||||
|
||||
/// Safely append the given items to the value in the storage. If a codec error occurs, then the
|
||||
/// old (presumably corrupt) value is replaced with the given `items`.
|
||||
///
|
||||
/// `V` is required to implement `codec::EncodeAppend`.
|
||||
fn append_or_insert<Items, Item, EncodeLikeItem, KeyArg>(key: KeyArg, items: Items) where
|
||||
KeyArg: EncodeLike<K>,
|
||||
/// # Warning
|
||||
///
|
||||
/// If the storage item is not encoded properly, the storage will be overwritten
|
||||
/// and set to `[item]`. Any default value set for the storage item will be ignored
|
||||
/// on overwrite.
|
||||
fn append<Item, EncodeLikeItem, EncodeLikeKey>(key: EncodeLikeKey, item: EncodeLikeItem)
|
||||
where
|
||||
EncodeLikeKey: EncodeLike<K>,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
V: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<V>,
|
||||
Items::IntoIter: ExactSizeIterator;
|
||||
V: StorageAppend<Item>;
|
||||
|
||||
/// Read the length of the value in a fast way, without decoding the entire value.
|
||||
///
|
||||
@@ -351,38 +329,23 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
|
||||
|
||||
/// Append the given item to the value in the storage.
|
||||
///
|
||||
/// `V` is required to implement `codec::EncodeAppend`.
|
||||
fn append<Items, Item, EncodeLikeItem, KArg1, KArg2>(
|
||||
k1: KArg1,
|
||||
k2: KArg2,
|
||||
items: Items,
|
||||
) -> Result<(), &'static str>
|
||||
where
|
||||
KArg1: EncodeLike<K1>,
|
||||
KArg2: EncodeLike<K2>,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
V: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem>,
|
||||
Items::IntoIter: ExactSizeIterator;
|
||||
|
||||
/// Safely append the given items to the value in the storage. If a codec error occurs, then the
|
||||
/// old (presumably corrupt) value is replaced with the given `items`.
|
||||
/// `V` is required to implement [`StorageAppend`].
|
||||
///
|
||||
/// `V` is required to implement `codec::EncodeAppend`.
|
||||
fn append_or_insert<Items, Item, EncodeLikeItem, KArg1, KArg2>(
|
||||
/// # Warning
|
||||
///
|
||||
/// If the storage item is not encoded properly, the storage will be overwritten
|
||||
/// and set to `[item]`. Any default value set for the storage item will be ignored
|
||||
/// on overwrite.
|
||||
fn append<Item, EncodeLikeItem, KArg1, KArg2>(
|
||||
k1: KArg1,
|
||||
k2: KArg2,
|
||||
items: Items,
|
||||
)
|
||||
where
|
||||
item: EncodeLikeItem,
|
||||
) where
|
||||
KArg1: EncodeLike<K1>,
|
||||
KArg2: EncodeLike<K2>,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
V: EncodeAppend<Item=Item>,
|
||||
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<V>,
|
||||
Items::IntoIter: ExactSizeIterator;
|
||||
V: StorageAppend<Item>;
|
||||
|
||||
/// Read the length of the value in a fast way, without decoding the entire value.
|
||||
///
|
||||
@@ -449,7 +412,6 @@ impl<Value: Decode> Iterator for PrefixIterator<Value> {
|
||||
/// Twox128(module_prefix) ++ Twox128(storage_prefix)
|
||||
/// ```
|
||||
pub trait StoragePrefixedMap<Value: FullCodec> {
|
||||
|
||||
/// Module prefix. Used for generating final key.
|
||||
fn module_prefix() -> &'static [u8];
|
||||
|
||||
@@ -525,6 +487,22 @@ pub trait StoragePrefixedMap<Value: FullCodec> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker trait that will be implemented for types that support the `storage::append` api.
|
||||
///
|
||||
/// This trait is sealed.
|
||||
pub trait StorageAppend<Item: Encode>: private::Sealed {}
|
||||
|
||||
/// Provides `Sealed` trait to prevent implementing trait `StorageAppend` outside of this crate.
|
||||
mod private {
|
||||
use super::*;
|
||||
|
||||
pub trait Sealed {}
|
||||
|
||||
impl<T: Encode> Sealed for Vec<T> {}
|
||||
}
|
||||
|
||||
impl<T: Encode> StorageAppend<T> for Vec<T> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use sp_core::hashing::twox_128;
|
||||
|
||||
@@ -526,50 +526,58 @@ mod test_append_and_len {
|
||||
#[test]
|
||||
fn append_works() {
|
||||
TestExternalities::default().execute_with(|| {
|
||||
let _ = MapVec::append(1, [1, 2, 3].iter());
|
||||
let _ = MapVec::append(1, [4, 5].iter());
|
||||
for val in &[1, 2, 3, 4, 5] {
|
||||
MapVec::append(1, val);
|
||||
}
|
||||
assert_eq!(MapVec::get(1), vec![1, 2, 3, 4, 5]);
|
||||
|
||||
let _ = JustVec::append([1, 2, 3].iter());
|
||||
let _ = JustVec::append([4, 5].iter());
|
||||
MapVec::remove(1);
|
||||
MapVec::append(1, 1);
|
||||
assert_eq!(MapVec::get(1), vec![1]);
|
||||
|
||||
for val in &[1, 2, 3, 4, 5] {
|
||||
JustVec::append(val);
|
||||
}
|
||||
assert_eq!(JustVec::get(), vec![1, 2, 3, 4, 5]);
|
||||
|
||||
JustVec::kill();
|
||||
JustVec::append(1);
|
||||
assert_eq!(JustVec::get(), vec![1]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_works_for_default() {
|
||||
fn append_overwrites_invalid_data() {
|
||||
TestExternalities::default().execute_with(|| {
|
||||
let key = JustVec::hashed_key();
|
||||
// Set it to some invalid value.
|
||||
frame_support::storage::unhashed::put_raw(&key, &*b"1");
|
||||
assert_eq!(JustVec::get(), Vec::new());
|
||||
assert_eq!(frame_support::storage::unhashed::get_raw(&key), Some(b"1".to_vec()));
|
||||
|
||||
JustVec::append(1);
|
||||
JustVec::append(2);
|
||||
assert_eq!(JustVec::get(), vec![1, 2]);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_overwrites_default() {
|
||||
TestExternalities::default().execute_with(|| {
|
||||
assert_eq!(JustVecWithDefault::get(), vec![6, 9]);
|
||||
let _ = JustVecWithDefault::append([1].iter());
|
||||
assert_eq!(JustVecWithDefault::get(), vec![6, 9, 1]);
|
||||
JustVecWithDefault::append(1);
|
||||
assert_eq!(JustVecWithDefault::get(), vec![1]);
|
||||
|
||||
assert_eq!(MapVecWithDefault::get(0), vec![6, 9]);
|
||||
let _ = MapVecWithDefault::append(0, [1].iter());
|
||||
assert_eq!(MapVecWithDefault::get(0), vec![6, 9, 1]);
|
||||
MapVecWithDefault::append(0, 1);
|
||||
assert_eq!(MapVecWithDefault::get(0), vec![1]);
|
||||
|
||||
assert_eq!(OptionVec::get(), None);
|
||||
let _ = OptionVec::append([1].iter());
|
||||
OptionVec::append(1);
|
||||
assert_eq!(OptionVec::get(), Some(vec![1]));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_or_put_works() {
|
||||
TestExternalities::default().execute_with(|| {
|
||||
let _ = MapVec::append_or_insert(1, &[1, 2, 3][..]);
|
||||
let _ = MapVec::append_or_insert(1, &[4, 5][..]);
|
||||
assert_eq!(MapVec::get(1), vec![1, 2, 3, 4, 5]);
|
||||
|
||||
let _ = JustVec::append_or_put(&[1, 2, 3][..]);
|
||||
let _ = JustVec::append_or_put(&[4, 5][..]);
|
||||
assert_eq!(JustVec::get(), vec![1, 2, 3, 4, 5]);
|
||||
|
||||
let _ = OptionVec::append_or_put(&[1, 2, 3][..]);
|
||||
let _ = OptionVec::append_or_put(&[4, 5][..]);
|
||||
assert_eq!(OptionVec::get(), Some(vec![1, 2, 3, 4, 5]));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len_works() {
|
||||
TestExternalities::default().execute_with(|| {
|
||||
|
||||
@@ -116,7 +116,7 @@ use sp_runtime::{
|
||||
use sp_core::{ChangesTrieConfiguration, storage::well_known_keys};
|
||||
use frame_support::{
|
||||
decl_module, decl_event, decl_storage, decl_error, Parameter, ensure, debug,
|
||||
storage::{self, generator::StorageValue},
|
||||
storage,
|
||||
traits::{
|
||||
Contains, Get, ModuleToIndex, OnNewAccount, OnKilledAccount, IsDeadAccount, Happened,
|
||||
StoredMap, EnsureOrigin,
|
||||
@@ -852,16 +852,10 @@ impl<T: Trait> Module<T> {
|
||||
old_event_count
|
||||
};
|
||||
|
||||
// We use append api here to avoid bringing all events in the runtime when we push a
|
||||
// new one in the list.
|
||||
let encoded_event = event.encode();
|
||||
sp_io::storage::append(&Events::<T>::storage_value_final_key()[..], encoded_event);
|
||||
Events::<T>::append(&event);
|
||||
|
||||
for topic in topics {
|
||||
// The same applies here.
|
||||
if <EventTopics<T>>::append(topic, &[(block_number, event_idx)]).is_err() {
|
||||
return;
|
||||
}
|
||||
<EventTopics<T>>::append(topic, &(block_number, event_idx));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user