no_std support for substrate trie (#2146)

* no_std trie compile in test_runtime (require to set nightly feature due
to the way hashbrown currently works).

* No nightly with hashmap_core.

* using crate elastic-array

* switch to publish trie crates

* fix default array decl

* bump impl_version for ci

* set all semver when possible wasm, and remove redundant code.

* Actually test use_trie function

* impl version +1

* Bump impl version
This commit is contained in:
cheme
2019-04-02 12:49:04 +02:00
committed by Bastian Köcher
parent 728f0393c7
commit 669e79181e
16 changed files with 150 additions and 65 deletions
+6 -6
View File
@@ -18,7 +18,7 @@ state-machine = { package = "substrate-state-machine", path = "../state-machine"
keyring = { package = "substrate-keyring", path = "../keyring", optional = true }
trie = { package = "substrate-trie", path = "../trie", optional = true }
substrate-telemetry = { path = "../telemetry", optional = true }
hash-db = { version = "0.12", optional = true }
hash-db = { version = "0.12.2", default-features = false }
kvdb = { git = "https://github.com/paritytech/parity-common", optional = true, rev="b0317f649ab2c665b7987b8475878fc4d2e1f81d" }
parity-codec = { version = "3.3", default-features = false, features = ["derive"] }
primitives = { package = "substrate-primitives", path = "../primitives", default-features = false }
@@ -35,10 +35,14 @@ kvdb-memorydb = { git = "https://github.com/paritytech/parity-common", rev="b031
[features]
default = ["std"]
std = [
"rstd/std",
"parity-codec/std",
"consensus",
"primitives/std",
"inherents/std",
"runtime-primitives/std",
"runtime-version/std",
"hash-db/std",
"consensus",
"parking_lot",
"error-chain",
"fnv",
@@ -47,13 +51,9 @@ std = [
"futures",
"heapsize",
"executor",
"runtime-primitives/std",
"runtime-version/std",
"rstd/std",
"state-machine",
"keyring",
"trie",
"substrate-telemetry",
"hash-db",
"kvdb"
]
@@ -106,3 +106,11 @@ fn calling_with_native_else_wasm_and_fail_on_native_should_work() {
let block_id = BlockId::Number(client.info().unwrap().chain.best_number);
assert_eq!(runtime_api.fail_on_native(&block_id).unwrap(), 1);
}
#[test]
fn use_trie_function() {
let client = test_client::new_with_execution_strategy(ExecutionStrategy::AlwaysWasm);
let runtime_api = client.runtime_api();
let block_id = BlockId::Number(client.info().unwrap().chain.best_number);
assert_eq!(runtime_api.use_trie(&block_id).unwrap(), 2);
}
+1 -2
View File
@@ -25,11 +25,10 @@ std = [
"primitives/std",
"parity-codec/std",
"rstd/std",
"hash-db/std",
"trie",
"environmental",
"substrate-state-machine",
"trie",
"libsecp256k1",
"tiny-keccak"
]
+1
View File
@@ -30,6 +30,7 @@ pub use std::ptr;
pub use std::rc;
pub use std::slice;
pub use std::vec;
pub use std::default;
pub use std::result;
pub mod collections {
+1
View File
@@ -61,6 +61,7 @@ pub use core::num;
pub use core::ops;
pub use core::ptr;
pub use core::slice;
pub use core::default;
pub use core::result;
// We are trying to avoid certain things here, such as `core::string`
// (if you need `String` you most probably doing something wrong, since
+7
View File
@@ -20,6 +20,9 @@ runtime_io = { package = "sr-io", path = "../sr-io", default-features = false }
runtime_primitives = { package = "sr-primitives", path = "../sr-primitives", default-features = false }
runtime_version = { package = "sr-version", path = "../sr-version", default-features = false }
runtime_support = { package = "srml-support", path = "../../srml/support", default-features = false }
substrate-trie = { path = "../trie", default-features = false }
trie-db = { version = "0.12", default-features = false }
memory-db = { version = "0.12", default-features = false }
offchain-primitives = { package = "substrate-offchain-primitives", path = "../offchain/primitives", default-features = false}
executive = { package = "srml-executive", path = "../../srml/executive", default-features = false }
cfg-if = "0.1.6"
@@ -47,6 +50,10 @@ std = [
"runtime_primitives/std",
"runtime_version/std",
"consensus_aura/std",
"primitives/std",
"substrate-trie/std",
"trie-db/std",
"memory-db/std",
"offchain-primitives/std",
"executive/std",
]
+51 -1
View File
@@ -25,6 +25,10 @@ pub mod system;
use rstd::{prelude::*, marker::PhantomData};
use parity_codec::{Encode, Decode, Input};
use primitives::Blake2Hasher;
use trie_db::{TrieMut, Trie};
use substrate_trie::{TrieDB, TrieDBMut, PrefixedMemoryDB};
use substrate_client::{
runtime_api as client_api, block_builder::api as block_builder_api, decl_runtime_apis,
impl_runtime_apis,
@@ -232,6 +236,8 @@ cfg_if! {
fn function_signature_changed() -> u64;
fn fail_on_native() -> u64;
fn fail_on_wasm() -> u64;
/// trie no_std testing
fn use_trie() -> u64;
fn benchmark_indirect_call() -> u64;
fn benchmark_direct_call() -> u64;
}
@@ -254,6 +260,8 @@ cfg_if! {
fn function_signature_changed() -> Vec<u64>;
fn fail_on_native() -> u64;
fn fail_on_wasm() -> u64;
/// trie no_std testing
fn use_trie() -> u64;
fn benchmark_indirect_call() -> u64;
fn benchmark_direct_call() -> u64;
}
@@ -281,6 +289,37 @@ fn benchmark_add_one(i: u64) -> u64 {
#[cfg(not(feature = "std"))]
static BENCHMARK_ADD_ONE: runtime_io::ExchangeableFunction<fn(u64) -> u64> = runtime_io::ExchangeableFunction::new(benchmark_add_one);
fn code_using_trie() -> u64 {
let pairs = [
(b"0103000000000000000464".to_vec(), b"0400000000".to_vec()),
(b"0103000000000000000469".to_vec(), b"0401000000".to_vec()),
].to_vec();
let mut mdb = PrefixedMemoryDB::default();
let mut root = rstd::default::Default::default();
let _ = {
let v = &pairs;
let mut t = TrieDBMut::<Blake2Hasher>::new(&mut mdb, &mut root);
for i in 0..v.len() {
let key: &[u8]= &v[i].0;
let val: &[u8] = &v[i].1;
t.insert(key, val).expect("static input");
}
t
};
let trie = TrieDB::<Blake2Hasher>::new(&mdb, &root).expect("on memory with static content");
let iter = trie.iter().expect("static input");
let mut iter_pairs = Vec::new();
for pair in iter {
let (key, value) = pair.expect("on memory with static content");
iter_pairs.push((key, value.to_vec()));
}
iter_pairs.len() as u64
}
cfg_if! {
if #[cfg(feature = "std")] {
impl_runtime_apis! {
@@ -367,6 +406,11 @@ cfg_if! {
fn fail_on_wasm() -> u64 {
1
}
fn use_trie() -> u64 {
code_using_trie()
}
fn benchmark_indirect_call() -> u64 {
let function = benchmark_add_one;
(0..1000).fold(0, |p, i| p + function(i))
@@ -483,6 +527,10 @@ cfg_if! {
panic!("Failing because we are on wasm")
}
fn use_trie() -> u64 {
code_using_trie()
}
fn benchmark_indirect_call() -> u64 {
(0..10000).fold(0, |p, i| p + BENCHMARK_ADD_ONE.get()(i))
}
@@ -492,6 +540,8 @@ cfg_if! {
}
}
impl consensus_aura::AuraApi<Block> for Runtime {
fn slot_duration() -> u64 { 1 }
}
@@ -510,4 +560,4 @@ cfg_if! {
}
}
}
}
}
+10 -7
View File
@@ -12,11 +12,12 @@ name = "bench"
harness = false
[dependencies]
codec = { package = "parity-codec", version = "3.2" }
hash-db = { version = "0.12", default-features = false }
trie-db = { version = "0.12", optional = true }
trie-root = { version = "0.12", default-features = false }
memory-db = { version = "0.12", optional = true }
codec = { package = "parity-codec", version = "3.2", default-features = false }
rstd = { package = "sr-std", path = "../sr-std", default-features = false }
hash-db = { version = "0.12.2", default-features = false }
trie-db = { version = "0.12.2", default-features = false }
trie-root = { version = "0.12.2", default-features = false }
memory-db = { version = "0.12.2", default-features = false }
[dev-dependencies]
substrate-primitives = { path = "../primitives" }
@@ -29,8 +30,10 @@ hex-literal = "0.1.0"
[features]
default = ["std"]
std = [
"rstd/std",
"codec/std",
"hash-db/std",
"memory-db",
"trie-db",
"memory-db/std",
"trie-db/std",
"trie-root/std"
]
+4
View File
@@ -6,7 +6,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[cfg(feature="std")]
use std::fmt;
#[cfg(feature="std")]
use std::error::Error as StdError;
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -16,12 +18,14 @@ pub enum Error {
BadFormat,
}
#[cfg(feature="std")]
impl StdError for Error {
fn description(&self) -> &str {
"codec error"
}
}
#[cfg(feature="std")]
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self, f)
+5 -2
View File
@@ -16,13 +16,16 @@
//! Utility functions to interact with Substrate's Base-16 Modified Merkle Patricia tree ("trie").
// FIXME: no_std - https://github.com/paritytech/substrate/issues/1574
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]
mod error;
mod node_header;
mod node_codec;
mod trie_stream;
use rstd::boxed::Box;
use rstd::vec::Vec;
use hash_db::Hasher;
/// Our `NodeCodec`-specific error.
pub use error::Error;
@@ -290,7 +293,7 @@ fn take<'a>(input: &mut &'a[u8], count: usize) -> Option<&'a[u8]> {
fn partial_to_key(partial: &[u8], offset: u8, big: u8) -> Vec<u8> {
let nibble_count = (partial.len() - 1) * 2 + if partial[0] & 16 == 16 { 1 } else { 0 };
let (first_byte_small, big_threshold) = (offset, (big - offset) as usize);
let mut output = vec![first_byte_small + nibble_count.min(big_threshold) as u8];
let mut output = [first_byte_small + nibble_count.min(big_threshold) as u8].to_vec();
if nibble_count >= big_threshold { output.push((nibble_count - big_threshold) as u8) }
if nibble_count % 2 == 1 {
output.push(partial[0] & 0x0f);
+5 -8
View File
@@ -16,7 +16,8 @@
//! `NodeCodec` implementation for Substrate's trie format.
use std::marker::PhantomData;
use rstd::marker::PhantomData;
use rstd::vec::Vec;
use codec::{Encode, Decode, Compact};
use hash_db::Hasher;
use trie_db::{self, DBValue, NibbleSlice, node::Node, ChildReference};
@@ -28,10 +29,6 @@ use super::{EMPTY_TRIE, LEAF_NODE_OFFSET, LEAF_NODE_BIG, EXTENSION_NODE_OFFSET,
#[derive(Default, Clone)]
pub struct NodeCodec<H: Hasher>(PhantomData<H>);
// NOTE: what we'd really like here is:
// `impl<H: Hasher> NodeCodec<H> for RlpNodeCodec<H> where H::Out: Decodable`
// but due to the current limitations of Rust const evaluation we can't
// do `const HASHED_NULL_NODE: H::Out = H::Out( … … )`. Perhaps one day soon?
impl<H: Hasher> trie_db::NodeCodec<H> for NodeCodec<H> {
type Error = Error;
@@ -39,7 +36,7 @@ impl<H: Hasher> trie_db::NodeCodec<H> for NodeCodec<H> {
H::hash(&[0u8][..])
}
fn decode(data: &[u8]) -> ::std::result::Result<Node, Self::Error> {
fn decode(data: &[u8]) -> ::rstd::result::Result<Node, Self::Error> {
use Error::BadFormat;
let input = &mut &*data;
match NodeHeader::decode(input).ok_or(BadFormat)? {
@@ -92,7 +89,7 @@ impl<H: Hasher> trie_db::NodeCodec<H> for NodeCodec<H> {
data == &[EMPTY_TRIE][..]
}
fn empty_node() -> Vec<u8> {
vec![EMPTY_TRIE]
[EMPTY_TRIE].to_vec()
}
// FIXME: refactor this so that `partial` isn't already encoded with HPE. Should just be an `impl Iterator<Item=u8>`.
@@ -117,7 +114,7 @@ impl<H: Hasher> trie_db::NodeCodec<H> for NodeCodec<H> {
fn branch_node<I>(children: I, maybe_value: Option<DBValue>) -> Vec<u8>
where I: IntoIterator<Item=Option<ChildReference<H::Out>>> + Iterator<Item=Option<ChildReference<H::Out>>>
{
let mut output = vec![0, 0, 0];
let mut output = [0, 0, 0].to_vec();
let have_value = if let Some(value) = maybe_value {
(&*value).encode_to(&mut output);
true
+2 -1
View File
@@ -16,10 +16,11 @@
//! `TrieStream` implementation for Substrate's trie format.
use std::iter::once;
use rstd::iter::once;
use hash_db::Hasher;
use trie_root;
use codec::Encode;
use rstd::vec::Vec;
use super::{EMPTY_TRIE, LEAF_NODE_OFFSET, LEAF_NODE_BIG, EXTENSION_NODE_OFFSET,
EXTENSION_NODE_BIG, branch_node};