diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index 97d1b88cc2..6bc118bdc0 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -59,7 +59,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_name: create_runtime_str!("substrate-node"), authoring_version: 10, spec_version: 88, - impl_version: 88, + impl_version: 89, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/srml/support/procedural/src/storage/impls.rs b/substrate/srml/support/procedural/src/storage/impls.rs index 720ed21c24..0e9e30e2a4 100644 --- a/substrate/srml/support/procedural/src/storage/impls.rs +++ b/substrate/srml/support/procedural/src/storage/impls.rs @@ -225,8 +225,11 @@ impl<'a, I: Iterator> Impls<'a, I> { #mutate_impl ; ret } - } + + impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> + #scrate::storage::hashed::generator::AppendableStorageMap<#kty, #typ> for #name<#traitinstance, #instance> + {} } } diff --git a/substrate/srml/support/src/lib.rs b/substrate/srml/support/src/lib.rs index 4f749d4c89..0931e4c5a3 100644 --- a/substrate/srml/support/src/lib.rs +++ b/substrate/srml/support/src/lib.rs @@ -57,7 +57,9 @@ pub mod unsigned; mod double_map; pub mod traits; -pub use self::storage::{StorageList, StorageValue, StorageMap, EnumerableStorageMap, StorageDoubleMap}; +pub use self::storage::{ + StorageList, StorageValue, StorageMap, EnumerableStorageMap, StorageDoubleMap, AppendableStorageMap +}; pub use self::hashable::Hashable; pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType}; pub use self::double_map::StorageDoubleMapWithHasher; diff --git a/substrate/srml/support/src/storage/child.rs b/substrate/srml/support/src/storage/child.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/substrate/srml/support/src/storage/hashed/generator.rs b/substrate/srml/support/src/storage/hashed/generator.rs index fb876a2adb..1cc62c69f7 100644 --- a/substrate/srml/support/src/storage/hashed/generator.rs +++ b/substrate/srml/support/src/storage/hashed/generator.rs @@ -281,5 +281,25 @@ pub trait EnumerableStorageMap: StorageMap>(storage: &S) -> Option; /// Enumerate all elements in the map. - fn enumerate<'a, S: HashedStorage>(storage: &'a S) -> Box + 'a> where K: 'a, V: 'a; + fn enumerate<'a, S: HashedStorage>( + storage: &'a S + ) -> Box + 'a> where K: 'a, V: 'a; +} + +/// A `StorageMap` with appendable entries. +pub trait AppendableStorageMap: StorageMap { + /// Append the given items to the value in the storage. + /// + /// `T` is required to implement `codec::EncodeAppend`. + fn append, I: codec::Encode>( + key : &K, items: &[I], storage: &mut S + ) -> Result<(), &'static str> where V: codec::EncodeAppend { + let k = Self::key_for(key); + let new_val = ::append( + storage.get_raw(&k[..]).unwrap_or_default(), + items, + ).ok_or_else(|| "Could not append given item")?; + storage.put_raw(&k[..], &new_val); + Ok(()) + } } diff --git a/substrate/srml/support/src/storage/mod.rs b/substrate/srml/support/src/storage/mod.rs index 635572c991..41ea4cfdbc 100644 --- a/substrate/srml/support/src/storage/mod.rs +++ b/substrate/srml/support/src/storage/mod.rs @@ -330,6 +330,25 @@ impl StorageMap for U where U: hashed::generator::S } } +/// A storage map with values that can be appended to. +pub trait AppendableStorageMap: StorageMap { + /// Append the given item to the value in the storage. + /// + /// `T` is required to implement `codec::EncodeAppend`. + fn append, I: Encode>(key: KeyArg, items: &[I]) -> Result<(), &'static str> + where V: EncodeAppend; +} + +impl AppendableStorageMap for U + where U: hashed::generator::AppendableStorageMap +{ + fn append, I: Encode>(key: KeyArg, items: &[I]) -> Result<(), &'static str> + where V: EncodeAppend + { + U::append(key.borrow(), items, &mut RuntimeStorage) + } +} + /// A storage map that can be enumerated. /// /// Primarily useful for off-chain computations. @@ -342,7 +361,9 @@ pub trait EnumerableStorageMap: StorageMap { fn enumerate() -> Box> where K: 'static, V: 'static; } -impl EnumerableStorageMap for U where U: hashed::generator::EnumerableStorageMap { +impl EnumerableStorageMap for U + where U: hashed::generator::EnumerableStorageMap +{ fn head() -> Option { >::head(&RuntimeStorage) } diff --git a/substrate/srml/support/src/storage/storage_items.rs b/substrate/srml/support/src/storage/storage_items.rs index 802965fc27..2e7a8d4bb4 100644 --- a/substrate/srml/support/src/storage/storage_items.rs +++ b/substrate/srml/support/src/storage/storage_items.rs @@ -900,3 +900,46 @@ mod test3 { type BlockNumber = u32; } } + +#[cfg(test)] +#[allow(dead_code)] +mod test_map_vec_append { + pub trait Trait { + type Origin; + type BlockNumber; + } + decl_module! { + pub struct Module for enum Call where origin: T::Origin {} + } + crate::decl_storage! { + trait Store for Module as Test { + JustVec: Vec; + MapVec: map u32 => Vec; + } + } + + struct Test {} + + impl Trait for Test { + type Origin = u32; + type BlockNumber = u32; + } + + #[test] + fn append_works() { + use crate::storage::{AppendableStorageMap, StorageMap, StorageValue}; + use runtime_io::{with_externalities, TestExternalities}; + + with_externalities(&mut TestExternalities::default(), || { + let _ = >::append(1, &[1, 2, 3]); + let _ = >::append(1, &[4, 5]); + assert_eq!(>::get(1), vec![1, 2, 3, 4, 5]); + + let _ = >::append(&[1, 2, 3]); + let _ = >::append(&[4, 5]); + assert_eq!(>::get(), vec![1, 2, 3, 4, 5]); + }); + } +} + +