Optional storage entries (#75)

* Block builder (substrate)

* Fix wasm build

* Bulid on any block

* Test for block builder.

* Block import tests for client.

* Tidy ups

* Repotted client

* Avoid pointless work

* All backend stuff now manages optional storage.

Also simplified a lot of the backend.

* Native runtime-io now supports empty storage items.

* Finish up the API transition.

* Build fix.

* Fix tests.

* Remerge in changes to client.

* Final fixes.

* Unrevert typos

* Remove accidentally committed change

* Bring back zero copy

* Fix merge.
This commit is contained in:
Gav Wood
2018-02-19 20:05:30 +01:00
committed by Robert Habermeier
parent 1d0ad42230
commit ec9060460c
32 changed files with 856 additions and 737 deletions
@@ -18,14 +18,34 @@
use rstd::prelude::*;
use runtime_io::{self, twox_128};
use codec::{Slicable, KeyedVec};
use codec::{Slicable, KeyedVec, Input};
// TODO: consider using blake256 to avoid possible preimage attack.
/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
struct IncrementalInput<'a> {
key: &'a [u8],
pos: usize,
}
impl<'a> Input for IncrementalInput<'a> {
fn read(&mut self, into: &mut [u8]) -> usize {
let len = runtime_io::read_storage(self.key, into, self.pos).unwrap_or(0);
let read = ::rstd::cmp::min(len, into.len());
self.pos += read;
read
}
}
/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
pub fn get<T: Slicable + Sized>(key: &[u8]) -> Option<T> {
let raw = runtime_io::storage(&twox_128(key)[..]);
Slicable::decode(&mut &raw[..])
let key = twox_128(key);
runtime_io::read_storage(&key[..], &mut [0; 0][..], 0).map(|_| {
let mut input = IncrementalInput {
key: &key[..],
pos: 0,
};
Slicable::decode(&mut input).expect("stroage is not null, therefore must be a valid type")
})
}
/// Return the value of the item in storage under `key`, or the type's default if there is no
@@ -85,17 +105,17 @@ pub fn take_or_else<T: Slicable + Sized, F: FnOnce() -> T>(key: &[u8], default_v
/// Check to see if `key` has an explicit entry in storage.
pub fn exists(key: &[u8]) -> bool {
let mut x = [0u8; 1];
runtime_io::read_storage(&twox_128(key)[..], &mut x[..], 0) >= 1
let mut x = [0u8; 0];
runtime_io::read_storage(&twox_128(key)[..], &mut x[..], 0).is_some()
}
/// Ensure `key` has no explicit entry in storage.
pub fn kill(key: &[u8]) {
runtime_io::set_storage(&twox_128(key)[..], b"");
runtime_io::clear_storage(&twox_128(key)[..]);
}
/// Get a Vec of bytes from storage.
pub fn get_raw(key: &[u8]) -> Vec<u8> {
pub fn get_raw(key: &[u8]) -> Option<Vec<u8>> {
runtime_io::storage(&twox_128(key)[..])
}
@@ -127,12 +147,18 @@ pub trait StorageVec {
}
}
fn clear_item(index: u32) {
if index < Self::count() {
kill(&index.to_keyed_vec(Self::PREFIX));
}
}
fn item(index: u32) -> Self::Item {
get_or_default(&index.to_keyed_vec(Self::PREFIX))
}
fn set_count(count: u32) {
(count..Self::count()).for_each(|i| Self::set_item(i, &Self::Item::default()));
(count..Self::count()).for_each(Self::clear_item);
put(&b"len".to_keyed_vec(Self::PREFIX), &count);
}
@@ -142,12 +168,17 @@ pub trait StorageVec {
}
pub mod unhashed {
use super::{runtime_io, Slicable, KeyedVec, Vec};
use super::{runtime_io, Slicable, KeyedVec, Vec, IncrementalInput};
/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
pub fn get<T: Slicable + Sized>(key: &[u8]) -> Option<T> {
let raw = runtime_io::storage(key);
T::decode(&mut &raw[..])
runtime_io::read_storage(key, &mut [0; 0][..], 0).map(|_| {
let mut input = IncrementalInput {
key,
pos: 0,
};
Slicable::decode(&mut input).expect("stroage is not null, therefore must be a valid type")
})
}
/// Return the value of the item in storage under `key`, or the type's default if there is no
@@ -207,17 +238,16 @@ pub mod unhashed {
/// Check to see if `key` has an explicit entry in storage.
pub fn exists(key: &[u8]) -> bool {
let mut x = [0u8; 1];
runtime_io::read_storage(key, &mut x[..], 0) >= 1
runtime_io::read_storage(key, &mut [0;0][..], 0).is_some()
}
/// Ensure `key` has no explicit entry in storage.
pub fn kill(key: &[u8]) {
runtime_io::set_storage(key, b"");
runtime_io::clear_storage(key);
}
/// Get a Vec of bytes from storage.
pub fn get_raw(key: &[u8]) -> Vec<u8> {
pub fn get_raw(key: &[u8]) -> Option<Vec<u8>> {
runtime_io::storage(key)
}
@@ -249,12 +279,18 @@ pub mod unhashed {
}
}
fn clear_item(index: u32) {
if index < Self::count() {
kill(&index.to_keyed_vec(Self::PREFIX));
}
}
fn item(index: u32) -> Self::Item {
get_or_default(&index.to_keyed_vec(Self::PREFIX))
}
fn set_count(count: u32) {
(count..Self::count()).for_each(|i| Self::set_item(i, &Self::Item::default()));
(count..Self::count()).for_each(Self::clear_item);
put(&b"len".to_keyed_vec(Self::PREFIX), &count);
}
@@ -267,13 +303,12 @@ pub mod unhashed {
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
use primitives::hexdisplay::HexDisplay;
use runtime_io::{storage, twox_128, TestExternalities, with_externalities};
#[test]
fn integers_can_be_stored() {
let mut t = TestExternalities { storage: HashMap::new(), };
let mut t = TestExternalities::new();
with_externalities(&mut t, || {
let x = 69u32;
put(b":test", &x);
@@ -290,7 +325,7 @@ mod tests {
#[test]
fn bools_can_be_stored() {
let mut t = TestExternalities { storage: HashMap::new(), };
let mut t = TestExternalities::new();
with_externalities(&mut t, || {
let x = true;
put(b":test", &x);
@@ -308,11 +343,11 @@ mod tests {
#[test]
fn vecs_can_be_retrieved() {
let mut t = TestExternalities { storage: HashMap::new(), };
let mut t = TestExternalities::new();
with_externalities(&mut t, || {
runtime_io::set_storage(&twox_128(b":test"), b"\x0b\0\0\0Hello world");
let x = b"Hello world".to_vec();
println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test"))));
println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test")).unwrap()));
let y = get::<Vec<u8>>(b":test").unwrap();
assert_eq!(x, y);
@@ -321,7 +356,7 @@ mod tests {
#[test]
fn vecs_can_be_stored() {
let mut t = TestExternalities { storage: HashMap::new(), };
let mut t = TestExternalities::new();
let x = b"Hello world".to_vec();
with_externalities(&mut t, || {
@@ -330,7 +365,7 @@ mod tests {
println!("Ext is {:?}", t);
with_externalities(&mut t, || {
println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test"))));
println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test")).unwrap()));
let y: Vec<u8> = get(b":test").unwrap();
assert_eq!(x, y);
});