Merge branch 'master' into split-substrate

This commit is contained in:
Robert Habermeier
2018-08-15 13:24:27 +02:00
82 changed files with 1677 additions and 689 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
/target/
**/target/
**/*.rs.bk
*.swp
.wasm-binaries
+233 -212
View File
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -59,6 +59,7 @@ use demo_executor::NativeExecutor;
struct DummyPool;
impl extrinsic_pool::api::ExtrinsicPool<UncheckedExtrinsic, BlockId, Hash> for DummyPool {
type Error = extrinsic_pool::txpool::Error;
type InPool = ();
fn submit(&self, _block: BlockId, _: Vec<UncheckedExtrinsic>)
-> Result<Vec<Hash>, Self::Error>
@@ -79,6 +80,10 @@ impl extrinsic_pool::api::ExtrinsicPool<UncheckedExtrinsic, BlockId, Hash> for D
fn import_notification_stream(&self) -> extrinsic_pool::api::EventStream {
unreachable!()
}
fn all(&self) -> Self::InPool {
unreachable!()
}
}
struct DummySystem;
@@ -176,7 +181,7 @@ pub fn run<I, T>(args: I) -> error::Result<()> where
let state = rpc::apis::state::State::new(client.clone(), runtime.executor());
let chain = rpc::apis::chain::Chain::new(client.clone(), runtime.executor());
let author = rpc::apis::author::Author::new(client.clone(), Arc::new(DummyPool), runtime.executor());
rpc::rpc_handler::<Block, _, _, _, _>(state, chain, author, DummySystem)
rpc::rpc_handler::<Block, _, _, _, _, _>(state, chain, author, DummySystem)
};
let http_address = "127.0.0.1:9933".parse().unwrap();
let ws_address = "127.0.0.1:9944".parse().unwrap();
+56 -14
View File
@@ -47,7 +47,7 @@ mod tests {
use keyring::Keyring;
use runtime_support::{Hashable, StorageValue, StorageMap};
use state_machine::{CodeExecutor, TestExternalities};
use primitives::twox_128;
use primitives::{twox_128, KeccakHasher};
use demo_primitives::{Hash, BlockNumber, AccountId};
use runtime_primitives::traits::Header as HeaderT;
use runtime_primitives::{ApplyOutcome, ApplyError, ApplyResult, MaybeUnsigned};
@@ -100,7 +100,7 @@ mod tests {
#[test]
fn panic_execution_with_foreign_code_gives_error() {
let mut t: TestExternalities = map![
let mut t: TestExternalities<KeccakHasher> = map![
twox_128(&<staking::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<staking::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![70u8; 8],
twox_128(<staking::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
@@ -119,7 +119,7 @@ mod tests {
#[test]
fn bad_extrinsic_with_native_equivalent_code_gives_error() {
let mut t: TestExternalities = map![
let mut t: TestExternalities<KeccakHasher> = map![
twox_128(&<staking::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<staking::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![70u8; 8],
twox_128(<staking::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
@@ -138,7 +138,7 @@ mod tests {
#[test]
fn successful_execution_with_native_equivalent_code_gives_ok() {
let mut t: TestExternalities = map![
let mut t: TestExternalities<KeccakHasher> = map![
twox_128(&<staking::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<staking::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<staking::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
@@ -161,7 +161,7 @@ mod tests {
#[test]
fn successful_execution_with_foreign_code_gives_ok() {
let mut t: TestExternalities = map![
let mut t: TestExternalities<KeccakHasher> = map![
twox_128(&<staking::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<staking::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<staking::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
@@ -182,7 +182,7 @@ mod tests {
});
}
fn new_test_ext() -> TestExternalities {
fn new_test_ext() -> TestExternalities<KeccakHasher> {
use keyring::Keyring::*;
let three = [3u8; 32].into();
GenesisConfig {
@@ -212,7 +212,7 @@ mod tests {
democracy: Some(Default::default()),
council: Some(Default::default()),
timestamp: Some(Default::default()),
}.build_storage().unwrap()
}.build_storage().unwrap().into()
}
fn construct_block(number: BlockNumber, parent_hash: Hash, state_root: Hash, extrinsics: Vec<BareExtrinsic>) -> (Vec<u8>, Hash) {
@@ -247,7 +247,10 @@ mod tests {
construct_block(
1,
[69u8; 32].into(),
hex!("b97d52254fc967bb94bed485de6a738e9fad05decfda3453711677b8becf6d0a").into(),
// Blake
// hex!("3437bf4b182ab17bb322af5c67e55f6be487a77084ad2b4e27ddac7242e4ad21").into(),
// Keccak
hex!("c563199c60df7d914262b1775b284870f3a5da2f24b56d2c6288b37c815a6cd9").into(),
vec![BareExtrinsic {
signed: alice(),
index: 0,
@@ -260,7 +263,43 @@ mod tests {
construct_block(
2,
block1().1,
hex!("a1f018d2faa339f72f5ee29050b4670d971e2e271cc06c41ee9cbe1f4c6feec9").into(),
// Blake
// hex!("741fcb660e6fa9f625fbcd993b49f6c1cc4040f5e0cc8727afdedf11fd3c464b").into(),
// Keccak
hex!("83f71d5475f63350825b0301de322233d3711a9f3fcfd74050d1534af47a36b3").into(),
vec![
BareExtrinsic {
signed: bob(),
index: 0,
function: Call::Staking(staking::Call::transfer(alice().into(), 5)),
},
BareExtrinsic {
signed: alice(),
index: 1,
function: Call::Staking(staking::Call::transfer(bob().into(), 15)),
}
]
)
}
fn block1_wasm() -> (Vec<u8>, Hash) {
construct_block(
1,
[69u8; 32].into(),
hex!("b97d52254fc967bb94bed485de6a738e9fad05decfda3453711677b8becf6d0a").into(),
vec![BareExtrinsic {
signed: alice(),
index: 0,
function: Call::Staking(staking::Call::transfer(bob().into(), 69)),
}]
)
}
fn block2_wasm() -> (Vec<u8>, Hash) {
construct_block(
2,
block1().1,
hex!("b820fe09935dba41d200b627c11bd7dd9ebff39c319dee18be3ee4f99fc1eab4").into(),
vec![
BareExtrinsic {
signed: bob(),
@@ -280,7 +319,10 @@ mod tests {
construct_block(
1,
[69u8; 32].into(),
hex!("41d07010f49aa29b2c9aca542cbaa6f59aafd3dda53cdf711c51ddb7d386912e").into(),
// Blake
// hex!("2c7231a9c210a7aa4bea169d944bc4aaacd517862b244b8021236ffa7f697991").into(),
// Keccak
hex!("06d026c0d687ec583660a6052de6f89acdb24ea964d06be3831c837c3c426966").into(),
vec![BareExtrinsic {
signed: alice(),
index: 0,
@@ -312,14 +354,14 @@ mod tests {
fn full_wasm_block_import_works() {
let mut t = new_test_ext();
WasmExecutor::new(8).call(&mut t, COMPACT_CODE, "execute_block", &block1().0).unwrap();
WasmExecutor::new(8).call(&mut t, COMPACT_CODE, "execute_block", &block1_wasm().0).unwrap();
runtime_io::with_externalities(&mut t, || {
assert_eq!(Staking::voting_balance(&alice()), 41);
assert_eq!(Staking::voting_balance(&bob()), 69);
});
WasmExecutor::new(8).call(&mut t, COMPACT_CODE, "execute_block", &block2().0).unwrap();
WasmExecutor::new(8).call(&mut t, COMPACT_CODE, "execute_block", &block2_wasm().0).unwrap();
runtime_io::with_externalities(&mut t, || {
assert_eq!(Staking::voting_balance(&alice()), 30);
@@ -353,7 +395,7 @@ mod tests {
#[test]
fn panic_execution_gives_error() {
let mut t: TestExternalities = map![
let mut t: TestExternalities<KeccakHasher> = map![
twox_128(&<staking::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<staking::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![70u8; 8],
twox_128(<staking::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
@@ -373,7 +415,7 @@ mod tests {
#[test]
fn successful_execution_gives_ok() {
let mut t: TestExternalities = map![
let mut t: TestExternalities<KeccakHasher> = map![
twox_128(&<staking::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<staking::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<staking::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
+1
View File
@@ -22,6 +22,7 @@ tokio = "0.1.7"
futures = "0.1.17"
fdlimit = "0.1"
exit-future = "0.1"
sysinfo = "0.5.7"
substrate-client = { path = "../../substrate/client" }
substrate-extrinsic-pool = { path = "../../substrate/extrinsic-pool" }
substrate-network = { path = "../../substrate/network" }
+15 -1
View File
@@ -22,6 +22,7 @@ use futures::{Future, Stream};
use service::{Service, Components};
use tokio::runtime::TaskExecutor;
use tokio::timer::Interval;
use sysinfo::{get_current_pid, ProcessExt, System, SystemExt};
use network::{SyncState, SyncProvider};
use client::BlockchainEvents;
use runtime_primitives::traits::{Header, As};
@@ -41,6 +42,9 @@ pub fn start<C>(service: &Service<C>, exit: ::exit_future::Exit, handle: TaskExe
let txpool = service.extrinsic_pool();
let mut last_number = None;
let mut sys = System::new();
let self_pid = get_current_pid();
let display_notifications = interval.map_err(|e| debug!("Timer error: {:?}", e)).for_each(move |_| {
let sync_status = network.status();
@@ -65,17 +69,27 @@ pub fn start<C>(service: &Service<C>, exit: ::exit_future::Exit, handle: TaskExe
Colour::White.paint(format!("{}", best_number)),
hash
);
// get cpu usage and memory usage of this process
let (cpu_usage, memory) = if sys.refresh_process(self_pid) {
let proc = sys.get_process(self_pid).expect("Above refresh_process succeeds, this should be Some(), qed");
(proc.cpu_usage(), proc.memory())
} else { (0.0, 0) };
telemetry!(
"system.interval";
"status" => format!("{}{}", status, target),
"peers" => num_peers,
"height" => best_number,
"best" => ?hash,
"txcount" => txpool_status.transaction_count
"txcount" => txpool_status.transaction_count,
"cpu" => cpu_usage,
"memory" => memory
);
} else {
warn!("Error getting best block information");
}
Ok(())
});
+1
View File
@@ -30,6 +30,7 @@ extern crate futures;
extern crate tokio;
extern crate names;
extern crate backtrace;
extern crate sysinfo;
extern crate substrate_client as client;
extern crate substrate_network as network;
+4
View File
@@ -13,6 +13,7 @@ hex-literal = "0.1"
futures = "0.1.17"
ed25519 = { path = "../ed25519" }
slog = "^2"
heapsize = "0.4"
substrate-bft = { path = "../bft" }
substrate-codec = { path = "../codec" }
substrate-executor = { path = "../executor" }
@@ -23,6 +24,9 @@ substrate-runtime-primitives = { path = "../runtime/primitives" }
substrate-state-machine = { path = "../state-machine" }
substrate-keyring = { path = "../../substrate/keyring" }
substrate-telemetry = { path = "../telemetry" }
hashdb = { git = "https://github.com/paritytech/parity-common" }
patricia-trie = { git = "https://github.com/paritytech/parity-common" }
rlp = { git = "https://github.com/paritytech/parity-common" }
[dev-dependencies]
substrate-test-client = { path = "../test-client" }
+5 -7
View File
@@ -6,12 +6,10 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
parking_lot = "0.4"
log = "0.3"
kvdb = { git = "https://github.com/paritytech/parity.git" }
kvdb-rocksdb = { git = "https://github.com/paritytech/parity.git" }
ethereum-types = "0.3"
hashdb = { git = "https://github.com/paritytech/parity.git" }
patricia-trie = { git = "https://github.com/paritytech/parity.git" }
memorydb = { git = "https://github.com/paritytech/parity.git" }
kvdb = { git = "https://github.com/paritytech/parity-common" }
kvdb-rocksdb = { git = "https://github.com/paritytech/parity-common" }
hashdb = { git = "https://github.com/paritytech/parity-common" }
memorydb = { git = "https://github.com/paritytech/parity-common" }
substrate-primitives = { path = "../../../substrate/primitives" }
substrate-runtime-primitives = { path = "../../../substrate/runtime/primitives" }
substrate-client = { path = "../../../substrate/client" }
@@ -23,4 +21,4 @@ substrate-executor = { path = "../../../substrate/executor" }
substrate-state-db = { path = "../../../substrate/state-db" }
[dev-dependencies]
kvdb-memorydb = { git = "https://github.com/paritytech/parity.git" }
kvdb-memorydb = { git = "https://github.com/paritytech/parity-common" }
+23 -18
View File
@@ -46,19 +46,21 @@ mod utils;
use std::sync::Arc;
use std::path::PathBuf;
use std::io;
use codec::{Decode, Encode};
use hashdb::Hasher;
use kvdb::{KeyValueDB, DBTransaction};
use memorydb::MemoryDB;
use parking_lot::RwLock;
use primitives::{H256, AuthorityId};
use primitives::{H256, AuthorityId, KeccakHasher, RlpCodec};
use runtime_primitives::generic::BlockId;
use runtime_primitives::bft::Justification;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, Hash, HashFor, NumberFor, Zero};
use runtime_primitives::BuildStorage;
use state_machine::backend::Backend as StateBackend;
use executor::RuntimeInfo;
use state_machine::{CodeExecutor, TrieH256, DBValue, ExecutionStrategy};
use state_machine::{CodeExecutor, DBValue, ExecutionStrategy};
use utils::{Meta, db_err, meta_keys, number_to_db_key, open_database, read_db, read_id, read_meta};
use state_db::StateDb;
pub use state_db::PruningMode;
@@ -66,7 +68,7 @@ pub use state_db::PruningMode;
const FINALIZATION_WINDOW: u64 = 32;
/// DB-backed patricia trie state, transaction type is an overlay of changes to commit.
pub type DbState = state_machine::TrieBackend;
pub type DbState = state_machine::TrieBackend<KeccakHasher, RlpCodec>;
/// Database settings.
pub struct DatabaseSettings {
@@ -87,7 +89,7 @@ pub fn new_client<E, S, Block>(
) -> Result<client::Client<Backend<Block>, client::LocalCallExecutor<Backend<Block>, E>, Block>, client::error::Error>
where
Block: BlockT,
E: CodeExecutor + RuntimeInfo,
E: CodeExecutor<KeccakHasher> + RuntimeInfo,
S: BuildStorage,
{
let backend = Arc::new(Backend::new(settings, FINALIZATION_WINDOW)?);
@@ -116,7 +118,7 @@ struct PendingBlock<Block: BlockT> {
struct StateMetaDb<'a>(&'a KeyValueDB);
impl<'a> state_db::MetaDb for StateMetaDb<'a> {
type Error = kvdb::Error;
type Error = io::Error;
fn get_meta(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
self.0.get(columns::STATE_META, key).map(|r| r.map(|v| v.to_vec()))
@@ -215,13 +217,16 @@ impl<Block: BlockT> client::blockchain::Backend<Block> for BlockchainDb<Block> {
}
/// Database transaction
pub struct BlockImportOperation<Block: BlockT> {
pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
old_state: DbState,
updates: MemoryDB,
updates: MemoryDB<H>,
pending_block: Option<PendingBlock<Block>>,
}
impl<Block: BlockT> client::backend::BlockImportOperation<Block> for BlockImportOperation<Block> {
impl<Block> client::backend::BlockImportOperation<Block, KeccakHasher, RlpCodec>
for BlockImportOperation<Block, KeccakHasher>
where Block: BlockT,
{
type State = DbState;
fn state(&self) -> Result<Option<&Self::State>, client::error::Error> {
@@ -243,7 +248,7 @@ impl<Block: BlockT> client::backend::BlockImportOperation<Block> for BlockImport
// currently authorities are not cached on full nodes
}
fn update_storage(&mut self, update: MemoryDB) -> Result<(), client::error::Error> {
fn update_storage(&mut self, update: MemoryDB<KeccakHasher>) -> Result<(), client::error::Error> {
self.updates = update;
Ok(())
}
@@ -261,15 +266,15 @@ struct StorageDb<Block: BlockT> {
pub state_db: StateDb<Block::Hash, H256>,
}
impl<Block: BlockT> state_machine::Storage for StorageDb<Block> {
fn get(&self, key: &TrieH256) -> Result<Option<DBValue>, String> {
impl<Block: BlockT> state_machine::Storage<KeccakHasher> for StorageDb<Block> {
fn get(&self, key: &H256) -> Result<Option<DBValue>, String> {
self.state_db.get(&key.0.into(), self).map(|r| r.map(|v| DBValue::from_slice(&v)))
.map_err(|e| format!("Database backend error: {:?}", e))
}
}
impl<Block: BlockT> state_db::HashDb for StorageDb<Block> {
type Error = kvdb::Error;
type Error = io::Error;
type Hash = H256;
fn get(&self, key: &H256) -> Result<Option<Vec<u8>>, Self::Error> {
@@ -305,7 +310,7 @@ impl<Block: BlockT> Backend<Block> {
fn from_kvdb(db: Arc<KeyValueDB>, pruning: PruningMode, finalization_window: u64) -> Result<Self, client::error::Error> {
let blockchain = BlockchainDb::new(db.clone())?;
let map_e = |e: state_db::Error<kvdb::Error>| ::client::error::Error::from(format!("State database error: {:?}", e));
let map_e = |e: state_db::Error<io::Error>| ::client::error::Error::from(format!("State database error: {:?}", e));
let state_db: StateDb<Block::Hash, H256> = StateDb::new(pruning, &StateMetaDb(&*db)).map_err(map_e)?;
let storage_db = StorageDb {
db,
@@ -335,8 +340,8 @@ fn apply_state_commit(transaction: &mut DBTransaction, commit: state_db::CommitS
}
}
impl<Block: BlockT> client::backend::Backend<Block> for Backend<Block> {
type BlockImportOperation = BlockImportOperation<Block>;
impl<Block> client::backend::Backend<Block, KeccakHasher, RlpCodec> for Backend<Block> where Block: BlockT {
type BlockImportOperation = BlockImportOperation<Block, KeccakHasher>;
type Blockchain = BlockchainDb<Block>;
type State = DbState;
@@ -450,14 +455,14 @@ impl<Block: BlockT> client::backend::Backend<Block> for Backend<Block> {
}
self.blockchain.header(block).and_then(|maybe_hdr| maybe_hdr.map(|hdr| {
let root: TrieH256 = TrieH256::from_slice(hdr.state_root().as_ref());
let root: H256 = H256::from_slice(hdr.state_root().as_ref());
DbState::with_storage(self.storage.clone(), root)
}).ok_or_else(|| client::error::ErrorKind::UnknownBlock(format!("{:?}", block)).into()))
}
}
impl<Block: BlockT> client::backend::LocalBackend<Block> for Backend<Block>
{}
impl<Block> client::backend::LocalBackend<Block, KeccakHasher, RlpCodec> for Backend<Block>
where Block: BlockT {}
#[cfg(test)]
mod tests {
+4 -8
View File
@@ -18,8 +18,9 @@
//! full and light storages.
use std::sync::Arc;
use std::io;
use kvdb::{self, KeyValueDB, DBTransaction};
use kvdb::{KeyValueDB, DBTransaction};
use kvdb_rocksdb::{Database, DatabaseConfig};
use client;
@@ -83,20 +84,15 @@ pub fn db_key_to_number<N>(key: &[u8]) -> client::error::Result<N> where N: As<u
}
/// Maps database error to client error
pub fn db_err(err: kvdb::Error) -> client::error::Error {
pub fn db_err(err: io::Error) -> client::error::Error {
use std::error::Error;
match err.kind() {
&kvdb::ErrorKind::Io(ref err) => client::error::ErrorKind::Backend(err.description().into()).into(),
&kvdb::ErrorKind::Msg(ref m) => client::error::ErrorKind::Backend(m.clone()).into(),
_ => client::error::ErrorKind::Backend("Unknown backend error".into()).into(),
}
client::error::ErrorKind::Backend(err.description().into()).into()
}
/// Open RocksDB database.
pub fn open_database(config: &DatabaseSettings, db_type: &str) -> client::error::Result<Arc<KeyValueDB>> {
let mut db_config = DatabaseConfig::with_columns(Some(NUM_COLUMNS));
db_config.memory_budget = config.cache_size;
db_config.wal = true;
let path = config.path.to_str().ok_or_else(|| client::error::ErrorKind::Backend("Invalid database path".into()))?;
let db = Database::open(&db_config, &path).map_err(db_err)?;
+30 -8
View File
@@ -22,11 +22,18 @@ use runtime_primitives::bft::Justification;
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Block as BlockT, NumberFor};
use state_machine::backend::Backend as StateBackend;
use patricia_trie::NodeCodec;
use hashdb::Hasher;
/// Block insertion operation. Keeps hold if the inserted block state and data.
pub trait BlockImportOperation<Block: BlockT> {
pub trait BlockImportOperation<Block, H, C>
where
Block: BlockT,
H: Hasher,
C: NodeCodec<H>,
{
/// Associated state backend type.
type State: StateBackend;
type State: StateBackend<H, C>;
/// Returns pending state. Returns None for backends with locally-unavailable state data.
fn state(&self) -> error::Result<Option<&Self::State>>;
@@ -43,7 +50,7 @@ pub trait BlockImportOperation<Block: BlockT> {
/// has been used to check justification of this block).
fn update_authorities(&mut self, authorities: Vec<AuthorityId>);
/// Inject storage data into the database.
fn update_storage(&mut self, update: <Self::State as StateBackend>::Transaction) -> error::Result<()>;
fn update_storage(&mut self, update: <Self::State as StateBackend<H, C>>::Transaction) -> error::Result<()>;
/// Inject storage data into the database replacing any existing data.
fn reset_storage<I: Iterator<Item=(Vec<u8>, Vec<u8>)>>(&mut self, iter: I) -> error::Result<()>;
}
@@ -56,13 +63,18 @@ pub trait BlockImportOperation<Block: BlockT> {
///
/// The same applies for live `BlockImportOperation`s: while an import operation building on a parent `P`
/// is alive, the state for `P` should not be pruned.
pub trait Backend<Block: BlockT>: Send + Sync {
pub trait Backend<Block, H, C>: Send + Sync
where
Block: BlockT,
H: Hasher,
C: NodeCodec<H>,
{
/// Associated block insertion operation type.
type BlockImportOperation: BlockImportOperation<Block>;
type BlockImportOperation: BlockImportOperation<Block, H, C>;
/// Associated blockchain backend type.
type Blockchain: ::blockchain::Backend<Block>;
/// Associated state backend type.
type State: StateBackend;
type State: StateBackend<H, C>;
/// Begin a new block insertion transaction with given parent block id.
/// When constructing the genesis, this is called with all-zero hash.
@@ -79,7 +91,17 @@ pub trait Backend<Block: BlockT>: Send + Sync {
}
/// Mark for all Backend implementations, that are making use of state data, stored locally.
pub trait LocalBackend<Block: BlockT>: Backend<Block> {}
pub trait LocalBackend<Block, H, C>: Backend<Block, H, C>
where
Block: BlockT,
H: Hasher,
C: NodeCodec<H>,
{}
/// Mark for all Backend implementations, that are fetching required state data from remote nodes.
pub trait RemoteBackend<Block: BlockT>: Backend<Block> {}
pub trait RemoteBackend<Block, H, C>: Backend<Block, H, C>
where
Block: BlockT,
H: Hasher,
C: NodeCodec<H>,
{}
@@ -23,12 +23,20 @@ use runtime_primitives::traits::{Header as HeaderT, Hash, Block as BlockT, One,
use runtime_primitives::generic::BlockId;
use {backend, error, Client, CallExecutor};
use runtime_primitives::{ApplyResult, ApplyOutcome};
use patricia_trie::NodeCodec;
use primitives::{KeccakHasher, RlpCodec};
use hashdb::Hasher;
use rlp::Encodable;
/// Utility for building new (valid) blocks from a stream of extrinsics.
pub struct BlockBuilder<B, E, Block> where
B: backend::Backend<Block>,
E: CallExecutor<Block> + Clone,
pub struct BlockBuilder<B, E, Block, H, C>
where
B: backend::Backend<Block, H, C>,
E: CallExecutor<Block, H, C> + Clone,
Block: BlockT,
H: Hasher,
H::Out: Encodable + Ord,
C: NodeCodec<H>,
{
header: <Block as BlockT>::Header,
extrinsics: Vec<<Block as BlockT>::Extrinsic>,
@@ -37,9 +45,10 @@ pub struct BlockBuilder<B, E, Block> where
changes: state_machine::OverlayedChanges,
}
impl<B, E, Block> BlockBuilder<B, E, Block> where
B: backend::Backend<Block>,
E: CallExecutor<Block> + Clone,
impl<B, E, Block> BlockBuilder<B, E, Block, KeccakHasher, RlpCodec>
where
B: backend::Backend<Block, KeccakHasher, RlpCodec>,
E: CallExecutor<Block, KeccakHasher, RlpCodec> + Clone,
Block: BlockT,
{
/// Create a new instance of builder from the given client, building on the latest block.
+22 -11
View File
@@ -15,12 +15,17 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use std::cmp::Ord;
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::Block as BlockT;
use state_machine::{self, OverlayedChanges, Ext,
use state_machine::{self, OverlayedChanges, Ext,
CodeExecutor, ExecutionManager, native_when_possible};
use runtime_io::Externalities;
use executor::{RuntimeVersion, RuntimeInfo};
use patricia_trie::NodeCodec;
use primitives::{KeccakHasher, RlpCodec};
use hashdb::Hasher;
use rlp::Encodable;
use backend;
use error;
@@ -35,7 +40,13 @@ pub struct CallResult {
}
/// Method call executor.
pub trait CallExecutor<B: BlockT> {
pub trait CallExecutor<B, H, C>
where
B: BlockT,
H: Hasher,
H::Out: Ord + Encodable,
C: NodeCodec<H>,
{
/// Externalities error type.
type Error: state_machine::Error;
@@ -57,7 +68,7 @@ pub trait CallExecutor<B: BlockT> {
///
/// No changes are made.
fn call_at_state<
S: state_machine::Backend,
S: state_machine::Backend<H, C>,
F: FnOnce(Result<Vec<u8>, Self::Error>, Result<Vec<u8>, Self::Error>) -> Result<Vec<u8>, Self::Error>,
>(&self,
state: &S,
@@ -70,7 +81,7 @@ pub trait CallExecutor<B: BlockT> {
/// Execute a call to a contract on top of given state, gathering execution proof.
///
/// No changes are made.
fn prove_at_state<S: state_machine::Backend>(&self,
fn prove_at_state<S: state_machine::Backend<H, C>>(&self,
state: S,
overlay: &mut OverlayedChanges,
method: &str,
@@ -104,11 +115,11 @@ impl<B, E> Clone for LocalCallExecutor<B, E> where E: Clone {
}
}
impl<B, E, Block> CallExecutor<Block> for LocalCallExecutor<B, E>
where
B: backend::LocalBackend<Block>,
E: CodeExecutor + RuntimeInfo,
Block: BlockT,
impl<B, E, Block> CallExecutor<Block, KeccakHasher, RlpCodec> for LocalCallExecutor<B, E>
where
B: backend::LocalBackend<Block, KeccakHasher, RlpCodec>,
E: CodeExecutor<KeccakHasher> + RuntimeInfo,
Block: BlockT,
{
type Error = E::Error;
@@ -140,7 +151,7 @@ impl<B, E, Block> CallExecutor<Block> for LocalCallExecutor<B, E>
}
fn call_at_state<
S: state_machine::Backend,
S: state_machine::Backend<KeccakHasher, RlpCodec>,
F: FnOnce(Result<Vec<u8>, Self::Error>, Result<Vec<u8>, Self::Error>) -> Result<Vec<u8>, Self::Error>,
>(&self,
state: &S,
@@ -159,7 +170,7 @@ impl<B, E, Block> CallExecutor<Block> for LocalCallExecutor<B, E>
).map_err(Into::into)
}
fn prove_at_state<S: state_machine::Backend>(&self,
fn prove_at_state<S: state_machine::Backend<KeccakHasher, RlpCodec>>(&self,
state: S,
changes: &mut OverlayedChanges,
method: &str,
+24 -19
View File
@@ -23,6 +23,7 @@ use primitives::AuthorityId;
use runtime_primitives::{bft::Justification, generic::{BlockId, SignedBlock, Block as RuntimeBlock}};
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, One, As, NumberFor};
use runtime_primitives::BuildStorage;
use primitives::{KeccakHasher, RlpCodec};
use primitives::storage::{StorageKey, StorageData};
use codec::Decode;
use state_machine::{
@@ -163,9 +164,9 @@ impl<Block: BlockT> JustifiedHeader<Block> {
pub fn new_in_mem<E, Block, S>(
executor: E,
genesis_storage: S,
) -> error::Result<Client<in_mem::Backend<Block>, LocalCallExecutor<in_mem::Backend<Block>, E>, Block>>
) -> error::Result<Client<in_mem::Backend<Block, KeccakHasher, RlpCodec>, LocalCallExecutor<in_mem::Backend<Block, KeccakHasher, RlpCodec>, E>, Block>>
where
E: CodeExecutor + RuntimeInfo,
E: CodeExecutor<KeccakHasher> + RuntimeInfo,
S: BuildStorage,
Block: BlockT,
{
@@ -175,8 +176,8 @@ pub fn new_in_mem<E, Block, S>(
}
impl<B, E, Block> Client<B, E, Block> where
B: backend::Backend<Block>,
E: CallExecutor<Block>,
B: backend::Backend<Block, KeccakHasher, RlpCodec>,
E: CallExecutor<Block, KeccakHasher, RlpCodec>,
Block: BlockT,
{
/// Creates new Substrate Client with given blockchain and code executor.
@@ -284,12 +285,16 @@ impl<B, E, Block> Client<B, E, Block> where
}
/// Create a new block, built on the head of the chain.
pub fn new_block(&self) -> error::Result<block_builder::BlockBuilder<B, E, Block>> where E: Clone {
pub fn new_block(&self) -> error::Result<block_builder::BlockBuilder<B, E, Block, KeccakHasher, RlpCodec>>
where E: Clone
{
block_builder::BlockBuilder::new(self)
}
/// Create a new block, built on top of `parent`.
pub fn new_block_at(&self, parent: &BlockId<Block>) -> error::Result<block_builder::BlockBuilder<B, E, Block>> where E: Clone {
pub fn new_block_at(&self, parent: &BlockId<Block>) -> error::Result<block_builder::BlockBuilder<B, E, Block, KeccakHasher, RlpCodec>>
where E: Clone
{
block_builder::BlockBuilder::at_block(parent, &self)
}
@@ -504,8 +509,8 @@ impl<B, E, Block> Client<B, E, Block> where
impl<B, E, Block> bft::BlockImport<Block> for Client<B, E, Block>
where
B: backend::Backend<Block>,
E: CallExecutor<Block>,
B: backend::Backend<Block, KeccakHasher, RlpCodec>,
E: CallExecutor<Block, KeccakHasher, RlpCodec>,
Block: BlockT,
{
fn import_block(
@@ -527,8 +532,8 @@ impl<B, E, Block> bft::BlockImport<Block> for Client<B, E, Block>
impl<B, E, Block> bft::Authorities<Block> for Client<B, E, Block>
where
B: backend::Backend<Block>,
E: CallExecutor<Block>,
B: backend::Backend<Block, KeccakHasher, RlpCodec>,
E: CallExecutor<Block, KeccakHasher, RlpCodec>,
Block: BlockT,
{
fn authorities(&self, at: &BlockId<Block>) -> Result<Vec<AuthorityId>, bft::Error> {
@@ -549,9 +554,9 @@ impl<B, E, Block> bft::Authorities<Block> for Client<B, E, Block>
}
impl<B, E, Block> BlockchainEvents<Block> for Client<B, E, Block>
where
E: CallExecutor<Block>,
Block: BlockT,
where
E: CallExecutor<Block, KeccakHasher, RlpCodec>,
Block: BlockT,
{
/// Get block import event stream.
fn import_notification_stream(&self) -> BlockchainEventStream<Block> {
@@ -567,10 +572,10 @@ impl<B, E, Block> BlockchainEvents<Block> for Client<B, E, Block>
}
impl<B, E, Block> ChainHead<Block> for Client<B, E, Block>
where
B: backend::Backend<Block>,
E: CallExecutor<Block>,
Block: BlockT,
where
B: backend::Backend<Block, KeccakHasher, RlpCodec>,
E: CallExecutor<Block, KeccakHasher, RlpCodec>,
Block: BlockT,
{
fn best_block_header(&self) -> error::Result<<Block as BlockT>::Header> {
Client::best_block_header(self)
@@ -579,8 +584,8 @@ impl<B, E, Block> ChainHead<Block> for Client<B, E, Block>
impl<B, E, Block> BlockBody<Block> for Client<B, E, Block>
where
B: backend::Backend<Block>,
E: CallExecutor<Block>,
B: backend::Backend<Block, KeccakHasher, RlpCodec>,
E: CallExecutor<Block, KeccakHasher, RlpCodec>,
Block: BlockT,
{
fn block_body(&self, id: &BlockId<Block>) -> error::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
+3 -2
View File
@@ -51,6 +51,7 @@ mod tests {
use test_client::runtime::genesismap::{GenesisConfig, additional_storage_with_genesis};
use test_client::runtime::{Hash, Transfer, Block, BlockNumber, Header, Digest, Extrinsic};
use ed25519::{Public, Pair};
use primitives::{KeccakHasher, RlpCodec};
native_executor_instance!(Executor, test_client::runtime::api::dispatch, test_client::runtime::VERSION, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm"));
@@ -58,7 +59,7 @@ mod tests {
NativeExecutionDispatch::with_heap_pages(8)
}
fn construct_block(backend: &InMemory, number: BlockNumber, parent_hash: Hash, state_root: Hash, txs: Vec<Transfer>) -> (Vec<u8>, Hash) {
fn construct_block(backend: &InMemory<KeccakHasher, RlpCodec>, number: BlockNumber, parent_hash: Hash, state_root: Hash, txs: Vec<Transfer>) -> (Vec<u8>, Hash) {
use triehash::ordered_trie_root;
let transactions = txs.into_iter().map(|tx| {
@@ -115,7 +116,7 @@ mod tests {
(vec![].and(&Block { header, extrinsics: transactions }), hash)
}
fn block1(genesis_hash: Hash, backend: &InMemory) -> (Vec<u8>, Hash) {
fn block1(genesis_hash: Hash, backend: &InMemory<KeccakHasher, RlpCodec>) -> (Vec<u8>, Hash) {
construct_block(
backend,
1,
+39 -14
View File
@@ -28,6 +28,9 @@ use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, Numbe
use runtime_primitives::bft::Justification;
use blockchain::{self, BlockStatus};
use state_machine::backend::{Backend as StateBackend, InMemory};
use patricia_trie::NodeCodec;
use hashdb::Hasher;
use heapsize::HeapSizeOf;
struct PendingBlock<B: BlockT> {
block: StoredBlock<B>,
@@ -248,15 +251,21 @@ impl<Block: BlockT> light::blockchain::Storage<Block> for Blockchain<Block> {
}
/// In-memory operation.
pub struct BlockImportOperation<Block: BlockT> {
pub struct BlockImportOperation<Block: BlockT, H: Hasher, C: NodeCodec<H>> {
pending_block: Option<PendingBlock<Block>>,
pending_authorities: Option<Vec<AuthorityId>>,
old_state: InMemory,
new_state: Option<InMemory>,
old_state: InMemory<H, C>,
new_state: Option<InMemory<H, C>>,
}
impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperation<Block> {
type State = InMemory;
impl<Block, H, C> backend::BlockImportOperation<Block, H, C> for BlockImportOperation<Block, H, C>
where
Block: BlockT,
H: Hasher,
C: NodeCodec<H>,
H::Out: HeapSizeOf,
{
type State = InMemory<H, C>;
fn state(&self) -> error::Result<Option<&Self::State>> {
Ok(Some(&self.old_state))
@@ -281,7 +290,7 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
self.pending_authorities = Some(authorities);
}
fn update_storage(&mut self, update: <InMemory as StateBackend>::Transaction) -> error::Result<()> {
fn update_storage(&mut self, update: <InMemory<H, C> as StateBackend<H, C>>::Transaction) -> error::Result<()> {
self.new_state = Some(self.old_state.update(update));
Ok(())
}
@@ -293,18 +302,24 @@ impl<Block: BlockT> backend::BlockImportOperation<Block> for BlockImportOperatio
}
/// In-memory backend. Keeps all states and blocks in memory. Useful for testing.
pub struct Backend<Block> where
pub struct Backend<Block, H, C>
where
Block: BlockT,
H: Hasher,
C: NodeCodec<H>
{
states: RwLock<HashMap<Block::Hash, InMemory>>,
states: RwLock<HashMap<Block::Hash, InMemory<H, C>>>,
blockchain: Blockchain<Block>,
}
impl<Block> Backend<Block> where
impl<Block, H, C> Backend<Block, H, C>
where
Block: BlockT,
H: Hasher,
C: NodeCodec<H>
{
/// Create a new instance of in-mem backend.
pub fn new() -> Backend<Block> {
pub fn new() -> Backend<Block, H, C> {
Backend {
states: RwLock::new(HashMap::new()),
blockchain: Blockchain::new(),
@@ -312,12 +327,16 @@ impl<Block> Backend<Block> where
}
}
impl<Block> backend::Backend<Block> for Backend<Block> where
impl<Block, H, C> backend::Backend<Block, H, C> for Backend<Block, H, C>
where
Block: BlockT,
H: Hasher,
H::Out: HeapSizeOf,
C: NodeCodec<H> + Send + Sync,
{
type BlockImportOperation = BlockImportOperation<Block>;
type BlockImportOperation = BlockImportOperation<Block, H, C>;
type Blockchain = Blockchain<Block>;
type State = InMemory;
type State = InMemory<H, C>;
fn begin_operation(&self, block: BlockId<Block>) -> error::Result<Self::BlockImportOperation> {
let state = match block {
@@ -366,7 +385,13 @@ impl<Block> backend::Backend<Block> for Backend<Block> where
}
}
impl<Block: BlockT> backend::LocalBackend<Block> for Backend<Block> {}
impl<Block, H, C> backend::LocalBackend<Block, H, C> for Backend<Block, H, C>
where
Block: BlockT,
H: Hasher,
H::Out: HeapSizeOf,
C: NodeCodec<H> + Send + Sync,
{}
impl<Block: BlockT> Cache<Block> {
fn insert(&self, at: Block::Hash, authorities: Option<Vec<AuthorityId>>) {
+4
View File
@@ -36,6 +36,10 @@ extern crate fnv;
extern crate futures;
extern crate parking_lot;
extern crate triehash;
extern crate patricia_trie;
extern crate hashdb;
extern crate rlp;
extern crate heapsize;
#[macro_use] extern crate error_chain;
#[macro_use] extern crate log;
+42 -17
View File
@@ -24,14 +24,19 @@ use parking_lot::RwLock;
use primitives::AuthorityId;
use runtime_primitives::{bft::Justification, generic::BlockId};
use runtime_primitives::traits::{Block as BlockT, NumberFor};
use state_machine::{Backend as StateBackend, TrieBackend as StateTrieBackend,
TryIntoTrieBackend as TryIntoStateTrieBackend};
use state_machine::{
Backend as StateBackend,
TrieBackend as StateTrieBackend,
TryIntoTrieBackend as TryIntoStateTrieBackend
};
use backend::{Backend as ClientBackend, BlockImportOperation, RemoteBackend};
use blockchain::HeaderBackend as BlockchainHeaderBackend;
use error::{Error as ClientError, ErrorKind as ClientErrorKind, Result as ClientResult};
use light::blockchain::{Blockchain, Storage as BlockchainStorage};
use light::fetcher::{Fetcher, RemoteReadRequest};
use patricia_trie::NodeCodec;
use hashdb::Hasher;
/// Light client backend.
pub struct Backend<S, F> {
@@ -66,10 +71,12 @@ impl<S, F> Backend<S, F> {
}
}
impl<S, F, Block> ClientBackend<Block> for Backend<S, F> where
impl<S, F, Block, H, C> ClientBackend<Block, H, C> for Backend<S, F> where
Block: BlockT,
S: BlockchainStorage<Block>,
F: Fetcher<Block>
F: Fetcher<Block>,
H: Hasher,
C: NodeCodec<H>,
{
type BlockImportOperation = ImportOperation<Block, S, F>;
type Blockchain = Blockchain<S, F>;
@@ -112,13 +119,22 @@ impl<S, F, Block> ClientBackend<Block> for Backend<S, F> where
}
}
impl<S, F, Block> RemoteBackend<Block> for Backend<S, F> where Block: BlockT, S: BlockchainStorage<Block>, F: Fetcher<Block> {}
impl<S, F, Block, H, C> RemoteBackend<Block, H, C> for Backend<S, F>
where
Block: BlockT,
S: BlockchainStorage<Block>,
F: Fetcher<Block>,
H: Hasher,
C: NodeCodec<H>,
{}
impl<S, F, Block> BlockImportOperation<Block> for ImportOperation<Block, S, F>
where
Block: BlockT,
S: BlockchainStorage<Block>,
F: Fetcher<Block>,
impl<S, F, Block, H, C> BlockImportOperation<Block, H, C> for ImportOperation<Block, S, F>
where
Block: BlockT,
F: Fetcher<Block>,
S: BlockchainStorage<Block>,
H: Hasher,
C: NodeCodec<H>,
{
type State = OnDemandState<Block, S, F>;
@@ -143,7 +159,7 @@ impl<S, F, Block> BlockImportOperation<Block> for ImportOperation<Block, S, F>
self.authorities = Some(authorities);
}
fn update_storage(&mut self, _update: <Self::State as StateBackend>::Transaction) -> ClientResult<()> {
fn update_storage(&mut self, _update: <Self::State as StateBackend<H, C>>::Transaction) -> ClientResult<()> {
// we're not storing anything locally => ignore changes
Ok(())
}
@@ -154,11 +170,13 @@ impl<S, F, Block> BlockImportOperation<Block> for ImportOperation<Block, S, F>
}
}
impl<Block, S, F> StateBackend for OnDemandState<Block, S, F>
impl<Block, S, F, H, C> StateBackend<H, C> for OnDemandState<Block, S, F>
where
Block: BlockT,
S: BlockchainStorage<Block>,
F: Fetcher<Block>,
H: Hasher,
C: NodeCodec<H>,
{
type Error = ClientError;
type Transaction = ();
@@ -186,9 +204,9 @@ impl<Block, S, F> StateBackend for OnDemandState<Block, S, F>
// whole state is not available on light node
}
fn storage_root<I>(&self, _delta: I) -> ([u8; 32], Self::Transaction)
fn storage_root<I>(&self, _delta: I) -> (H::Out, Self::Transaction)
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)> {
([0; 32], ())
(H::Out::default(), ())
}
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
@@ -197,8 +215,14 @@ impl<Block, S, F> StateBackend for OnDemandState<Block, S, F>
}
}
impl<Block, S, F> TryIntoStateTrieBackend for OnDemandState<Block, S, F> where Block: BlockT, F: Fetcher<Block> {
fn try_into_trie_backend(self) -> Option<StateTrieBackend> {
impl<Block, S, F, H, C> TryIntoStateTrieBackend<H, C> for OnDemandState<Block, S, F>
where
Block: BlockT,
F: Fetcher<Block>,
H: Hasher,
C: NodeCodec<H>,
{
fn try_into_trie_backend(self) -> Option<StateTrieBackend<H, C>> {
None
}
}
@@ -214,6 +238,7 @@ pub mod tests {
use light::new_fetch_checker;
use light::fetcher::{Fetcher, FetchChecker, RemoteCallRequest};
use super::*;
use primitives::{KeccakHasher, RlpCodec};
pub type OkCallFetcher = Mutex<CallResult>;
@@ -246,7 +271,7 @@ pub mod tests {
// check remote read proof locally
let local_executor = test_client::LocalExecutor::with_heap_pages(8);
let local_checker = new_fetch_checker(local_executor);
let local_checker = new_fetch_checker::<_, KeccakHasher, RlpCodec>(local_executor);
let request = RemoteReadRequest {
block: remote_block_hash,
header: remote_block_header,
@@ -23,7 +23,12 @@ use futures::{IntoFuture, Future};
use runtime_primitives::generic::BlockId;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT};
use state_machine::{Backend as StateBackend, CodeExecutor, OverlayedChanges,
execution_proof_check, TrieH256, ExecutionManager};
execution_proof_check, ExecutionManager};
use primitives::H256;
use patricia_trie::NodeCodec;
use hashdb::Hasher;
use rlp::Encodable;
use primitives::{KeccakHasher, RlpCodec};
use blockchain::Backend as ChainBackend;
use call_executor::{CallExecutor, CallResult};
@@ -31,6 +36,7 @@ use error::{Error as ClientError, ErrorKind as ClientErrorKind, Result as Client
use light::fetcher::{Fetcher, RemoteCallRequest};
use executor::RuntimeVersion;
use codec::Decode;
use heapsize::HeapSizeOf;
/// Call executor that executes methods on remote node, querying execution proof
/// and checking proof by re-executing locally.
@@ -46,7 +52,7 @@ impl<B, F> RemoteCallExecutor<B, F> {
}
}
impl<B, F, Block> CallExecutor<Block> for RemoteCallExecutor<B, F>
impl<B, F, Block> CallExecutor<Block, KeccakHasher, RlpCodec> for RemoteCallExecutor<B, F>
where
Block: BlockT,
B: ChainBackend<Block>,
@@ -77,19 +83,25 @@ impl<B, F, Block> CallExecutor<Block> for RemoteCallExecutor<B, F>
}
fn call_at_state<
S: StateBackend,
H: FnOnce(Result<Vec<u8>, Self::Error>, Result<Vec<u8>, Self::Error>) -> Result<Vec<u8>, Self::Error>
S: StateBackend<KeccakHasher, RlpCodec>,
FF: FnOnce(Result<Vec<u8>, Self::Error>, Result<Vec<u8>, Self::Error>) -> Result<Vec<u8>, Self::Error>
>(&self,
_state: &S,
_changes: &mut OverlayedChanges,
_method: &str,
_call_data: &[u8],
_m: ExecutionManager<H>
_m: ExecutionManager<FF>
) -> ClientResult<(Vec<u8>, S::Transaction)> {
Err(ClientErrorKind::NotAvailableOnLightClient.into())
}
fn prove_at_state<S: StateBackend>(&self, _state: S, _changes: &mut OverlayedChanges, _method: &str, _call_data: &[u8]) -> ClientResult<(Vec<u8>, Vec<Vec<u8>>)> {
fn prove_at_state<S: StateBackend<KeccakHasher, RlpCodec>>(
&self,
_state: S,
_changes: &mut OverlayedChanges,
_method: &str,
_call_data: &[u8]
) -> ClientResult<(Vec<u8>, Vec<Vec<u8>>)> {
Err(ClientErrorKind::NotAvailableOnLightClient.into())
}
@@ -99,20 +111,23 @@ impl<B, F, Block> CallExecutor<Block> for RemoteCallExecutor<B, F>
}
/// Check remote execution proof using given backend.
pub fn check_execution_proof<Header, E>(
pub fn check_execution_proof<Header, E, H, C>(
executor: &E,
request: &RemoteCallRequest<Header>,
remote_proof: Vec<Vec<u8>>
) -> ClientResult<CallResult>
where
Header: HeaderT,
E: CodeExecutor,
E: CodeExecutor<H>,
H: Hasher,
H::Out: Ord + Encodable + HeapSizeOf + From<H256>,
C: NodeCodec<H>,
{
let local_state_root = request.header.state_root();
let mut changes = OverlayedChanges::default();
let (local_result, _) = execution_proof_check(
TrieH256::from_slice(local_state_root.as_ref()).into(),
let (local_result, _) = execution_proof_check::<H, C, _>(
H256::from_slice(local_state_root.as_ref()).into(),
remote_proof,
&mut changes,
executor,
@@ -127,6 +142,7 @@ mod tests {
use test_client;
use executor::NativeExecutionDispatch;
use super::*;
use primitives::RlpCodec;
#[test]
fn execution_proof_is_generated_and_checked() {
@@ -138,10 +154,10 @@ mod tests {
// 'fetch' execution proof from remote node
let remote_execution_proof = remote_client.execution_proof(&remote_block_id, "authorities", &[]).unwrap().1;
// check remote execution proof locally
let local_executor = test_client::LocalExecutor::with_heap_pages(8);
check_execution_proof(&local_executor, &RemoteCallRequest {
check_execution_proof::<_, _, _, RlpCodec>(&local_executor, &RemoteCallRequest {
block: test_client::runtime::Hash::default(),
header: test_client::runtime::Header {
state_root: remote_block_storage_root.into(),
@@ -18,8 +18,14 @@
use futures::IntoFuture;
use primitives::H256;
use hashdb::Hasher;
use patricia_trie::NodeCodec;
use rlp::Encodable;
use heapsize::HeapSizeOf;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT};
use state_machine::{CodeExecutor, read_proof_check};
use std::marker::PhantomData;
use call_executor::CallResult;
use error::{Error as ClientError, Result as ClientResult};
@@ -83,24 +89,29 @@ pub trait FetchChecker<Block: BlockT>: Send + Sync {
}
/// Remote data checker.
pub struct LightDataChecker<E> {
pub struct LightDataChecker<E, H, C> {
executor: E,
_hasher: PhantomData<H>,
_codec: PhantomData<C>,
}
impl<E> LightDataChecker<E> {
impl<E, H, C> LightDataChecker<E, H, C> {
/// Create new light data checker.
pub fn new(executor: E) -> Self {
Self {
executor,
executor, _hasher: PhantomData, _codec: PhantomData
}
}
}
impl<E, Block> FetchChecker<Block> for LightDataChecker<E>
impl<E, Block, H, C> FetchChecker<Block> for LightDataChecker<E, H, C>
where
Block: BlockT,
Block::Hash: Into<[u8; 32]>,
E: CodeExecutor,
Block::Hash: Into<H::Out>,
E: CodeExecutor<H>,
H: Hasher,
C: NodeCodec<H> + Sync + Send,
H::Out: Ord + Encodable + HeapSizeOf + From<H256>,
{
fn check_read_proof(
&self,
@@ -108,7 +119,7 @@ impl<E, Block> FetchChecker<Block> for LightDataChecker<E>
remote_proof: Vec<Vec<u8>>
) -> ClientResult<Option<Vec<u8>>> {
let local_state_root = request.header.state_root().clone();
read_proof_check(local_state_root.into(), remote_proof, &request.key).map_err(Into::into)
read_proof_check::<H, C>(local_state_root.into(), remote_proof, &request.key).map_err(Into::into)
}
fn check_execution_proof(
@@ -116,6 +127,6 @@ impl<E, Block> FetchChecker<Block> for LightDataChecker<E>
request: &RemoteCallRequest<Block::Header>,
remote_proof: Vec<Vec<u8>>
) -> ClientResult<CallResult> {
check_execution_proof(&self.executor, request, remote_proof)
check_execution_proof::<_, _, H, C>(&self.executor, request, remote_proof)
}
}
+7 -3
View File
@@ -33,6 +33,8 @@ use light::backend::Backend;
use light::blockchain::{Blockchain, Storage as BlockchainStorage};
use light::call_executor::RemoteCallExecutor;
use light::fetcher::{Fetcher, LightDataChecker};
use hashdb::Hasher;
use patricia_trie::NodeCodec;
/// Create an instance of light client blockchain backend.
pub fn new_light_blockchain<B: BlockT, S: BlockchainStorage<B>, F>(storage: S) -> Arc<Blockchain<S, F>> {
@@ -62,11 +64,13 @@ pub fn new_light<B, S, F, GS>(
}
/// Create an instance of fetch data checker.
pub fn new_fetch_checker<E>(
pub fn new_fetch_checker<E, H, C>(
executor: E,
) -> LightDataChecker<E>
) -> LightDataChecker<E, H, C>
where
E: CodeExecutor,
E: CodeExecutor<H>,
H: Hasher,
C: NodeCodec<H>,
{
LightDataChecker::new(executor)
}
+2
View File
@@ -21,6 +21,8 @@ twox-hash = "1.1.0"
lazy_static = "1.0"
parking_lot = "*"
log = "0.3"
hashdb = { git = "https://github.com/paritytech/parity-common" }
tiny-keccak = "1.4"
[dev-dependencies]
assert_matches = "1.1"
+5 -1
View File
@@ -42,6 +42,9 @@ extern crate byteorder;
extern crate triehash;
extern crate parking_lot;
extern crate twox_hash;
extern crate hashdb;
extern crate tiny_keccak;
#[macro_use] extern crate log;
#[macro_use]
@@ -73,6 +76,7 @@ pub use native_executor::{with_native_environment, NativeExecutor, NativeExecuti
pub use state_machine::Externalities;
pub use runtime_version::RuntimeVersion;
pub use codec::Codec;
use primitives::KeccakHasher;
/// Provides runtime information.
pub trait RuntimeInfo {
@@ -80,7 +84,7 @@ pub trait RuntimeInfo {
const NATIVE_VERSION: Option<RuntimeVersion>;
/// Extract RuntimeVersion of given :code block
fn runtime_version<E: Externalities> (
fn runtime_version<E: Externalities<KeccakHasher>> (
&self,
ext: &mut E,
code: &[u8]
@@ -25,6 +25,7 @@ use twox_hash::XxHash;
use std::hash::Hasher;
use parking_lot::{Mutex, MutexGuard};
use RuntimeInfo;
use primitives::KeccakHasher;
// For the internal Runtime Cache:
// Is it compatible enough to run this natively or do we need to fall back on the WasmModule
@@ -56,7 +57,7 @@ fn gen_cache_key(code: &[u8]) -> u64 {
/// fetch a runtime version from the cache or if there is no cached version yet, create
/// the runtime version entry for `code`, determines whether `Compatibility::IsCompatible`
/// can be used by by comparing returned RuntimeVersion to `ref_version`
fn fetch_cached_runtime_version<'a, E: Externalities>(
fn fetch_cached_runtime_version<'a, E: Externalities<KeccakHasher>>(
wasm_executor: &WasmExecutor,
cache: &'a mut MutexGuard<CacheType>,
ext: &mut E,
@@ -94,8 +95,8 @@ fn safe_call<F, U>(f: F) -> Result<U>
/// Set up the externalities and safe calling environment to execute calls to a native runtime.
///
/// If the inner closure panics, it will be caught and return an error.
pub fn with_native_environment<F, U>(ext: &mut Externalities, f: F) -> Result<U>
where F: ::std::panic::UnwindSafe + FnOnce() -> U
pub fn with_native_environment<F, U>(ext: &mut Externalities<KeccakHasher>, f: F) -> Result<U>
where F: ::std::panic::UnwindSafe + FnOnce() -> U
{
::runtime_io::with_externalities(ext, move || safe_call(f))
}
@@ -107,7 +108,8 @@ pub trait NativeExecutionDispatch: Send + Sync {
/// Dispatch a method and input data to be executed natively. Returns `Some` result or `None`
/// if the `method` is unknown. Panics if there's an unrecoverable error.
fn dispatch(ext: &mut Externalities, method: &str, data: &[u8]) -> Result<Vec<u8>>;
// fn dispatch<H: hashdb::Hasher>(ext: &mut Externalities<H>, method: &str, data: &[u8]) -> Result<Vec<u8>>;
fn dispatch(ext: &mut Externalities<KeccakHasher>, method: &str, data: &[u8]) -> Result<Vec<u8>>;
/// Get native runtime version.
const VERSION: RuntimeVersion;
@@ -150,7 +152,7 @@ impl<D: NativeExecutionDispatch> Clone for NativeExecutor<D> {
impl<D: NativeExecutionDispatch> RuntimeInfo for NativeExecutor<D> {
const NATIVE_VERSION: Option<RuntimeVersion> = Some(D::VERSION);
fn runtime_version<E: Externalities>(
fn runtime_version<E: Externalities<KeccakHasher>>(
&self,
ext: &mut E,
code: &[u8],
@@ -163,10 +165,10 @@ impl<D: NativeExecutionDispatch> RuntimeInfo for NativeExecutor<D> {
}
}
impl<D: NativeExecutionDispatch> CodeExecutor for NativeExecutor<D> {
impl<D: NativeExecutionDispatch> CodeExecutor<KeccakHasher> for NativeExecutor<D> {
type Error = Error;
fn call<E: Externalities>(
fn call<E: Externalities<KeccakHasher>>(
&self,
ext: &mut E,
code: &[u8],
@@ -195,6 +197,8 @@ macro_rules! native_executor_instance {
native_executor_instance!(IMPL $name, $dispatcher, $version, $code);
};
(IMPL $name:ident, $dispatcher:path, $version:path, $code:expr) => {
// TODO: this is not so great I think I should go back to have dispatch take a type param and modify this macro to accept a type param and then pass it in from the test-client instead
use primitives::KeccakHasher as _KeccakHasher;
impl $crate::NativeExecutionDispatch for $name {
const VERSION: $crate::RuntimeVersion = $version;
fn native_equivalent() -> &'static [u8] {
@@ -202,8 +206,7 @@ macro_rules! native_executor_instance {
// get a proper build script, this must be strictly adhered to or things will go wrong.
$code
}
fn dispatch(ext: &mut $crate::Externalities, method: &str, data: &[u8]) -> $crate::error::Result<Vec<u8>> {
fn dispatch(ext: &mut $crate::Externalities<_KeccakHasher>, method: &str, data: &[u8]) -> $crate::error::Result<Vec<u8>> {
$crate::with_native_environment(ext, move || $dispatcher(method, data))?
.ok_or_else(|| $crate::error::ErrorKind::MethodNotFound(method.to_owned()).into())
}
@@ -18,6 +18,7 @@
use std::cmp::Ordering;
use std::collections::HashMap;
use wasmi::{
Module, ModuleInstance, MemoryInstance, MemoryRef, TableRef, ImportsBuilder
};
@@ -29,8 +30,11 @@ use wasm_utils::UserError;
use primitives::{blake2_256, twox_128, twox_256};
use primitives::hexdisplay::HexDisplay;
use primitives::sandbox as sandbox_primitives;
use primitives::KeccakHasher;
use triehash::ordered_trie_root;
use sandbox;
use tiny_keccak::keccak256;
struct Heap {
end: u32,
@@ -71,7 +75,7 @@ macro_rules! debug_trace {
( $( $x:tt )* ) => ()
}
struct FunctionExecutor<'e, E: Externalities + 'e> {
struct FunctionExecutor<'e, E: Externalities<KeccakHasher> + 'e> {
sandbox_store: sandbox::Store,
heap: Heap,
memory: MemoryRef,
@@ -80,7 +84,7 @@ struct FunctionExecutor<'e, E: Externalities + 'e> {
hash_lookup: HashMap<Vec<u8>, Vec<u8>>,
}
impl<'e, E: Externalities> FunctionExecutor<'e, E> {
impl<'e, E: Externalities<KeccakHasher>> FunctionExecutor<'e, E> {
fn new(m: MemoryRef, heap_pages: usize, t: Option<TableRef>, e: &'e mut E) -> Result<Self> {
Ok(FunctionExecutor {
sandbox_store: sandbox::Store::new(),
@@ -93,7 +97,7 @@ impl<'e, E: Externalities> FunctionExecutor<'e, E> {
}
}
impl<'e, E: Externalities> sandbox::SandboxCapabilities for FunctionExecutor<'e, E> {
impl<'e, E: Externalities<KeccakHasher>> sandbox::SandboxCapabilities for FunctionExecutor<'e, E> {
fn store(&self) -> &sandbox::Store {
&self.sandbox_store
}
@@ -138,6 +142,7 @@ impl ReadPrimitive<u32> for MemoryInstance {
}
}
// TODO: this macro does not support `where` clauses and that seems somewhat tricky to add
impl_function_executor!(this: FunctionExecutor<'e, E>,
ext_print_utf8(utf8_data: *const u8, utf8_len: u32) => {
if let Ok(utf8) = this.memory.get(utf8_data, utf8_len as usize) {
@@ -285,7 +290,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
},
ext_storage_root(result: *mut u8) => {
let r = this.ext.storage_root();
this.memory.set(result, &r[..]).map_err(|_| UserError("Invalid attempt to set memory in ext_storage_root"))?;
this.memory.set(result, r.as_ref()).map_err(|_| UserError("Invalid attempt to set memory in ext_storage_root"))?;
Ok(())
},
ext_enumerated_trie_root(values_data: *const u8, lens_data: *const u32, lens_len: u32, result: *mut u8) => {
@@ -348,6 +353,15 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
this.memory.set(out, &result).map_err(|_| UserError("Invalid attempt to set result in ext_blake2_256"))?;
Ok(())
},
ext_keccak256(data: *const u8, len: u32, out: *mut u8) => {
let result = if len == 0 {
keccak256(&[0u8; 0])
} else {
keccak256(&this.memory.get(data, len as usize).map_err(|_| UserError("Invalid attempt to get data in ext_keccak256"))?)
};
this.memory.set(out, &result).map_err(|_| UserError("Invalid attempt to set result in ext_keccak256"))?;
Ok(())
},
ext_ed25519_verify(msg_data: *const u8, msg_len: u32, sig_data: *const u8, pubkey_data: *const u8) -> u32 => {
let mut sig = [0u8; 64];
this.memory.get_into(sig_data, &mut sig[..]).map_err(|_| UserError("Invalid attempt to get signature in ext_ed25519_verify"))?;
@@ -476,7 +490,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
this.sandbox_store.memory_teardown(memory_idx)?;
Ok(())
},
=> <'e, E: Externalities + 'e>
=> <'e, E: Externalities<KeccakHasher> + 'e>
);
/// Wasm rust executor for contracts.
@@ -508,7 +522,7 @@ impl WasmExecutor {
/// Call a given method in the given code.
/// This should be used for tests only.
pub fn call<E: Externalities>(
pub fn call<E: Externalities<KeccakHasher>>(
&self,
ext: &mut E,
code: &[u8],
@@ -520,7 +534,7 @@ impl WasmExecutor {
}
/// Call a given method in the given wasm-module runtime.
pub fn call_in_wasm_module<E: Externalities>(
pub fn call_in_wasm_module<E: Externalities<KeccakHasher>>(
&self,
ext: &mut E,
module: &Module,
@@ -632,7 +646,7 @@ mod tests {
assert_eq!(output, b"all ok!".to_vec());
let expected: HashMap<_, _> = map![
let expected : TestExternalities<_> = map![
b"input".to_vec() => b"Hello world".to_vec(),
b"foo".to_vec() => b"bar".to_vec(),
b"baz".to_vec() => b"bar".to_vec()
@@ -655,7 +669,7 @@ mod tests {
assert_eq!(output, b"all ok!".to_vec());
let expected: HashMap<_, _> = map![
let expected: TestExternalities<_> = map![
b"aaa".to_vec() => b"1".to_vec(),
b"aab".to_vec() => b"2".to_vec(),
b"bbb".to_vec() => b"5".to_vec()
+25 -8
View File
@@ -18,14 +18,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fixed-hash"
version = "0.1.3"
source = "git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm#8dc457899afdaf968ff7f16140b03d1e37b01d71"
version = "0.2.2"
source = "git+https://github.com/paritytech/parity-common#9bcbfa0f10fee1852791ce07338d664817f69521"
[[package]]
name = "hashdb"
version = "0.2.1"
source = "git+https://github.com/paritytech/parity-common#9bcbfa0f10fee1852791ce07338d664817f69521"
[[package]]
name = "nodrop"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plain_hasher"
version = "0.2.0"
source = "git+https://github.com/paritytech/parity-common#9bcbfa0f10fee1852791ce07338d664817f69521"
dependencies = [
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.4.9"
@@ -115,13 +128,15 @@ version = "0.1.0"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"fixed-hash 0.1.3 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)",
"fixed-hash 0.2.2 (git+https://github.com/paritytech/parity-common)",
"hashdb 0.2.1 (git+https://github.com/paritytech/parity-common)",
"plain_hasher 0.2.0 (git+https://github.com/paritytech/parity-common)",
"rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-codec-derive 0.1.0",
"substrate-runtime-std 0.1.0",
"uint 0.1.2 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)",
"uint 0.2.2 (git+https://github.com/paritytech/parity-common)",
]
[[package]]
@@ -166,8 +181,8 @@ dependencies = [
[[package]]
name = "uint"
version = "0.1.2"
source = "git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm#8dc457899afdaf968ff7f16140b03d1e37b01d71"
version = "0.2.2"
source = "git+https://github.com/paritytech/parity-common#9bcbfa0f10fee1852791ce07338d664817f69521"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -182,8 +197,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda"
"checksum fixed-hash 0.1.3 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)" = "<none>"
"checksum fixed-hash 0.2.2 (git+https://github.com/paritytech/parity-common)" = "<none>"
"checksum hashdb 0.2.1 (git+https://github.com/paritytech/parity-common)" = "<none>"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum plain_hasher 0.2.0 (git+https://github.com/paritytech/parity-common)" = "<none>"
"checksum proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "cccdc7557a98fe98453030f077df7f3a042052fae465bb61d2c2c41435cfd9b6"
"checksum quote 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3372dc35766b36a99ce2352bd1b6ea0137c38d215cc0c8780bf6de6df7842ba9"
"checksum rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b03280c2813907a030785570c577fb27d3deec8da4c18566751ade94de0ace"
@@ -192,5 +209,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526"
"checksum syn 0.14.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e13df71f29f9440b50261a5882c86eac334f1badb3134ec26f0de2f1418e44"
"checksum uint 0.1.2 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)" = "<none>"
"checksum uint 0.2.2 (git+https://github.com/paritytech/parity-common)" = "<none>"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
@@ -16,6 +16,9 @@
//! External API for extrinsic pool.
use std::fmt::Debug;
use serde::{Serialize, de::DeserializeOwned};
use txpool;
use futures::sync::mpsc;
@@ -43,6 +46,9 @@ pub trait ExtrinsicPool<Ex, BlockId, Hash>: Send + Sync + 'static {
/// Error type
type Error: Error;
/// Pooled extrinsics
type InPool: Debug + Serialize + DeserializeOwned + Send + Sync + 'static;
/// Submit a collection of extrinsics to the pool.
fn submit(&self, block: BlockId, xt: Vec<Ex>) -> Result<Vec<Hash>, Self::Error>;
@@ -54,4 +60,7 @@ pub trait ExtrinsicPool<Ex, BlockId, Hash>: Send + Sync + 'static {
/// Return an event stream of transactions imported to the pool.
fn import_notification_stream(&self) -> EventStream;
/// Return all extrinsics in the pool aggregated by the sender.
fn all(&self) -> Self::InPool;
}
@@ -149,4 +149,19 @@ impl<Hash, VEx, S, E> Pool<Hash, VEx, S, E> where
{
f(self.pool.read().pending(ready))
}
/// Retrieve all transactions in the pool. The transactions might be unordered.
pub fn all<F, T>(&self, f: F) -> T where
F: FnOnce(txpool::UnorderedIterator<VEx, AlwaysReady, S>) -> T,
{
f(self.pool.read().unordered_pending(AlwaysReady))
}
}
/// A Readiness implementation that returns `Ready` for all transactions.
pub struct AlwaysReady;
impl<VEx> txpool::Ready<VEx> for AlwaysReady {
fn is_ready(&mut self, _tx: &VEx) -> txpool::Readiness {
txpool::Readiness::Ready
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
ethcore-crypto = { git = "https://github.com/paritytech/parity.git", default_features = false }
parity-crypto = { git = "https://github.com/paritytech/parity-common.git", default_features = false }
ed25519 = { path = "../ed25519" }
error-chain = "0.12"
hex = "0.3"
+1 -1
View File
@@ -16,7 +16,7 @@
//! Keystore (and session key management) for ed25519 based chains like Polkadot.
extern crate ethcore_crypto as crypto;
extern crate parity_crypto as crypto;
extern crate subtle;
extern crate ed25519;
extern crate rand;
@@ -11,7 +11,8 @@ bytes = "0.4"
error-chain = { version = "0.12", default-features = false }
fnv = "1.0"
futures = "0.1"
libp2p = { git = "https://github.com/tomaka/libp2p-rs", branch = "polkadot-2", default-features = false, features = ["libp2p-secio", "libp2p-secio-secp256k1"] }
# libp2p = { git = "https://github.com/tomaka/libp2p-rs", branch = "polkadot-2", default-features = false, features = ["libp2p-secio", "libp2p-secio-secp256k1"] }
libp2p = { git = "https://github.com/tomaka/libp2p-rs", rev = "6aa139a12dbea3d75d898ce0b2af7fcec129e294", default-features = false, features = ["libp2p-secio", "libp2p-secio-secp256k1"] }
ethcore-io = { git = "https://github.com/paritytech/parity.git" }
ethkey = { git = "https://github.com/paritytech/parity.git" }
ethereum-types = "0.3"
@@ -26,6 +27,6 @@ unsigned-varint = { version = "0.1", features = ["codec"] }
[dev-dependencies]
assert_matches = "1.2"
ethcore-bytes = { git = "https://github.com/paritytech/parity.git" }
parity-bytes = { git = "https://github.com/paritytech/parity-common.git" }
ethcore-io = { git = "https://github.com/paritytech/parity.git" }
ethcore-logger = { git = "https://github.com/paritytech/parity.git" }
@@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
extern crate parking_lot;
extern crate ethcore_bytes;
extern crate parity_bytes;
extern crate ethcore_io as io;
extern crate ethcore_logger;
extern crate substrate_network_libp2p;
@@ -26,7 +26,7 @@ use std::sync::Arc;
use std::thread;
use std::time::*;
use parking_lot::Mutex;
use ethcore_bytes::Bytes;
use parity_bytes::Bytes;
use substrate_network_libp2p::*;
use ethkey::{Random, Generator};
use io::TimerToken;
+3 -2
View File
@@ -21,6 +21,7 @@ use client::error::Error;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT};
use runtime_primitives::generic::BlockId;
use runtime_primitives::bft::Justification;
use primitives::{KeccakHasher, RlpCodec};
/// Local client abstraction for the network.
pub trait Client<Block: BlockT>: Send + Sync {
@@ -53,8 +54,8 @@ pub trait Client<Block: BlockT>: Send + Sync {
}
impl<B, E, Block> Client<Block> for SubstrateClient<B, E, Block> where
B: client::backend::Backend<Block> + Send + Sync + 'static,
E: CallExecutor<Block> + Send + Sync + 'static,
B: client::backend::Backend<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
E: CallExecutor<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
Block: BlockT,
{
fn import(&self, origin: BlockOrigin, header: Block::Header, justification: Justification<Block::Hash>, body: Option<Vec<Block::Extrinsic>>) -> Result<ImportResult, Error> {
+4 -1
View File
@@ -26,6 +26,7 @@ use runtime_primitives::traits::Block as BlockT;
use runtime_primitives::generic::BlockId;
use io::SyncIo;
use protocol::{Context, Protocol};
use primitives::{KeccakHasher, RlpCodec};
use config::ProtocolConfig;
use service::TransactionPool;
use network_libp2p::{NodeIndex, SessionInfo, Severity};
@@ -172,7 +173,9 @@ impl Peer {
fn flush(&self) {
}
fn generate_blocks<F>(&self, count: usize, mut edit_block: F) where F: FnMut(&mut BlockBuilder<test_client::Backend, test_client::Executor, Block>) {
fn generate_blocks<F>(&self, count: usize, mut edit_block: F)
where F: FnMut(&mut BlockBuilder<test_client::Backend, test_client::Executor, Block, KeccakHasher, RlpCodec>)
{
for _ in 0 .. count {
let mut builder = self.client.new_block().unwrap();
edit_block(&mut builder);
+19 -4
View File
@@ -8,19 +8,28 @@ crunchy = "0.1"
substrate-runtime-std = { path = "../runtime-std", default_features = false }
substrate-codec = { path = "../codec", default_features = false }
substrate-codec-derive = { path = "../codec/derive", default_features = false }
fixed-hash = { git = "https://github.com/rphmeier/primitives.git", branch = "compile-for-wasm", default_features = false }
elastic-array = {version = "0.10", optional = true }
fixed-hash = { git = "https://github.com/paritytech/parity-common", default_features = false }
rustc-hex = { version = "2.0", default_features = false }
serde = { version = "1.0", default_features = false }
serde_derive = { version = "1.0", optional = true }
uint = { git = "https://github.com/rphmeier/primitives.git", branch = "compile-for-wasm", default_features = false }
uint = { git = "https://github.com/paritytech/parity-common", default_features = false }
rlp = { git = "https://github.com/paritytech/parity-common", optional = true }
twox-hash = { version = "1.1.0", optional = true }
byteorder = { version = "1.1", default_features = false }
blake2-rfc = { version = "0.2.18", optional = true }
wasmi = { version = "0.4", optional = true }
hashdb = { git = "https://github.com/paritytech/parity-common", default_features = false }
patricia-trie = { git = "https://github.com/paritytech/parity-common", optional = true }
plain_hasher = { git = "https://github.com/paritytech/parity-common", default_features = false }
blake2-rfc = { version = "0.2.18", optional = true }
# Switch back to Blake after PoC-3 is out and remove this
tiny-keccak = { version = "1.4", optional = true }
[dev-dependencies]
substrate-serializer = { path = "../serializer" }
pretty_assertions = "0.4"
heapsize = "0.4"
[features]
default = ["std"]
@@ -28,12 +37,18 @@ std = [
"wasmi",
"uint/std",
"fixed-hash/std",
"fixed-hash/heapsizeof",
"fixed-hash/libc",
"substrate-codec/std",
"substrate-runtime-std/std",
"serde/std",
"rustc-hex/std",
"twox-hash",
"blake2-rfc",
"tiny-keccak",
"serde_derive",
"byteorder/std"
"byteorder/std",
"patricia-trie",
"rlp",
"elastic-array",
]
@@ -21,6 +21,10 @@ use serde::{Serialize, Serializer, Deserialize, Deserializer};
#[cfg(feature = "std")]
use bytes;
#[cfg(feature = "std")]
use core::cmp;
#[cfg(feature = "std")]
use rlp::{Rlp, RlpStream, DecoderError};
macro_rules! impl_rest {
($name: ident, $len: expr) => {
@@ -49,6 +53,29 @@ macro_rules! impl_rest {
<[u8; $len] as ::codec::Decode>::decode(input).map($name)
}
}
#[cfg(feature = "std")]
impl ::rlp::Encodable for $name {
fn rlp_append(&self, s: &mut RlpStream) {
s.encoder().encode_value(self);
}
}
#[cfg(feature = "std")]
impl ::rlp::Decodable for $name {
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
rlp.decoder().decode_value(|bytes| match bytes.len().cmp(&$len) {
cmp::Ordering::Less => Err(DecoderError::RlpIsTooShort),
cmp::Ordering::Greater => Err(DecoderError::RlpIsTooBig),
cmp::Ordering::Equal => {
let mut t = [0u8; $len];
t.copy_from_slice(bytes);
Ok($name(t))
}
})
}
}
}
}
@@ -63,6 +90,26 @@ impl_rest!(H512, 64);
mod tests {
use super::*;
use substrate_serializer as ser;
use rlp::{Encodable, RlpStream};
#[test]
fn test_hash_is_encodable() {
let h = H160::from(21);
let mut s = RlpStream::new();
h.rlp_append(&mut s);
assert_eq!(s.drain().into_vec(), &[148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21]);
}
#[test]
fn test_hash_is_decodable() {
let data = vec![148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123];
let res = ::rlp::decode::<H160>(&data);
assert!(res.is_ok());
assert_eq!(res.unwrap(), H160::from(123));
let res = ::rlp::decode::<H256>(&data);
assert!(res.is_err());
}
#[test]
fn test_h160() {
@@ -109,4 +156,11 @@ mod tests {
assert!(ser::from_str::<H256>("\"0\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>("\"10\"").unwrap_err().is_data());
}
#[test]
fn test_heapsizeof() {
use heapsize::HeapSizeOf;
let h = H256::new();
assert_eq!(h.heap_size_of_children(), 0);
}
}
@@ -0,0 +1,88 @@
// Copyright 2018 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Polkadot Blake2b Hasher implementation
use hashdb::Hasher;
use plain_hasher::PlainHasher;
use hash::H256;
// Use this when switching to Blake2 after PoC-3
// pub mod blake {
// use super::{Hasher, PlainHasher, H256};
// #[cfg(feature = "std")]
// use hashing::blake2_256;
// #[cfg(not(feature = "std"))]
// extern "C" {
// fn ext_blake2_256(data: *const u8, len: u32, out: *mut u8);
// }
// #[cfg(not(feature = "std"))]
// fn blake2_256(data: &[u8]) -> [u8; 32] {
// let mut result: [u8; 32] = Default::default();
// unsafe {
// ext_blake2_256(data.as_ptr(), data.len() as u32, result.as_mut_ptr());
// }
// result
// }
// /// Concrete implementation of Hasher using Blake2b 256-bit hashes
// #[derive(Debug)]
// pub struct BlakeHasher;
// impl Hasher for BlakeHasher {
// type Out = H256;
// type StdHasher = PlainHasher;
// const LENGTH:usize = 32;
// fn hash(x: &[u8]) -> Self::Out {
// blake2_256(x).into()
// }
// }
// }
pub mod keccak {
use super::{Hasher, PlainHasher, H256};
#[cfg(feature = "std")]
use tiny_keccak::keccak256;
#[cfg(not(feature = "std"))]
extern "C" {
fn ext_keccak256(data: *const u8, len: u32, out: *mut u8);
}
#[cfg(not(feature = "std"))]
fn keccak256(data: &[u8]) -> [u8; 32] {
let mut result: [u8; 32] = Default::default();
unsafe {
ext_keccak256(data.as_ptr(), data.len() as u32, result.as_mut_ptr());
}
result
}
/// Concrete implementation of Hasher using Keccak 256-bit hashes
#[derive(Debug)]
pub struct KeccakHasher;
impl Hasher for KeccakHasher {
type Out = H256;
type StdHasher = PlainHasher;
const LENGTH : usize = 32;
fn hash(x: &[u8]) -> Self::Out {
keccak256(x).into()
}
}
}
+27 -1
View File
@@ -33,13 +33,20 @@ extern crate substrate_codec_derive;
extern crate rustc_hex;
extern crate byteorder;
extern crate substrate_codec as codec;
#[cfg(feature = "std")]
extern crate rlp;
#[cfg(feature = "std")]
extern crate serde;
#[cfg(feature = "std")]
extern crate twox_hash;
#[cfg(feature = "std")]
extern crate blake2_rfc;
// Switch back to Blake after PoC-3 is out
#[cfg(feature = "std")]
extern crate tiny_keccak;
#[cfg(feature = "std")]
#[macro_use]
extern crate serde_derive;
@@ -47,12 +54,21 @@ extern crate serde_derive;
extern crate core;
#[cfg(feature = "std")]
extern crate wasmi;
extern crate hashdb;
extern crate plain_hasher;
#[cfg(feature = "std")]
extern crate patricia_trie;
#[cfg(feature = "std")]
extern crate elastic_array;
extern crate substrate_runtime_std as rstd;
#[cfg(test)]
extern crate substrate_serializer;
#[cfg(test)]
extern crate heapsize;
#[cfg(test)]
#[macro_use]
extern crate pretty_assertions;
@@ -77,18 +93,28 @@ pub use hashing::{blake2_256, twox_128, twox_256};
pub mod hexdisplay;
pub mod hash;
mod hasher;
pub mod sandbox;
pub mod storage;
pub mod uint;
mod authority_id;
#[cfg(feature = "std")]
mod rlp_codec;
#[cfg(test)]
mod tests;
pub use self::hash::{H160, H256, H512};
pub use self::uint::{U256, U512};
pub use self::uint::U256;
pub use authority_id::AuthorityId;
// Switch back to Blake after PoC-3 is out
// pub use self::hasher::blake::BlakeHasher;
pub use self::hasher::keccak::KeccakHasher;
#[cfg(feature = "std")]
pub use self::rlp_codec::RlpCodec;
/// A 512-bit value interpreted as a signature.
pub type Signature = hash::H512;
@@ -0,0 +1,129 @@
// Copyright 2018 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Polkadot Blake2b (trie) NodeCodec implementation
use elastic_array::{ElasticArray1024, ElasticArray128};
use hashdb::Hasher;
use rlp::{DecoderError, RlpStream, Rlp, Prototype};
use core::marker::PhantomData;
use patricia_trie::{NibbleSlice, NodeCodec, node::Node, ChildReference};
use hash::H256;
// When switching to Blake2, use this instead:
// use BlakeHasher;
use KeccakHasher;
/// Concrete implementation of a `NodeCodec` with Rlp encoding, generic over the `Hasher`
pub struct RlpNodeCodec<H: Hasher> {mark: PhantomData<H>}
/// Convenience type for a Keccak/Rlp flavoured NodeCodec
pub type RlpCodec = RlpNodeCodec<KeccakHasher>;
// When switching to Blake2, use this instead:
// pub type RlpCodec = RlpNodeCodec<BlakeHasher>;
impl NodeCodec<KeccakHasher> for RlpCodec {
type Error = DecoderError;
// When switching to Blake2, use this null node
// const HASHED_NULL_NODE : H256 = H256( [0x45, 0xb0, 0xcf, 0xc2, 0x20, 0xce, 0xec, 0x5b, 0x7c, 0x1c, 0x62, 0xc4, 0xd4, 0x19, 0x3d, 0x38, 0xe4, 0xeb, 0xa4, 0x8e, 0x88, 0x15, 0x72, 0x9c, 0xe7, 0x5f, 0x9c, 0xa, 0xb0, 0xe4, 0xc1, 0xc0] );
const HASHED_NULL_NODE : H256 = H256( [0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0, 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x01, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21] );
fn decode(data: &[u8]) -> ::std::result::Result<Node, Self::Error> {
let r = Rlp::new(data);
match r.prototype()? {
// either leaf or extension - decode first item with NibbleSlice::???
// and use is_leaf return to figure out which.
// if leaf, second item is a value (is_data())
// if extension, second item is a node (either SHA3 to be looked up and
// fed back into this function or inline RLP which can be fed back into this function).
Prototype::List(2) => match NibbleSlice::from_encoded(r.at(0)?.data()?) {
(slice, true) => Ok(Node::Leaf(slice, r.at(1)?.data()?)),
(slice, false) => Ok(Node::Extension(slice, r.at(1)?.as_raw())),
},
// branch - first 16 are nodes, 17th is a value (or empty).
Prototype::List(17) => {
let mut nodes = [&[] as &[u8]; 16];
for i in 0..16 {
nodes[i] = r.at(i)?.as_raw();
}
Ok(Node::Branch(nodes, if r.at(16)?.is_empty() { None } else { Some(r.at(16)?.data()?) }))
},
// an empty branch index.
Prototype::Data(0) => Ok(Node::Empty),
// something went wrong.
_ => Err(DecoderError::Custom("Rlp is not valid."))
}
}
fn try_decode_hash(data: &[u8]) -> Option<<KeccakHasher as Hasher>::Out> {
let r = Rlp::new(data);
if r.is_data() && r.size() == KeccakHasher::LENGTH {
Some(r.as_val().expect("Hash is the correct size; qed"))
} else {
None
}
}
fn is_empty_node(data: &[u8]) -> bool {
Rlp::new(data).is_empty()
}
fn empty_node() -> ElasticArray1024<u8> {
let mut stream = RlpStream::new();
stream.append_empty_data();
stream.drain()
}
fn leaf_node(partial: &[u8], value: &[u8]) -> ElasticArray1024<u8> {
let mut stream = RlpStream::new_list(2);
stream.append(&partial);
stream.append(&value);
stream.drain()
}
fn ext_node(partial: &[u8], child_ref: ChildReference<<KeccakHasher as Hasher>::Out>) -> ElasticArray1024<u8> {
let mut stream = RlpStream::new_list(2);
stream.append(&partial);
match child_ref {
ChildReference::Hash(h) => stream.append(&h),
ChildReference::Inline(inline_data, len) => {
let bytes = &AsRef::<[u8]>::as_ref(&inline_data)[..len];
stream.append_raw(bytes, 1)
},
};
stream.drain()
}
fn branch_node<I>(children: I, value: Option<ElasticArray128<u8>>) -> ElasticArray1024<u8>
where I: IntoIterator<Item=Option<ChildReference<<KeccakHasher as Hasher>::Out>>>
{
let mut stream = RlpStream::new_list(17);
for child_ref in children {
match child_ref {
Some(c) => match c {
ChildReference::Hash(h) => stream.append(&h),
ChildReference::Inline(inline_data, len) => {
let bytes = &AsRef::<[u8]>::as_ref(&inline_data)[..len];
stream.append_raw(bytes, 1)
},
},
None => stream.append_empty_data()
};
}
if let Some(value) = value {
stream.append(&&*value);
} else {
stream.append_empty_data();
}
stream.drain()
}
}
+1 -4
View File
@@ -44,9 +44,7 @@ macro_rules! impl_serde {
}
construct_uint!(U256, 4);
construct_uint!(U512, 8);
impl_serde!(U256, 4);
impl_serde!(U512, 8);
#[cfg(test)]
mod tests {
@@ -68,7 +66,7 @@ mod tests {
($name::from(1_000), "0x3e8"),
($name::from(100_000), "0x186a0"),
($name::from(u64::max_value()), "0xffffffffffffffff"),
($name::from(u64::max_value()) + 1.into(), "0x10000000000000000"),
($name::from(u64::max_value()) + $name::from(1), "0x10000000000000000"),
];
for (number, expected) in tests {
@@ -87,7 +85,6 @@ mod tests {
}
test!(U256, test_u256);
test!(U512, test_u512);
#[test]
fn test_large_values() {
@@ -9,5 +9,6 @@ jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git" }
jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc.git" }
jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc.git" }
log = "0.3"
serde = "1.0"
substrate-rpc = { path = "../rpc", version = "0.1" }
substrate-runtime-primitives = { path = "../runtime/primitives" }
+6 -4
View File
@@ -24,6 +24,7 @@ extern crate jsonrpc_core as rpc;
extern crate jsonrpc_http_server as http;
extern crate jsonrpc_pubsub as pubsub;
extern crate jsonrpc_ws_server as ws;
extern crate serde;
extern crate substrate_runtime_primitives;
#[macro_use]
@@ -38,16 +39,17 @@ pub type HttpServer = http::Server;
pub type WsServer = ws::Server;
/// Construct rpc `IoHandler`
pub fn rpc_handler<Block: BlockT, S, C, A, Y>(
pub fn rpc_handler<Block, PendingExtrinsics, S, C, A, Y>(
state: S,
chain: C,
author: A,
system: Y,
) -> RpcHandler where
Block: 'static,
Block: BlockT + 'static,
PendingExtrinsics: serde::Serialize + serde::de::DeserializeOwned + Send + Sync + 'static,
S: apis::state::StateApi<Block::Hash, Metadata=Metadata>,
C: apis::chain::ChainApi<Block::Hash, Block::Header, Metadata=Metadata>,
A: apis::author::AuthorApi<Block::Hash, Block::Extrinsic, Metadata=Metadata>,
C: apis::chain::ChainApi<Block::Hash, Block::Header, Block::Extrinsic, Metadata=Metadata>,
A: apis::author::AuthorApi<Block::Hash, Block::Extrinsic, PendingExtrinsics, Metadata=Metadata>,
Y: apis::system::SystemApi,
{
let mut io = pubsub::PubSubHandler::default();
+17 -8
View File
@@ -26,7 +26,7 @@ use extrinsic_pool::{
};
use jsonrpc_macros::pubsub;
use jsonrpc_pubsub::SubscriptionId;
use primitives::Bytes;
use primitives::{Bytes, KeccakHasher, RlpCodec};
use rpc::futures::{Sink, Stream, Future};
use runtime_primitives::{generic, traits};
use subscriptions::Subscriptions;
@@ -41,7 +41,7 @@ use self::error::Result;
build_rpc_trait! {
/// Substrate authoring RPC API
pub trait AuthorApi<Hash, Extrinsic> {
pub trait AuthorApi<Hash, Extrinsic, PendingExtrinsics> {
type Metadata;
/// Submit extrinsic for inclusion in block.
@@ -51,6 +51,10 @@ build_rpc_trait! {
#[rpc(name = "author_submitExtrinsic")]
fn submit_extrinsic(&self, Bytes) -> Result<Hash>;
/// Returns all pending extrinsics, potentially grouped by sender.
#[rpc(name = "author_pendingExtrinsics")]
fn pending_extrinsics(&self) -> Result<PendingExtrinsics>;
#[pubsub(name = "author_extrinsicUpdate")] {
/// Submit an extrinsic to watch.
#[rpc(name = "author_submitAndWatchExtrinsic")]
@@ -60,7 +64,6 @@ build_rpc_trait! {
#[rpc(name = "author_unwatchExtrinsic")]
fn unwatch_extrinsic(&self, SubscriptionId) -> Result<bool>;
}
}
}
@@ -85,12 +88,13 @@ impl<B, E, Block: traits::Block, P> Author<B, E, Block, P> {
}
}
impl<B, E, Block, P, Ex, Hash> AuthorApi<Hash, Ex> for Author<B, E, Block, P> where
B: client::backend::Backend<Block> + Send + Sync + 'static,
E: client::CallExecutor<Block> + Send + Sync + 'static,
impl<B, E, Block, P, Ex, Hash, InPool> AuthorApi<Hash, Ex, InPool> for Author<B, E, Block, P> where
B: client::backend::Backend<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
E: client::CallExecutor<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
Block: traits::Block + 'static,
Hash: traits::MaybeSerializeDebug + Sync + Send + 'static,
P: ExtrinsicPool<Ex, generic::BlockId<Block>, Hash>,
Hash: traits::MaybeSerializeDebug + Send + Sync + 'static,
InPool: traits::MaybeSerializeDebug + Send + Sync + 'static,
P: ExtrinsicPool<Ex, generic::BlockId<Block>, Hash, InPool=InPool>,
P::Error: 'static,
Ex: Codec,
{
@@ -112,6 +116,10 @@ impl<B, E, Block, P, Ex, Hash> AuthorApi<Hash, Ex> for Author<B, E, Block, P> wh
)
}
fn pending_extrinsics(&self) -> Result<InPool> {
Ok(self.pool.all())
}
fn watch_extrinsic(&self, _metadata: Self::Metadata, subscriber: pubsub::Subscriber<Status<Hash>>, xt: Bytes) {
let submit = || -> Result<_> {
@@ -146,3 +154,4 @@ impl<B, E, Block, P, Ex, Hash> AuthorApi<Hash, Ex> for Author<B, E, Block, P> wh
Ok(self.subscriptions.cancel(id))
}
}
@@ -46,6 +46,7 @@ impl fmt::Display for Error {
impl<BlockHash> api::ExtrinsicPool<Extrinsic, BlockHash, u64> for DummyTxPool {
type Error = Error;
type InPool = Vec<u8>;
/// Submit extrinsic for inclusion in block.
fn submit(&self, _block: BlockHash, xt: Vec<Extrinsic>) -> Result<Vec<Hash>, Self::Error> {
@@ -79,6 +80,10 @@ impl<BlockHash> api::ExtrinsicPool<Extrinsic, BlockHash, u64> for DummyTxPool {
fn import_notification_stream(&self) -> api::EventStream {
unreachable!()
}
fn all(&self) -> Self::InPool {
vec![1, 2, 3, 4, 5]
}
}
#[test]
@@ -143,3 +148,18 @@ fn should_watch_extrinsic() {
Some(r#"{"jsonrpc":"2.0","method":"test","params":{"result":{"usurped":5},"subscription":0}}"#.into())
);
}
#[test]
fn should_return_pending_extrinsics() {
let runtime = runtime::Runtime::new().unwrap();
let p = Author {
client: Arc::new(test_client::new()),
pool: Arc::new(DummyTxPool::default()),
subscriptions: Subscriptions::new(runtime.executor()),
};
assert_matches!(
p.pending_extrinsics(),
Ok(ref expected) if expected == &[1u8, 2, 3, 4, 5]
);
}
+14 -5
View File
@@ -23,9 +23,10 @@ use jsonrpc_macros::pubsub;
use jsonrpc_pubsub::SubscriptionId;
use rpc::Result as RpcResult;
use rpc::futures::{stream, Future, Sink, Stream};
use runtime_primitives::generic::BlockId;
use runtime_primitives::generic::{BlockId, SignedBlock};
use runtime_primitives::traits::Block as BlockT;
use tokio::runtime::TaskExecutor;
use primitives::{KeccakHasher, RlpCodec};
use subscriptions::Subscriptions;
@@ -37,13 +38,17 @@ use self::error::Result;
build_rpc_trait! {
/// Polkadot blockchain API
pub trait ChainApi<Hash, Header> {
pub trait ChainApi<Hash, Header, Extrinsic> {
type Metadata;
/// Get header of a relay chain block.
#[rpc(name = "chain_getHeader")]
fn header(&self, Hash) -> Result<Option<Header>>;
/// Get header and body of a relay chain block.
#[rpc(name = "chain_getBlock")]
fn block(&self, Hash) -> Result<Option<SignedBlock<Header, Extrinsic, Hash>>>;
/// Get hash of the head.
#[rpc(name = "chain_getHead")]
fn head(&self) -> Result<Hash>;
@@ -78,10 +83,10 @@ impl<B, E, Block: BlockT> Chain<B, E, Block> {
}
}
impl<B, E, Block> ChainApi<Block::Hash, Block::Header> for Chain<B, E, Block> where
impl<B, E, Block> ChainApi<Block::Hash, Block::Header, Block::Extrinsic> for Chain<B, E, Block> where
Block: BlockT + 'static,
B: client::backend::Backend<Block> + Send + Sync + 'static,
E: client::CallExecutor<Block> + Send + Sync + 'static,
B: client::backend::Backend<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
E: client::CallExecutor<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
{
type Metadata = ::metadata::Metadata;
@@ -89,6 +94,10 @@ impl<B, E, Block> ChainApi<Block::Hash, Block::Header> for Chain<B, E, Block> wh
Ok(self.client.header(&BlockId::Hash(hash))?)
}
fn block(&self, hash: Block::Hash) -> Result<Option<SignedBlock<Block::Header, Block::Extrinsic, Block::Hash>>> {
Ok(self.client.block(&BlockId::Hash(hash))?)
}
fn head(&self) -> Result<Block::Hash> {
Ok(self.client.info()?.chain.best_hash)
}
+42 -1
View File
@@ -18,7 +18,7 @@ use super::*;
use jsonrpc_macros::pubsub;
use client::BlockOrigin;
use test_client::{self, TestClient};
use test_client::runtime::Header;
use test_client::runtime::{Block, Header};
#[test]
fn should_return_header() {
@@ -46,6 +46,47 @@ fn should_return_header() {
);
}
#[test]
fn should_return_a_block() {
let core = ::tokio::runtime::Runtime::new().unwrap();
let remote = core.executor();
let api = Chain {
client: Arc::new(test_client::new()),
subscriptions: Subscriptions::new(remote),
};
let block = api.client.new_block().unwrap().bake().unwrap();
let block_hash = block.hash();
api.client.justify_and_import(BlockOrigin::Own, block).unwrap();
// Genesis block is not justified, so we can't query it?
assert_matches!(
api.block(api.client.genesis_hash()),
Ok(None)
);
assert_matches!(
api.block(block_hash),
Ok(Some(ref x)) if x.block == Block {
header: Header {
parent_hash: api.client.genesis_hash(),
number: 1,
state_root: x.block.header.state_root.clone(),
extrinsics_root: "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".into(),
digest: Default::default(),
},
extrinsics: vec![],
}
);
assert_matches!(
api.block(5.into()),
Ok(None)
);
}
#[test]
fn should_notify_about_latest_block() {
let mut core = ::tokio::runtime::Runtime::new().unwrap();
+5 -4
View File
@@ -27,6 +27,7 @@ use jsonrpc_macros::pubsub;
use jsonrpc_pubsub::SubscriptionId;
use primitives::hexdisplay::HexDisplay;
use primitives::storage::{StorageKey, StorageData, StorageChangeSet};
use primitives::{KeccakHasher, RlpCodec};
use rpc::Result as RpcResult;
use rpc::futures::{stream, Future, Sink, Stream};
use runtime_primitives::generic::BlockId;
@@ -101,8 +102,8 @@ impl<B, E, Block: BlockT> State<B, E, Block> {
impl<B, E, Block> State<B, E, Block> where
Block: BlockT + 'static,
B: client::backend::Backend<Block> + Send + Sync + 'static,
E: CallExecutor<Block> + Send + Sync + 'static,
B: client::backend::Backend<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
E: CallExecutor<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
{
fn unwrap_or_best(&self, hash: Trailing<Block::Hash>) -> Result<Block::Hash> {
Ok(match hash.into() {
@@ -114,8 +115,8 @@ impl<B, E, Block> State<B, E, Block> where
impl<B, E, Block> StateApi<Block::Hash> for State<B, E, Block> where
Block: BlockT + 'static,
B: client::backend::Backend<Block> + Send + Sync + 'static,
E: CallExecutor<Block> + Send + Sync + 'static,
B: client::backend::Backend<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
E: CallExecutor<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
{
type Metadata = ::metadata::Metadata;
+12 -7
View File
@@ -29,12 +29,16 @@ pub extern crate substrate_codec as codec;
// re-export hashing functions.
pub use primitives::{blake2_256, twox_128, twox_256};
pub use primitives::KeccakHasher;
// Switch to this after PoC-3
// pub use primitives::BlakeHasher;
pub use substrate_state_machine::{Externalities, TestExternalities};
use primitives::hexdisplay::HexDisplay;
use primitives::H256;
// TODO: use the real error, not NoError.
environmental!(ext: trait Externalities);
environmental!(ext: trait Externalities<KeccakHasher>);
/// Get `key` from storage and return a `Vec`, empty if there's a problem.
pub fn storage(key: &[u8]) -> Option<Vec<u8>> {
@@ -90,10 +94,10 @@ pub fn chain_id() -> u64 {
}
/// "Commit" all existing operations and get the resultant storage root.
pub fn storage_root() -> [u8; 32] {
pub fn storage_root() -> H256 {
ext::with(|ext|
ext.storage_root()
).unwrap_or([0u8; 32])
).unwrap_or(H256::new())
}
/// A trie root formed from the enumerated items.
@@ -125,7 +129,8 @@ pub fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) ->
/// Execute the given closure with global function available whose functionality routes into the
/// externalities `ext`. Forwards the value that the closure returns.
pub fn with_externalities<R, F: FnOnce() -> R>(ext: &mut Externalities, f: F) -> R {
// NOTE: need a concrete hasher here due to limitations of the `environmental!` macro, otherwise a type param would have been fine I think.
pub fn with_externalities<R, F: FnOnce() -> R>(ext: &mut Externalities<KeccakHasher>, f: F) -> R {
ext::using(ext, f)
}
@@ -191,7 +196,7 @@ mod std_tests {
#[test]
fn storage_works() {
let mut t = TestExternalities::new();
let mut t = TestExternalities::<KeccakHasher>::new();
assert!(with_externalities(&mut t, || {
assert_eq!(storage(b"hello"), None);
set_storage(b"hello", b"world");
@@ -212,7 +217,7 @@ mod std_tests {
#[test]
fn read_storage_works() {
let mut t: TestExternalities = map![
let mut t: TestExternalities<KeccakHasher> = map![
b":test".to_vec() => b"\x0b\0\0\0Hello world".to_vec()
];
@@ -228,7 +233,7 @@ mod std_tests {
#[test]
fn clear_prefix_works() {
let mut t: TestExternalities = map![
let mut t: TestExternalities<KeccakHasher> = map![
b":a".to_vec() => b"\x0b\0\0\0Hello world".to_vec(),
b":abcd".to_vec() => b"\x0b\0\0\0Hello world".to_vec(),
b":abc".to_vec() => b"\x0b\0\0\0Hello world".to_vec(),
@@ -45,6 +45,11 @@ use runtime_support::storage::unhashed::StorageVec;
use primitives::traits::{RefInto, MaybeSerializeDebug, MaybeEmpty};
use primitives::bft::MisbehaviorReport;
#[cfg(any(feature = "std", test))]
use substrate_primitives::KeccakHasher;
#[cfg(any(feature = "std", test))]
use std::collections::HashMap;
pub const AUTHORITY_AT: &'static [u8] = b":auth:";
pub const AUTHORITY_COUNT: &'static [u8] = b":auth:len";
@@ -146,14 +151,14 @@ impl<T: Trait> Default for GenesisConfig<T> {
#[cfg(any(feature = "std", test))]
impl<T: Trait> primitives::BuildStorage for GenesisConfig<T>
{
fn build_storage(self) -> ::std::result::Result<runtime_io::TestExternalities, String> {
fn build_storage(self) -> ::std::result::Result<HashMap<Vec<u8>, Vec<u8>>, String> {
use codec::{Encode, KeyedVec};
let auth_count = self.authorities.len() as u32;
let mut r: runtime_io::TestExternalities = self.authorities.into_iter().enumerate().map(|(i, v)|
let mut r: runtime_io::TestExternalities<KeccakHasher> = self.authorities.into_iter().enumerate().map(|(i, v)|
((i as u32).to_keyed_vec(AUTHORITY_AT), v.encode())
).collect();
r.insert(AUTHORITY_COUNT.to_vec(), auth_count.encode());
r.insert(CODE.to_vec(), self.code);
Ok(r)
Ok(r.into())
}
}
@@ -7,6 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
serde = { version = "1.0", default_features = false }
serde_derive = { version = "1.0", optional = true }
substrate-codec = { path = "../../codec", default_features = false }
substrate-primitives = { path = "../../primitives" }
substrate-runtime-consensus = { path = "../../runtime/consensus", default_features = false }
substrate-runtime-primitives = { path = "../../runtime/primitives" }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
@@ -136,6 +136,7 @@ pub fn buy_gas<T: Trait>(
return Err("not enough funds for transaction fee");
}
<staking::Module<T>>::set_free_balance(transactor, b - cost);
<staking::Module<T>>::decrease_total_stake_by(cost);
Ok(GasMeter {
gas_left: gas_limit,
gas_price,
@@ -147,4 +148,5 @@ pub fn refund_unused_gas<T: Trait>(transactor: &T::AccountId, gas_meter: GasMete
let b = <staking::Module<T>>::free_balance(transactor);
let refund = <T::Gas as As<T::Balance>>::as_(gas_meter.gas_left) * gas_meter.gas_price;
<staking::Module<T>>::set_free_balance(transactor, b + refund);
<staking::Module<T>>::increase_total_stake_by(refund);
}
@@ -22,6 +22,8 @@ use runtime_primitives;
use runtime_io::{self, twox_128};
use runtime_support::StorageValue;
use codec::Encode;
use std::collections::HashMap;
use substrate_primitives::KeccakHasher;
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -35,14 +37,14 @@ pub struct GenesisConfig<T: Trait> {
}
impl<T: Trait> runtime_primitives::BuildStorage for GenesisConfig<T> {
fn build_storage(self) -> Result<runtime_io::TestExternalities, String> {
let r: runtime_io::TestExternalities = map![
fn build_storage(self) -> ::std::result::Result<HashMap<Vec<u8>, Vec<u8>>, String> {
let r: runtime_io::TestExternalities<KeccakHasher> = map![
twox_128(<ContractFee<T>>::key()).to_vec() => self.contract_fee.encode(),
twox_128(<CallBaseFee<T>>::key()).to_vec() => self.call_base_fee.encode(),
twox_128(<CreateBaseFee<T>>::key()).to_vec() => self.create_base_fee.encode(),
twox_128(<GasPrice<T>>::key()).to_vec() => self.gas_price.encode(),
twox_128(<MaxDepth<T>>::key()).to_vec() => self.max_depth.encode()
];
Ok(r)
Ok(r.into())
}
}
@@ -65,6 +65,7 @@ extern crate substrate_runtime_session as session;
extern crate substrate_runtime_support as runtime_support;
extern crate substrate_runtime_primitives as runtime_primitives;
extern crate substrate_primitives;
#[cfg(test)]
#[macro_use]
@@ -20,6 +20,7 @@ use runtime_primitives::testing::{Digest, H256, Header};
use runtime_primitives::traits::{BlakeTwo256, HasPublicAux, Identity};
use runtime_primitives::BuildStorage;
use runtime_support::StorageMap;
use substrate_primitives::KeccakHasher;
use wabt;
use {
consensus, runtime_io, session, staking, system, timestamp, CodeOf, ContractAddressFor,
@@ -73,7 +74,7 @@ impl ContractAddressFor<u64> for DummyContractAddressFor {
}
}
fn new_test_ext(existential_deposit: u64, gas_price: u64) -> runtime_io::TestExternalities {
fn new_test_ext(existential_deposit: u64, gas_price: u64) -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = system::GenesisConfig::<Test>::default()
.build_storage()
.unwrap();
@@ -126,7 +127,7 @@ fn new_test_ext(existential_deposit: u64, gas_price: u64) -> runtime_io::TestExt
}.build_storage()
.unwrap(),
);
t
t.into()
}
const CODE_TRANSFER: &str = r#"
@@ -162,7 +163,9 @@ fn contract_transfer() {
<CodeOf<Test>>::insert(1, code_transfer.to_vec());
Staking::set_free_balance(&0, 100_000_000);
Staking::increase_total_stake_by(100_000_000);
Staking::set_free_balance(&1, 11);
Staking::increase_total_stake_by(11);
assert_ok!(Contract::call(&0, 1, 3, 100_000, Vec::new()));
@@ -195,7 +198,9 @@ fn contract_transfer_oog() {
<CodeOf<Test>>::insert(1, code_transfer.to_vec());
Staking::set_free_balance(&0, 100_000_000);
Staking::increase_total_stake_by(100_000_000);
Staking::set_free_balance(&1, 11);
Staking::increase_total_stake_by(11);
assert_err!(
Contract::call(&0, 1, 3, 276, Vec::new()),
@@ -232,7 +237,9 @@ fn contract_transfer_max_depth() {
<CodeOf<Test>>::insert(CONTRACT_SHOULD_TRANSFER_TO, code_transfer.to_vec());
Staking::set_free_balance(&0, 100_000_000);
Staking::increase_total_stake_by(100_000_000);
Staking::set_free_balance(&CONTRACT_SHOULD_TRANSFER_TO, 11);
Staking::increase_total_stake_by(11);
assert_err!(
Contract::call(&0, CONTRACT_SHOULD_TRANSFER_TO, 3, 100_000, Vec::new()),
@@ -331,8 +338,10 @@ fn contract_create() {
with_externalities(&mut new_test_ext(0, 2), || {
Staking::set_free_balance(&0, 100_000_000);
Staking::increase_total_stake_by(100_000_000);
Staking::set_free_balance(&1, 0);
Staking::set_free_balance(&9, 30);
Staking::increase_total_stake_by(30);
<CodeOf<Test>>::insert(1, code_create.to_vec());
@@ -383,7 +392,9 @@ fn top_level_create() {
);
Staking::set_free_balance(&0, 100_000_000);
Staking::increase_total_stake_by(100_000_000);
Staking::set_free_balance(&derived_address, 30);
Staking::increase_total_stake_by(30);
assert_ok!(Contract::create(
&0,
@@ -423,6 +434,7 @@ fn refunds_unused_gas() {
<CodeOf<Test>>::insert(1, code_nop.to_vec());
Staking::set_free_balance(&0, 100_000_000);
Staking::increase_total_stake_by(100_000_000);
assert_ok!(Contract::call(&0, 1, 0, 100_000, Vec::new(),));
@@ -436,6 +448,7 @@ fn call_with_zero_value() {
<CodeOf<Test>>::insert(1, vec![]);
Staking::set_free_balance(&0, 100_000_000);
Staking::increase_total_stake_by(100_000_000);
assert_ok!(Contract::call(&0, 1, 0, 100_000, Vec::new(),));
@@ -449,6 +462,7 @@ fn create_with_zero_endowment() {
with_externalities(&mut new_test_ext(0, 2), || {
Staking::set_free_balance(&0, 100_000_000);
Staking::increase_total_stake_by(100_000_000);
assert_ok!(Contract::create(&0, 0, 100_000, code_nop, Vec::new(),));
@@ -467,10 +481,12 @@ fn account_removal_removes_storage() {
// Setup two accounts with free balance above than exsistential threshold.
{
Staking::set_free_balance(&1, 110);
Staking::increase_total_stake_by(110);
<StorageOf<Test>>::insert(1, b"foo".to_vec(), b"1".to_vec());
<StorageOf<Test>>::insert(1, b"bar".to_vec(), b"2".to_vec());
Staking::set_free_balance(&2, 110);
Staking::increase_total_stake_by(110);
<StorageOf<Test>>::insert(2, b"hello".to_vec(), b"3".to_vec());
<StorageOf<Test>>::insert(2, b"world".to_vec(), b"4".to_vec());
}
@@ -515,6 +531,7 @@ fn top_level_call_refunds_even_if_fails() {
<CodeOf<Test>>::insert(1, code_unreachable.to_vec());
Staking::set_free_balance(&0, 100_000_000);
Staking::increase_total_stake_by(100_000_000);
assert_err!(
Contract::call(&0, 1, 0, 100_000, Vec::new()),
@@ -46,6 +46,8 @@ use primitives::traits::{Zero, One, RefInto, As, AuxLookup};
use substrate_runtime_support::{StorageValue, StorageMap};
use substrate_runtime_support::dispatch::Result;
use staking::address::Address;
#[cfg(any(feature = "std", test))]
use std::collections::HashMap;
pub mod voting;
@@ -590,7 +592,7 @@ impl<T: Trait> Default for GenesisConfig<T> {
#[cfg(any(feature = "std", test))]
impl<T: Trait> primitives::BuildStorage for GenesisConfig<T>
{
fn build_storage(self) -> ::std::result::Result<runtime_io::TestExternalities, String> {
fn build_storage(self) -> ::std::result::Result<HashMap<Vec<u8>, Vec<u8>>, String> {
use codec::Encode;
Ok(map![
@@ -614,12 +616,14 @@ impl<T: Trait> primitives::BuildStorage for GenesisConfig<T>
#[cfg(test)]
mod tests {
// These re-exports are here for a reason, edit with care
pub use super::*;
pub use runtime_io::with_externalities;
pub use substrate_primitives::H256;
use primitives::BuildStorage;
use primitives::traits::{HasPublicAux, Identity, BlakeTwo256};
use primitives::testing::{Digest, Header};
use substrate_primitives::KeccakHasher;
impl_outer_dispatch! {
#[derive(Debug, Clone, Eq, Serialize, Deserialize, PartialEq)]
@@ -667,7 +671,7 @@ mod tests {
}
impl Trait for Test {}
pub fn new_test_ext(with_council: bool) -> runtime_io::TestExternalities {
pub fn new_test_ext(with_council: bool) -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
t.extend(consensus::GenesisConfig::<Test>{
code: vec![],
@@ -718,7 +722,7 @@ mod tests {
voting_period: 1,
}.build_storage().unwrap());
t.extend(timestamp::GenesisConfig::<Test>::default().build_storage().unwrap());
t
t.into()
}
pub type System = system::Module<Test>;
@@ -784,7 +788,7 @@ mod tests {
});
}
fn new_test_ext_with_candidate_holes() -> runtime_io::TestExternalities {
fn new_test_ext_with_candidate_holes() -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = new_test_ext(false);
with_externalities(&mut t, || {
<Candidates<Test>>::put(vec![0, 0, 1]);
@@ -51,6 +51,9 @@ use primitives::traits::{Zero, Executable, RefInto, As, MaybeSerializeDebug};
use substrate_runtime_support::{StorageValue, StorageMap, Parameter, Dispatchable, IsSubType};
use substrate_runtime_support::dispatch::Result;
#[cfg(any(feature = "std", test))]
use std::collections::HashMap;
mod vote_threshold;
pub use vote_threshold::{Approved, VoteThreshold};
@@ -339,7 +342,7 @@ impl<T: Trait> Default for GenesisConfig<T> {
#[cfg(any(feature = "std", test))]
impl<T: Trait> primitives::BuildStorage for GenesisConfig<T>
{
fn build_storage(self) -> ::std::result::Result<runtime_io::TestExternalities, String> {
fn build_storage(self) -> ::std::result::Result<HashMap<Vec<u8>, Vec<u8>>, String> {
use codec::Encode;
Ok(map![
@@ -357,7 +360,7 @@ impl<T: Trait> primitives::BuildStorage for GenesisConfig<T>
mod tests {
use super::*;
use runtime_io::with_externalities;
use substrate_primitives::H256;
use substrate_primitives::{H256, KeccakHasher};
use primitives::BuildStorage;
use primitives::traits::{HasPublicAux, Identity, BlakeTwo256};
use primitives::testing::{Digest, Header};
@@ -409,7 +412,7 @@ mod tests {
type Proposal = Proposal;
}
fn new_test_ext() -> runtime_io::TestExternalities {
fn new_test_ext() -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
t.extend(consensus::GenesisConfig::<Test>{
code: vec![],
@@ -442,7 +445,7 @@ mod tests {
minimum_deposit: 1,
}.build_storage().unwrap());
t.extend(timestamp::GenesisConfig::<Test>::default().build_storage().unwrap());
t
t.into()
}
type System = system::Module<Test>;
@@ -218,7 +218,7 @@ mod tests {
use super::*;
use staking::Call;
use runtime_io::with_externalities;
use substrate_primitives::H256;
use substrate_primitives::{H256, KeccakHasher};
use primitives::BuildStorage;
use primitives::traits::{HasPublicAux, Identity, Header as HeaderT, BlakeTwo256, AuxLookup};
use primitives::testing::{Digest, Header, Block};
@@ -289,6 +289,7 @@ mod tests {
session_reward: 0,
}.build_storage().unwrap());
let xt = primitives::testing::TestXt((1, 0, Call::transfer(2.into(), 69)));
let mut t = runtime_io::TestExternalities::from(t);
with_externalities(&mut t, || {
Executive::initialise_block(&Header::new(1, H256::default(), H256::default(), [69u8; 32].into(), Digest::default()));
Executive::apply_extrinsic(xt).unwrap();
@@ -297,13 +298,13 @@ mod tests {
});
}
fn new_test_ext() -> runtime_io::TestExternalities {
fn new_test_ext() -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
t.extend(consensus::GenesisConfig::<Test>::default().build_storage().unwrap());
t.extend(session::GenesisConfig::<Test>::default().build_storage().unwrap());
t.extend(staking::GenesisConfig::<Test>::default().build_storage().unwrap());
t.extend(timestamp::GenesisConfig::<Test>::default().build_storage().unwrap());
t
t.into()
}
#[test]
@@ -313,8 +314,11 @@ mod tests {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
// Blake
// state_root: hex!("02532989c613369596025dfcfc821339fc9861987003924913a5a1382f87034a").into(),
// Keccak
state_root: hex!("8fad93b6b9e5251a2e4913598fd0d74a138c0e486eb1133ff8081b429b0c56f2").into(),
extrinsics_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
extrinsics_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(), // REVIEW: I expected this to be wrong with a different hasher?
digest: Digest { logs: vec![], },
},
extrinsics: vec![],
@@ -50,6 +50,9 @@ use primitives::traits::{Zero, One, RefInto, MaybeEmpty, Executable, Convert, As
use runtime_support::{StorageValue, StorageMap};
use runtime_support::dispatch::Result;
#[cfg(any(feature = "std", test))]
use std::collections::HashMap;
/// A session has changed.
pub trait OnSessionChange<T, A> {
/// Session has changed.
@@ -265,7 +268,8 @@ impl<T: Trait> Default for GenesisConfig<T> {
#[cfg(any(feature = "std", test))]
impl<T: Trait> primitives::BuildStorage for GenesisConfig<T>
{
fn build_storage(self) -> ::std::result::Result<runtime_io::TestExternalities, String> {
fn build_storage(self) -> ::std::result::Result<HashMap<Vec<u8>, Vec<u8>>, String> {
use codec::Encode;
use primitives::traits::As;
Ok(map![
@@ -282,7 +286,7 @@ impl<T: Trait> primitives::BuildStorage for GenesisConfig<T>
mod tests {
use super::*;
use runtime_io::with_externalities;
use substrate_primitives::H256;
use substrate_primitives::{H256, KeccakHasher};
use primitives::BuildStorage;
use primitives::traits::{HasPublicAux, Identity, BlakeTwo256};
use primitives::testing::{Digest, Header};
@@ -320,7 +324,7 @@ mod tests {
type Timestamp = timestamp::Module<Test>;
type Session = Module<Test>;
fn new_test_ext() -> runtime_io::TestExternalities {
fn new_test_ext() -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
t.extend(consensus::GenesisConfig::<Test>{
code: vec![],
@@ -334,7 +338,7 @@ mod tests {
validators: vec![1, 2, 3],
broken_percent_late: 30,
}.build_storage().unwrap());
t
t.into()
}
#[test]
@@ -18,10 +18,12 @@
#![cfg(feature = "std")]
use std::collections::HashMap;
use rstd::prelude::*;
use codec::Encode;
use runtime_support::{StorageValue, StorageMap};
use primitives::traits::{Zero, As};
use substrate_primitives::KeccakHasher;
use {runtime_io, primitives};
use super::{Trait, ENUM_SET_SIZE, EnumSet, NextEnumSet, Intentions, CurrentEra,
BondingDuration, CreationFee, TransferFee, ReclaimRebate,
@@ -118,10 +120,10 @@ impl<T: Trait> Default for GenesisConfig<T> {
}
impl<T: Trait> primitives::BuildStorage for GenesisConfig<T> {
fn build_storage(self) -> Result<runtime_io::TestExternalities, String> {
fn build_storage(self) -> ::std::result::Result<HashMap<Vec<u8>, Vec<u8>>, String> {
let total_stake: T::Balance = self.balances.iter().fold(Zero::zero(), |acc, &(_, n)| acc + n);
let mut r: runtime_io::TestExternalities = map![
let mut r: runtime_io::TestExternalities<KeccakHasher> = map![
Self::hash(<NextEnumSet<T>>::key()).to_vec() => T::AccountIndex::sa(self.balances.len() / ENUM_SET_SIZE).encode(),
Self::hash(<Intentions<T>>::key()).to_vec() => self.intentions.encode(),
Self::hash(<SessionsPerEra<T>>::key()).to_vec() => self.sessions_per_era.encode(),
@@ -147,6 +149,6 @@ impl<T: Trait> primitives::BuildStorage for GenesisConfig<T> {
for (who, value) in self.balances.into_iter() {
r.insert(Self::hash(&<FreeBalance<T>>::key_for(who)).to_vec(), value.encode());
}
Ok(r)
Ok(r.into())
}
}
+34 -10
View File
@@ -302,7 +302,8 @@ impl<T: Trait> Module<T> {
};
if transactor != &dest {
Self::set_free_balance(transactor, new_from_balance);
Self::set_free_balance(transactor, new_from_balance);
Self::decrease_total_stake_by(fee);
Self::set_free_balance_creating(&dest, new_to_balance);
}
@@ -424,6 +425,7 @@ impl<T: Trait> Module<T> {
/// In that case it will return `AccountKilled`.
pub fn set_reserved_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome {
if balance < Self::existential_deposit() {
<ReservedBalance<T>>::insert(who, balance);
Self::on_reserved_too_low(who);
UpdateBalanceOutcome::AccountKilled
} else {
@@ -443,6 +445,7 @@ impl<T: Trait> Module<T> {
// Commented out for no - but consider it instructive.
// assert!(!Self::voting_balance(who).is_zero());
if balance < Self::existential_deposit() {
<FreeBalance<T>>::insert(who, balance);
Self::on_free_too_low(who);
UpdateBalanceOutcome::AccountKilled
} else {
@@ -472,7 +475,7 @@ impl<T: Trait> Module<T> {
// value of which makes even the `free_balance` unspendable.
// TODO: enforce this for the other balance-altering functions.
if balance < ed {
Self::on_free_too_low(who);
Self::set_free_balance(who, balance);
UpdateBalanceOutcome::AccountKilled
} else {
if !<FreeBalance<T>>::exists(who) {
@@ -481,10 +484,12 @@ impl<T: Trait> Module<T> {
NewAccountOutcome::GoodHint => balance + <Module<T>>::reclaim_rebate(),
_ => balance,
};
<FreeBalance<T>>::insert(who, credit);
} else {
<FreeBalance<T>>::insert(who, balance);
Self::set_free_balance(who, credit);
Self::increase_total_stake_by(credit - balance);
} else {
Self::set_free_balance(who, balance);
}
UpdateBalanceOutcome::Updated
}
}
@@ -493,11 +498,12 @@ impl<T: Trait> Module<T> {
/// free balance. This function cannot fail.
///
/// As much funds up to `value` will be deducted as possible. If this is less than `value`,
/// then `Some(remaining)` will be retutned. Full completion is given by `None`.
/// then `Some(remaining)` will be returned. Full completion is given by `None`.
pub fn slash(who: &T::AccountId, value: T::Balance) -> Option<T::Balance> {
let free_balance = Self::free_balance(who);
let free_slash = cmp::min(free_balance, value);
Self::set_free_balance(who, free_balance - free_slash);
Self::decrease_total_stake_by(free_slash);
if free_slash < value {
Self::slash_reserved(who, value - free_slash)
} else {
@@ -513,6 +519,7 @@ impl<T: Trait> Module<T> {
return Err("beneficiary account must pre-exist");
}
Self::set_free_balance(who, Self::free_balance(who) + value);
Self::increase_total_stake_by(value);
Ok(())
}
@@ -536,7 +543,7 @@ impl<T: Trait> Module<T> {
/// Moves up to `value` from reserved balance to balance. This function cannot fail.
///
/// As much funds up to `value` will be deducted as possible. If this is less than `value`,
/// then `Some(remaining)` will be retutned. Full completion is given by `None`.
/// then `Some(remaining)` will be returned. Full completion is given by `None`.
/// NOTE: This is different to `reserve`.
pub fn unreserve(who: &T::AccountId, value: T::Balance) -> Option<T::Balance> {
let b = Self::reserved_balance(who);
@@ -553,11 +560,12 @@ impl<T: Trait> Module<T> {
/// Deducts up to `value` from reserved balance of `who`. This function cannot fail.
///
/// As much funds up to `value` will be deducted as possible. If this is less than `value`,
/// then `Some(remaining)` will be retutned. Full completion is given by `None`.
/// then `Some(remaining)` will be returned. Full completion is given by `None`.
pub fn slash_reserved(who: &T::AccountId, value: T::Balance) -> Option<T::Balance> {
let b = Self::reserved_balance(who);
let slash = cmp::min(b, value);
Self::set_reserved_balance(who, b - slash);
Self::decrease_total_stake_by(slash);
if value == slash {
None
} else {
@@ -570,7 +578,7 @@ impl<T: Trait> Module<T> {
/// returned.
///
/// As much funds up to `value` will be moved as possible. If this is less than `value`, then
/// `Ok(Some(remaining))` will be retutned. Full completion is given by `Ok(None)`.
/// `Ok(Some(remaining))` will be returned. Full completion is given by `Ok(None)`.
pub fn transfer_reserved(
slashed: &T::AccountId,
beneficiary: &T::AccountId,
@@ -785,6 +793,7 @@ impl<T: Trait> Module<T> {
/// Kill an account's free portion.
fn on_free_too_low(who: &T::AccountId) {
Self::decrease_total_stake_by(Self::free_balance(who));
<FreeBalance<T>>::remove(who);
<Bondage<T>>::remove(who);
T::OnAccountKill::on_account_kill(who);
@@ -796,11 +805,25 @@ impl<T: Trait> Module<T> {
/// Kill an account's reserved portion.
fn on_reserved_too_low(who: &T::AccountId) {
Self::decrease_total_stake_by(Self::reserved_balance(who));
<ReservedBalance<T>>::remove(who);
if Self::free_balance(who).is_zero() {
<system::AccountNonce<T>>::remove(who);
}
}
/// Increase TotalStake by Value.
pub fn increase_total_stake_by(value: T::Balance) {
if <TotalStake<T>>::exists() {
<TotalStake<T>>::put(<Module<T>>::total_stake() + value);
}
}
/// Decrease TotalStake by Value.
pub fn decrease_total_stake_by(value: T::Balance) {
if <TotalStake<T>>::exists() {
<TotalStake<T>>::put(<Module<T>>::total_stake() - value);
}
}
}
impl<T: Trait> Executable for Module<T> {
@@ -832,7 +855,8 @@ impl<T: Trait> MakePayment<T::AccountId> for Module<T> {
if b < transaction_fee + Self::existential_deposit() {
return Err("not enough funds for transaction fee");
}
<FreeBalance<T>>::insert(transactor, b - transaction_fee);
Self::set_free_balance(transactor, b - transaction_fee);
Self::decrease_total_stake_by(transaction_fee);
Ok(())
}
}
@@ -21,7 +21,7 @@
use primitives::BuildStorage;
use primitives::traits::{HasPublicAux, Identity};
use primitives::testing::{Digest, Header};
use substrate_primitives::H256;
use substrate_primitives::{H256, KeccakHasher};
use runtime_io;
use {GenesisConfig, Module, Trait, consensus, session, system, timestamp};
@@ -59,7 +59,7 @@ impl Trait for Test {
type OnAccountKill = ();
}
pub fn new_test_ext(ext_deposit: u64, session_length: u64, sessions_per_era: u64, current_era: u64, monied: bool, reward: u64) -> runtime_io::TestExternalities {
pub fn new_test_ext(ext_deposit: u64, session_length: u64, sessions_per_era: u64, current_era: u64, monied: bool, reward: u64) -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
let balance_factor = if ext_deposit > 0 {
256
@@ -102,7 +102,7 @@ pub fn new_test_ext(ext_deposit: u64, session_length: u64, sessions_per_era: u64
t.extend(timestamp::GenesisConfig::<Test>{
period: 5
}.build_storage().unwrap());
t
t.into()
}
pub type System = system::Module<Test>;
@@ -28,6 +28,7 @@ fn reward_should_work() {
assert_eq!(Staking::voting_balance(&10), 1);
assert_ok!(Staking::reward(&10, 10));
assert_eq!(Staking::voting_balance(&10), 11);
assert_eq!(<TotalStake<Test>>::get(), 112);
});
}
@@ -408,7 +409,7 @@ fn staking_eras_work() {
#[test]
fn staking_balance_works() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 42);
Staking::set_free_balance(&1, 42);
assert_eq!(Staking::free_balance(&1), 42);
assert_eq!(Staking::reserved_balance(&1), 0);
assert_eq!(Staking::voting_balance(&1), 42);
@@ -421,7 +422,8 @@ fn staking_balance_works() {
#[test]
fn staking_balance_transfer_works() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
Staking::increase_total_stake_by(111);
assert_ok!(Staking::transfer(&1, 2.into(), 69));
assert_eq!(Staking::voting_balance(&1), 42);
assert_eq!(Staking::voting_balance(&2), 69);
@@ -431,7 +433,7 @@ fn staking_balance_transfer_works() {
#[test]
fn staking_balance_transfer_when_bonded_should_not_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
assert_ok!(Staking::stake(&1));
assert_noop!(Staking::transfer(&1, 2.into(), 69), "bondage too high to send value");
});
@@ -440,7 +442,7 @@ fn staking_balance_transfer_when_bonded_should_not_work() {
#[test]
fn reserving_balance_should_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
assert_eq!(Staking::voting_balance(&1), 111);
assert_eq!(Staking::free_balance(&1), 111);
@@ -457,7 +459,7 @@ fn reserving_balance_should_work() {
#[test]
fn staking_balance_transfer_when_reserved_should_not_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
assert_ok!(Staking::reserve(&1, 69));
assert_noop!(Staking::transfer(&1, 2.into(), 69), "balance too low to send value");
});
@@ -466,7 +468,7 @@ fn staking_balance_transfer_when_reserved_should_not_work() {
#[test]
fn deducting_balance_should_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
assert_ok!(Staking::reserve(&1, 69));
assert_eq!(Staking::free_balance(&1), 42);
});
@@ -475,7 +477,7 @@ fn deducting_balance_should_work() {
#[test]
fn deducting_balance_when_bonded_should_not_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
<Bondage<Test>>::insert(1, 2);
System::set_block_number(1);
assert_eq!(Staking::unlock_block(&1), LockStatus::LockedUntil(2));
@@ -486,8 +488,8 @@ fn deducting_balance_when_bonded_should_not_work() {
#[test]
fn refunding_balance_should_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 42);
<ReservedBalance<Test>>::insert(1, 69);
Staking::set_free_balance(&1, 42);
Staking::set_reserved_balance(&1, 69);
Staking::unreserve(&1, 69);
assert_eq!(Staking::free_balance(&1), 111);
assert_eq!(Staking::reserved_balance(&1), 0);
@@ -497,29 +499,33 @@ fn refunding_balance_should_work() {
#[test]
fn slashing_balance_should_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
Staking::increase_total_stake_by(111);
assert_ok!(Staking::reserve(&1, 69));
assert!(Staking::slash(&1, 69).is_none());
assert_eq!(Staking::free_balance(&1), 0);
assert_eq!(Staking::reserved_balance(&1), 42);
assert_eq!(<TotalStake<Test>>::get(), 44);
});
}
#[test]
fn slashing_incomplete_balance_should_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 42);
Staking::set_free_balance(&1, 42);
Staking::increase_total_stake_by(42);
assert_ok!(Staking::reserve(&1, 21));
assert!(Staking::slash(&1, 69).is_some());
assert_eq!(Staking::free_balance(&1), 0);
assert_eq!(Staking::reserved_balance(&1), 0);
assert_eq!(<TotalStake<Test>>::get(), 2);
});
}
#[test]
fn unreserving_balance_should_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
assert_ok!(Staking::reserve(&1, 111));
Staking::unreserve(&1, 42);
assert_eq!(Staking::reserved_balance(&1), 69);
@@ -530,30 +536,34 @@ fn unreserving_balance_should_work() {
#[test]
fn slashing_reserved_balance_should_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
Staking::increase_total_stake_by(111);
assert_ok!(Staking::reserve(&1, 111));
assert!(Staking::slash_reserved(&1, 42).is_none());
assert_eq!(Staking::reserved_balance(&1), 69);
assert_eq!(Staking::free_balance(&1), 0);
assert_eq!(<TotalStake<Test>>::get(), 71);
});
}
#[test]
fn slashing_incomplete_reserved_balance_should_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
Staking::increase_total_stake_by(111);
assert_ok!(Staking::reserve(&1, 42));
assert!(Staking::slash_reserved(&1, 69).is_some());
assert_eq!(Staking::free_balance(&1), 69);
assert_eq!(Staking::reserved_balance(&1), 0);
assert_eq!(<TotalStake<Test>>::get(), 71);
});
}
#[test]
fn transferring_reserved_balance_should_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 110);
<FreeBalance<Test>>::insert(2, 1);
Staking::set_free_balance(&1, 110);
Staking::set_free_balance(&2, 1);
assert_ok!(Staking::reserve(&1, 110));
assert_ok!(Staking::transfer_reserved(&1, &2, 41), None);
assert_eq!(Staking::reserved_balance(&1), 69);
@@ -566,7 +576,7 @@ fn transferring_reserved_balance_should_work() {
#[test]
fn transferring_reserved_balance_to_nonexistent_should_fail() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 111);
Staking::set_free_balance(&1, 111);
assert_ok!(Staking::reserve(&1, 111));
assert_noop!(Staking::transfer_reserved(&1, &2, 42), "beneficiary account must pre-exist");
});
@@ -575,8 +585,8 @@ fn transferring_reserved_balance_to_nonexistent_should_fail() {
#[test]
fn transferring_incomplete_reserved_balance_should_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
<FreeBalance<Test>>::insert(1, 110);
<FreeBalance<Test>>::insert(2, 1);
Staking::set_free_balance(&1, 110);
Staking::set_free_balance(&2, 1);
assert_ok!(Staking::reserve(&1, 41));
assert!(Staking::transfer_reserved(&1, &2, 69).unwrap().is_some());
assert_eq!(Staking::reserved_balance(&1), 0);
@@ -599,5 +609,32 @@ fn transferring_too_high_value_should_not_panic() {
assert_eq!(Staking::free_balance(&1), u64::max_value());
assert_eq!(Staking::free_balance(&2), 1);
});
}
#[test]
fn account_removal_on_free_too_low() {
with_externalities(&mut new_test_ext(100, 1, 3, 1, false, 0), || {
// Setup two accounts with free balance above the exsistential threshold.
{
Staking::set_free_balance(&1, 110);
Staking::increase_total_stake_by(110);
Staking::set_free_balance(&2, 110);
Staking::increase_total_stake_by(110);
assert_eq!(<TotalStake<Test>>::get(), 732);
}
// Transfer funds from account 1 of such amount that after this transfer
// the balance of account 1 will be below the exsistential threshold.
// This should lead to the removal of all balance of this account.
assert_ok!(Staking::transfer(&1, 2.into(), 20));
// Verify free balance removal of account 1.
assert_eq!(Staking::free_balance(&1), 0);
// Verify that TotalStake tracks balance removal when free balance is too low.
assert_eq!(<TotalStake<Test>>::get(), 642);
});
}
@@ -49,7 +49,7 @@ use rstd::marker::PhantomData;
use codec::Encode;
#[cfg(any(feature = "std", test))]
use runtime_io::{twox_128, TestExternalities};
use runtime_io::{twox_128, TestExternalities, KeccakHasher};
/// Compute the extrinsics root of a list of extrinsics.
pub fn extrinsics_root<H: Hash, E: codec::Encode>(extrinsics: &[E]) -> H::Output {
@@ -142,7 +142,7 @@ impl<T: Trait> Module<T> {
/// Get the basic externalities for this module, useful for tests.
#[cfg(any(feature = "std", test))]
pub fn externalities() -> TestExternalities {
pub fn externalities() -> TestExternalities<KeccakHasher> {
map![
twox_128(&<BlockHash<T>>::key_for(T::BlockNumber::zero())).to_vec() => [69u8; 32].encode(), // TODO: replace with Hash::default().encode
twox_128(<Number<T>>::key()).to_vec() => T::BlockNumber::one().encode(),
@@ -207,7 +207,7 @@ impl<T: Trait> Default for GenesisConfig<T> {
#[cfg(any(feature = "std", test))]
impl<T: Trait> primitives::BuildStorage for GenesisConfig<T>
{
fn build_storage(self) -> Result<runtime_io::TestExternalities, String> {
fn build_storage(self) -> Result<primitives::StorageMap, String> {
use codec::Encode;
Ok(map![
@@ -26,6 +26,7 @@ std = [
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
"substrate-runtime-consensus/std",
"serde/std",
"serde_derive",
"substrate-codec/std",
@@ -173,7 +173,7 @@ mod tests {
fn timestamp_works() {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
t.extend(GenesisConfig::<Test> { period: 0 }.build_storage().unwrap());
let mut t = runtime_io::TestExternalities::from(t);
with_externalities(&mut t, || {
Timestamp::set_timestamp(42);
assert_ok!(Timestamp::aux_dispatch(Call::set(69), &0));
@@ -186,7 +186,7 @@ mod tests {
fn double_timestamp_should_fail() {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
t.extend(GenesisConfig::<Test> { period: 5 }.build_storage().unwrap());
let mut t = runtime_io::TestExternalities::from(t);
with_externalities(&mut t, || {
Timestamp::set_timestamp(42);
assert_ok!(Timestamp::aux_dispatch(Call::set(69), &0));
@@ -199,7 +199,7 @@ mod tests {
fn block_period_is_enforced() {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
t.extend(GenesisConfig::<Test> { period: 5 }.build_storage().unwrap());
let mut t = runtime_io::TestExternalities::from(t);
with_externalities(&mut t, || {
Timestamp::set_timestamp(42);
let _ = Timestamp::aux_dispatch(Call::set(46), &0);
@@ -28,6 +28,7 @@ use substrate_executor::{NativeExecutor, NativeExecutionDispatch};
use extrinsic_pool::{txpool::Options as ExtrinsicPoolOptions, api::ExtrinsicPool as ExtrinsicPoolApi};
use runtime_primitives::{traits::Block as BlockT, traits::Header as HeaderT, generic::BlockId, BuildStorage};
use config::Configuration;
use primitives::{KeccakHasher, RlpCodec, H256};
// Type aliases.
// These exist mainly to avoid typing `<F as Factory>::Foo` all over the code.
@@ -152,9 +153,9 @@ pub trait Components {
/// Associated service factory.
type Factory: ServiceFactory;
/// Client backend.
type Backend: 'static + client::backend::Backend<FactoryBlock<Self::Factory>>;
type Backend: 'static + client::backend::Backend<FactoryBlock<Self::Factory>, KeccakHasher, RlpCodec>;
/// Client executor.
type Executor: 'static + client::CallExecutor<FactoryBlock<Self::Factory>> + Send + Sync;
type Executor: 'static + client::CallExecutor<FactoryBlock<Self::Factory>, KeccakHasher, RlpCodec> + Send + Sync;
/// Extrinsic pool type.
type ExtrinsicPool: ExtrinsicPool<FactoryBlock<Self::Factory>>;
@@ -215,7 +216,7 @@ pub struct LightComponents<Factory: ServiceFactory> {
impl<Factory: ServiceFactory> Components for LightComponents<Factory>
where
<<Factory as ServiceFactory>::Block as BlockT>::Hash: Into<[u8; 32]>,
<<Factory as ServiceFactory>::Block as BlockT>::Hash: Into<H256>,
{
type Factory = Factory;
type Executor = LightExecutor<Factory>;
@@ -239,7 +240,7 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory>
};
let db_storage = client_db::light::LightStorage::new(db_settings)?;
let light_blockchain = client::light::new_light_blockchain(db_storage);
let fetch_checker = Arc::new(client::light::new_fetch_checker(executor));
let fetch_checker = Arc::new(client::light::new_fetch_checker::<_, KeccakHasher, RlpCodec>(executor));
let fetcher = Arc::new(network::OnDemand::new(fetch_checker));
let client_backend = client::light::new_light_backend(light_blockchain, fetcher.clone());
let client = client::light::new_light(client_backend, fetcher.clone(), &config.chain_spec)?;
+2 -1
View File
@@ -210,7 +210,8 @@ impl<Components> Service<Components>
let chain = rpc::apis::chain::Chain::new(client.clone(), task_executor.clone());
let state = rpc::apis::state::State::new(client.clone(), task_executor.clone());
let author = rpc::apis::author::Author::new(client.clone(), extrinsic_pool.api(), task_executor.clone());
rpc::rpc_handler::<ComponentBlock<Components>, _, _, _, _>(
rpc::rpc_handler::<ComponentBlock<Components>, _, _, _, _, _>(
state,
chain,
author,
+6 -5
View File
@@ -6,14 +6,15 @@ description = "Substrate State Machine"
[dependencies]
byteorder = "1.1"
ethereum-types = "0.3"
hex-literal = "0.1.0"
log = "0.3"
parking_lot = "0.4"
triehash = "0.1"
heapsize = "0.4"
substrate-primitives = { path = "../primitives", version = "0.1.0" }
hashdb = { git = "https://github.com/paritytech/parity.git" }
memorydb = { git = "https://github.com/paritytech/parity.git" }
patricia-trie = { git = "https://github.com/paritytech/parity.git" }
hashdb = { git = "https://github.com/paritytech/parity-common" }
memorydb = { git = "https://github.com/paritytech/parity-common" }
patricia-trie = { git = "https://github.com/paritytech/parity-common" }
triehash = { git = "https://github.com/paritytech/parity-common" }
rlp = { git = "https://github.com/paritytech/parity-common" }
@@ -17,15 +17,22 @@
//! State machine backends. These manage the code and storage of contracts.
use std::{error, fmt};
use std::cmp::Ord;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc;
use hashdb::Hasher;
use rlp::Encodable;
use trie_backend::{TryIntoTrieBackend, TrieBackend};
use patricia_trie::{TrieDBMut, TrieMut, NodeCodec};
use heapsize::HeapSizeOf;
/// A state backend is used to read state data and can have changes committed
/// to it.
///
/// The clone operation (if implemented) should be cheap.
pub trait Backend: TryIntoTrieBackend {
pub trait Backend<H: Hasher, C: NodeCodec<H>>: TryIntoTrieBackend<H, C> {
/// An error type when fetching data is not possible.
type Error: super::Error;
@@ -46,8 +53,10 @@ pub trait Backend: TryIntoTrieBackend {
/// Calculate the storage root, with given delta over what is already stored in
/// the backend, and produce a "transaction" that can be used to commit.
fn storage_root<I>(&self, delta: I) -> ([u8; 32], Self::Transaction)
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>;
fn storage_root<I>(&self, delta: I) -> (H::Out, Self::Transaction)
where
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
H::Out: Ord + Encodable;
/// Get all key/value pairs into a Vec.
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)>;
@@ -70,22 +79,40 @@ impl error::Error for Void {
/// In-memory backend. Fully recomputes tries on each commit but useful for
/// tests.
#[derive(Clone, PartialEq, Eq)]
pub struct InMemory {
#[derive(Eq)]
pub struct InMemory<H, C> {
inner: Arc<HashMap<Vec<u8>, Vec<u8>>>,
_hasher: PhantomData<H>,
_codec: PhantomData<C>,
}
impl Default for InMemory {
impl<H, C> Default for InMemory<H, C> {
fn default() -> Self {
InMemory {
inner: Arc::new(Default::default()),
_hasher: PhantomData,
_codec: PhantomData,
}
}
}
impl InMemory {
impl<H, C> Clone for InMemory<H, C> {
fn clone(&self) -> Self {
InMemory {
inner: self.inner.clone(), _hasher: PhantomData, _codec: PhantomData,
}
}
}
impl<H, C> PartialEq for InMemory<H, C> {
fn eq(&self, other: &Self) -> bool {
self.inner.eq(&other.inner)
}
}
impl<H: Hasher, C: NodeCodec<H>> InMemory<H, C> where H::Out: HeapSizeOf {
/// Copy the state, with applied updates
pub fn update(&self, changes: <Self as Backend>::Transaction) -> Self {
pub fn update(&self, changes: <Self as Backend<H, C>>::Transaction) -> Self {
let mut inner: HashMap<_, _> = (&*self.inner).clone();
for (key, val) in changes {
match val {
@@ -98,17 +125,17 @@ impl InMemory {
}
}
impl From<HashMap<Vec<u8>, Vec<u8>>> for InMemory {
impl<H, C> From<HashMap<Vec<u8>, Vec<u8>>> for InMemory<H, C> {
fn from(inner: HashMap<Vec<u8>, Vec<u8>>) -> Self {
InMemory {
inner: Arc::new(inner),
inner: Arc::new(inner), _hasher: PhantomData, _codec: PhantomData
}
}
}
impl super::Error for Void {}
impl Backend for InMemory {
impl<H: Hasher, C: NodeCodec<H>> Backend<H, C> for InMemory<H, C> where H::Out: HeapSizeOf {
type Error = Void;
type Transaction = Vec<(Vec<u8>, Option<Vec<u8>>)>;
@@ -124,17 +151,19 @@ impl Backend for InMemory {
self.inner.keys().filter(|key| key.starts_with(prefix)).map(|k| &**k).for_each(f);
}
fn storage_root<I>(&self, delta: I) -> ([u8; 32], Self::Transaction)
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
fn storage_root<I>(&self, delta: I) -> (H::Out, Self::Transaction)
where
I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>,
<H as Hasher>::Out: Ord + Encodable,
{
let existing_pairs = self.inner.iter().map(|(k, v)| (k.clone(), Some(v.clone())));
let transaction: Vec<_> = delta.into_iter().collect();
let root = ::triehash::trie_root(existing_pairs.chain(transaction.iter().cloned())
let root = ::triehash::trie_root::<H, _, _, _>(existing_pairs.chain(transaction.iter().cloned())
.collect::<HashMap<_, _>>()
.into_iter()
.filter_map(|(k, maybe_val)| maybe_val.map(|val| (k, val)))
).0;
);
(root, transaction)
}
@@ -144,16 +173,13 @@ impl Backend for InMemory {
}
}
impl TryIntoTrieBackend for InMemory {
fn try_into_trie_backend(self) -> Option<TrieBackend> {
use ethereum_types::H256 as TrieH256;
impl<H: Hasher, C: NodeCodec<H>> TryIntoTrieBackend<H, C> for InMemory<H, C> where H::Out: HeapSizeOf {
fn try_into_trie_backend(self) -> Option<TrieBackend<H, C>> {
use memorydb::MemoryDB;
use patricia_trie::{TrieDBMut, TrieMut};
let mut root = TrieH256::default();
let mut mdb = MemoryDB::default();
let mut root = <H as Hasher>::Out::default();
let mut mdb = MemoryDB::new();
{
let mut trie = TrieDBMut::new(&mut mdb, &mut root);
let mut trie = TrieDBMut::<H, C>::new(&mut mdb, &mut root);
for (key, value) in self.inner.iter() {
if let Err(e) = trie.insert(&key, &value) {
warn!(target: "trie", "Failed to write to trie: {}", e);
+31 -8
View File
@@ -16,9 +16,12 @@
//! Conrete externalities implementation.
use std::{error, fmt};
use std::{error, fmt, cmp::Ord};
use backend::Backend;
use {Externalities, OverlayedChanges};
use hashdb::Hasher;
use rlp::Encodable;
use patricia_trie::NodeCodec;
/// Errors that can occur when interacting with the externalities.
#[derive(Debug, Copy, Clone)]
@@ -50,16 +53,27 @@ impl<B: error::Error, E: error::Error> error::Error for Error<B, E> {
}
/// Wraps a read-only backend, call executor, and current overlayed changes.
pub struct Ext<'a, B: 'a + Backend> {
pub struct Ext<'a, H, C, B>
where
H: Hasher,
C: NodeCodec<H>,
B: 'a + Backend<H, C>,
{
// The overlayed changes to write to.
overlay: &'a mut OverlayedChanges,
// The storage backend to read from.
backend: &'a B,
// The transaction necessary to commit to the backend.
transaction: Option<(B::Transaction, [u8; 32])>,
transaction: Option<(B::Transaction, H::Out)>,
}
impl<'a, B: 'a + Backend> Ext<'a, B> {
impl<'a, H, C, B> Ext<'a, H, C, B>
where
H: Hasher,
C: NodeCodec<H>,
B: 'a + Backend<H, C>,
H::Out: Ord + Encodable
{
/// Create a new `Ext` from overlayed changes and read-only backend
pub fn new(overlay: &'a mut OverlayedChanges, backend: &'a B) -> Self {
Ext {
@@ -84,7 +98,12 @@ impl<'a, B: 'a + Backend> Ext<'a, B> {
}
#[cfg(test)]
impl<'a, B: 'a + Backend> Ext<'a, B> {
impl<'a, H, C, B> Ext<'a, H, C, B>
where
H: Hasher,
C: NodeCodec<H>,
B: 'a + Backend<H,C>,
{
pub fn storage_pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
use std::collections::HashMap;
@@ -99,8 +118,12 @@ impl<'a, B: 'a + Backend> Ext<'a, B> {
}
}
impl<'a, B: 'a> Externalities for Ext<'a, B>
where B: Backend
impl<'a, B: 'a, H, C> Externalities<H> for Ext<'a, H, C, B>
where
H: Hasher,
C: NodeCodec<H>,
B: 'a + Backend<H, C>,
H::Out: Ord + Encodable
{
fn storage(&self, key: &[u8]) -> Option<Vec<u8>> {
self.overlay.storage(key).map(|x| x.map(|x| x.to_vec())).unwrap_or_else(||
@@ -131,7 +154,7 @@ impl<'a, B: 'a> Externalities for Ext<'a, B>
42
}
fn storage_root(&mut self) -> [u8; 32] {
fn storage_root(&mut self) -> H::Out {
if let Some((_, ref root)) = self.transaction {
return root.clone();
}
+80 -37
View File
@@ -24,17 +24,23 @@ extern crate hex_literal;
#[macro_use]
extern crate log;
extern crate ethereum_types;
extern crate hashdb;
extern crate memorydb;
extern crate triehash;
extern crate patricia_trie;
extern crate byteorder;
extern crate parking_lot;
extern crate rlp;
extern crate heapsize;
#[cfg(test)]
extern crate substrate_primitives as primitives;
use std::collections::HashMap;
use std::fmt;
use hashdb::Hasher;
use patricia_trie::NodeCodec;
use rlp::Encodable;
use heapsize::HeapSizeOf;
pub mod backend;
mod ext;
@@ -45,7 +51,7 @@ mod trie_backend;
pub use testing::TestExternalities;
pub use ext::Ext;
pub use backend::Backend;
pub use trie_backend::{TryIntoTrieBackend, TrieBackend, TrieH256, Storage, DBValue};
pub use trie_backend::{TryIntoTrieBackend, TrieBackend, Storage, DBValue};
/// The overlayed changes to state to be queried on top of the backend.
///
@@ -158,7 +164,7 @@ impl fmt::Display for ExecutionError {
}
/// Externalities: pinned to specific active address.
pub trait Externalities {
pub trait Externalities<H: Hasher> {
/// Read storage of current contract being called.
fn storage(&self, key: &[u8]) -> Option<Vec<u8>>;
@@ -187,17 +193,17 @@ pub trait Externalities {
fn chain_id(&self) -> u64;
/// Get the trie root of the current storage map.
fn storage_root(&mut self) -> [u8; 32];
fn storage_root(&mut self) -> H::Out where H::Out: Ord + Encodable;
}
/// Code execution engine.
pub trait CodeExecutor: Sized + Send + Sync {
pub trait CodeExecutor<H: Hasher>: Sized + Send + Sync {
/// Externalities error type.
type Error: Error;
/// Call a given method in the runtime. Returns a tuple of the result (either the output data
/// or an execution error) together with a `bool`, which is true if native execution was used.
fn call<E: Externalities>(
fn call<E: Externalities<H>>(
&self,
ext: &mut E,
code: &[u8],
@@ -256,14 +262,21 @@ pub fn always_wasm<E>() -> ExecutionManager<fn(Result<Vec<u8>, E>, Result<Vec<u8
///
/// Note: changes to code will be in place if this call is made again. For running partial
/// blocks (e.g. a transaction at a time), ensure a different method is used.
pub fn execute<B: backend::Backend, Exec: CodeExecutor>(
pub fn execute<H, C, B, Exec>(
backend: &B,
overlay: &mut OverlayedChanges,
exec: &Exec,
method: &str,
call_data: &[u8],
strategy: ExecutionStrategy,
) -> Result<(Vec<u8>, B::Transaction), Box<Error>> {
) -> Result<(Vec<u8>, B::Transaction), Box<Error>>
where
H: Hasher,
C: NodeCodec<H>,
Exec: CodeExecutor<H>,
B: Backend<H, C>,
H::Out: Ord + Encodable
{
execute_using_consensus_failure_handler(
backend,
overlay,
@@ -289,18 +302,22 @@ pub fn execute<B: backend::Backend, Exec: CodeExecutor>(
///
/// Note: changes to code will be in place if this call is made again. For running partial
/// blocks (e.g. a transaction at a time), ensure a different method is used.
pub fn execute_using_consensus_failure_handler<
B: backend::Backend,
Exec: CodeExecutor,
Handler: FnOnce(Result<Vec<u8>, Exec::Error>, Result<Vec<u8>, Exec::Error>) -> Result<Vec<u8>, Exec::Error>
>(
pub fn execute_using_consensus_failure_handler<H, C, B, Exec, Handler>(
backend: &B,
overlay: &mut OverlayedChanges,
exec: &Exec,
method: &str,
call_data: &[u8],
manager: ExecutionManager<Handler>,
) -> Result<(Vec<u8>, B::Transaction), Box<Error>> {
) -> Result<(Vec<u8>, B::Transaction), Box<Error>>
where
H: Hasher,
C: NodeCodec<H>,
Exec: CodeExecutor<H>,
B: Backend<H, C>,
H::Out: Ord + Encodable,
Handler: FnOnce(Result<Vec<u8>, Exec::Error>, Result<Vec<u8>, Exec::Error>) -> Result<Vec<u8>, Exec::Error>
{
let strategy: ExecutionStrategy = (&manager).into();
// make a copy.
@@ -378,55 +395,77 @@ pub fn execute_using_consensus_failure_handler<
///
/// Note: changes to code will be in place if this call is made again. For running partial
/// blocks (e.g. a transaction at a time), ensure a different method is used.
pub fn prove_execution<B: TryIntoTrieBackend, Exec: CodeExecutor>(
pub fn prove_execution<H, C, B, Exec>(
backend: B,
overlay: &mut OverlayedChanges,
exec: &Exec,
method: &str,
call_data: &[u8],
) -> Result<(Vec<u8>, Vec<Vec<u8>>, <TrieBackend as Backend>::Transaction), Box<Error>> {
) -> Result<(Vec<u8>, Vec<Vec<u8>>, <TrieBackend<H, C> as Backend<H, C>>::Transaction), Box<Error>>
where
H: Hasher,
Exec: CodeExecutor<H>,
C: NodeCodec<H>,
B: TryIntoTrieBackend<H, C>,
H::Out: Ord + Encodable + HeapSizeOf,
{
let trie_backend = backend.try_into_trie_backend()
.ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box<Error>)?;
let proving_backend = proving_backend::ProvingBackend::new(trie_backend);
let (result, transaction) = execute(&proving_backend, overlay, exec, method, call_data, ExecutionStrategy::NativeWhenPossible)?;
let (result, transaction) = execute::<H, C, _, _>(&proving_backend, overlay, exec, method, call_data, ExecutionStrategy::NativeWhenPossible)?;
let proof = proving_backend.extract_proof();
Ok((result, proof, transaction))
}
/// Check execution proof, generated by `prove_execution` call.
pub fn execution_proof_check<Exec: CodeExecutor>(
root: [u8; 32],
pub fn execution_proof_check<H, C, Exec>(
root: H::Out,
proof: Vec<Vec<u8>>,
overlay: &mut OverlayedChanges,
exec: &Exec,
method: &str,
call_data: &[u8],
) -> Result<(Vec<u8>, memorydb::MemoryDB), Box<Error>> {
let backend = proving_backend::create_proof_check_backend(root.into(), proof)?;
execute(&backend, overlay, exec, method, call_data, ExecutionStrategy::NativeWhenPossible)
) -> Result<(Vec<u8>, memorydb::MemoryDB<H>), Box<Error>>
where
H: Hasher,
C: NodeCodec<H>,
Exec: CodeExecutor<H>,
H::Out: Ord + Encodable + HeapSizeOf,
{
let backend = proving_backend::create_proof_check_backend::<H, C>(root.into(), proof)?;
execute::<H, C, _, _>(&backend, overlay, exec, method, call_data, ExecutionStrategy::NativeWhenPossible)
}
/// Generate storage read proof.
pub fn prove_read<B: TryIntoTrieBackend>(
pub fn prove_read<B, H, C>(
backend: B,
key: &[u8],
key: &[u8]
) -> Result<(Option<Vec<u8>>, Vec<Vec<u8>>), Box<Error>>
where
B: TryIntoTrieBackend<H, C>,
H: Hasher,
C: NodeCodec<H>,
H::Out: Ord + Encodable + HeapSizeOf
{
let trie_backend = backend.try_into_trie_backend()
.ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box<Error>)?;
let proving_backend = proving_backend::ProvingBackend::new(trie_backend);
let proving_backend = proving_backend::ProvingBackend::<H, C>::new(trie_backend);
let result = proving_backend.storage(key).map_err(|e| Box::new(e) as Box<Error>)?;
Ok((result, proving_backend.extract_proof()))
}
/// Check storage read proof, generated by `prove_read` call.
pub fn read_proof_check(
root: [u8; 32],
pub fn read_proof_check<H, C>(
root: H::Out,
proof: Vec<Vec<u8>>,
key: &[u8],
) -> Result<Option<Vec<u8>>, Box<Error>>
where
H: Hasher,
C: NodeCodec<H>,
H::Out: Ord + Encodable + HeapSizeOf
{
let backend = proving_backend::create_proof_check_backend(root.into(), proof)?;
let backend = proving_backend::create_proof_check_backend::<H, C>(root, proof)?;
backend.storage(key).map_err(|e| Box::new(e) as Box<Error>)
}
@@ -435,6 +474,7 @@ mod tests {
use super::*;
use super::backend::InMemory;
use super::ext::Ext;
use primitives::{KeccakHasher, RlpCodec, H256};
struct DummyCodeExecutor {
native_available: bool,
@@ -442,10 +482,10 @@ mod tests {
fallback_succeeds: bool,
}
impl CodeExecutor for DummyCodeExecutor {
impl<H: Hasher> CodeExecutor<H> for DummyCodeExecutor {
type Error = u8;
fn call<E: Externalities>(
fn call<E: Externalities<H>>(
&self,
ext: &mut E,
_code: &[u8],
@@ -506,7 +546,7 @@ mod tests {
b"dogglesworth".to_vec() => b"catXXX".to_vec(),
b"doug".to_vec() => b"notadog".to_vec()
];
let backend = InMemory::from(initial);
let backend = InMemory::<KeccakHasher, RlpCodec>::from(initial);
let mut overlay = OverlayedChanges {
committed: map![
b"dog".to_vec() => Some(b"puppy".to_vec()),
@@ -519,8 +559,11 @@ mod tests {
],
};
let mut ext = Ext::new(&mut overlay, &backend);
// Blake
// const ROOT: [u8; 32] = hex!("6ca394ff9b13d6690a51dea30b1b5c43108e52944d30b9095227c49bae03ff8b");
// Keccak
const ROOT: [u8; 32] = hex!("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3");
assert_eq!(ext.storage_root(), ROOT);
assert_eq!(ext.storage_root(), H256(ROOT));
}
#[test]
@@ -576,7 +619,7 @@ mod tests {
&mut Default::default(), &executor, "test", &[]).unwrap();
// check proof locally
let (local_result, _) = execution_proof_check(remote_root, remote_proof,
let (local_result, _) = execution_proof_check::<KeccakHasher, RlpCodec,_,>(remote_root, remote_proof,
&mut Default::default(), &executor, "test", &[]).unwrap();
// check that both results are correct
@@ -592,7 +635,7 @@ mod tests {
b"abc".to_vec() => b"2".to_vec(),
b"bbb".to_vec() => b"3".to_vec()
];
let backend = InMemory::from(initial).try_into_trie_backend().unwrap();
let backend = InMemory::<KeccakHasher, RlpCodec>::from(initial).try_into_trie_backend().unwrap();
let mut overlay = OverlayedChanges {
committed: map![
b"aba".to_vec() => Some(b"1312".to_vec()),
@@ -631,8 +674,8 @@ mod tests {
let remote_root = remote_backend.storage_root(::std::iter::empty()).0;
let remote_proof = prove_read(remote_backend, b"value2").unwrap().1;
// check proof locally
let local_result1 = read_proof_check(remote_root, remote_proof.clone(), b"value2").unwrap();
let local_result2 = read_proof_check(remote_root, remote_proof.clone(), &[0xff]).is_ok();
let local_result1 = read_proof_check::<KeccakHasher, RlpCodec>(remote_root, remote_proof.clone(), b"value2").unwrap();
let local_result2 = read_proof_check::<KeccakHasher, RlpCodec>(remote_root, remote_proof.clone(), &[0xff]).is_ok();
// check that results are correct
assert_eq!(local_result1, Some(vec![24]));
assert_eq!(local_result2, false);
@@ -17,23 +17,24 @@
//! Proving state machine backend.
use std::cell::RefCell;
use ethereum_types::H256 as TrieH256;
use hashdb::HashDB;
use hashdb::{Hasher, HashDB};
use memorydb::MemoryDB;
use patricia_trie::{TrieDB, TrieError, Trie, Recorder};
use patricia_trie::{TrieDB, Trie, Recorder, NodeCodec};
use trie_backend::{TrieBackend, Ephemeral};
use {Error, ExecutionError, Backend, TryIntoTrieBackend};
use rlp::Encodable;
use heapsize::HeapSizeOf;
/// Patricia trie-based backend which also tracks all touched storage trie values.
/// These can be sent to remote node and used as a proof of execution.
pub struct ProvingBackend {
backend: TrieBackend,
proof_recorder: RefCell<Recorder>,
pub struct ProvingBackend<H: Hasher, C: NodeCodec<H>> {
backend: TrieBackend<H, C>,
proof_recorder: RefCell<Recorder<H::Out>>,
}
impl ProvingBackend {
impl<H: Hasher, C: NodeCodec<H>> ProvingBackend<H, C> {
/// Create new proving backend.
pub fn new(backend: TrieBackend) -> Self {
pub fn new(backend: TrieBackend<H, C>) -> Self {
ProvingBackend {
backend,
proof_recorder: RefCell::new(Recorder::new()),
@@ -50,22 +51,26 @@ impl ProvingBackend {
}
}
impl Backend for ProvingBackend {
impl<H, C> Backend<H, C> for ProvingBackend<H, C>
where
H: Hasher,
C: NodeCodec<H>,
H::Out: Ord + Encodable + HeapSizeOf
{
type Error = String;
type Transaction = MemoryDB;
type Transaction = MemoryDB<H>;
fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
let mut read_overlay = MemoryDB::default();
let mut read_overlay = MemoryDB::new();
let eph = Ephemeral::new(
self.backend.backend_storage(),
&mut read_overlay,
);
let map_e = |e: Box<TrieError>| format!("Trie lookup error: {}", e);
let map_e = |e| format!("Trie lookup error: {}", e);
let mut proof_recorder = self.proof_recorder.try_borrow_mut()
.expect("only fails when already borrowed; storage() is non-reentrant; qed");
TrieDB::new(&eph, &self.backend.root()).map_err(map_e)?
TrieDB::<H, C>::new(&eph, &self.backend.root()).map_err(map_e)?
.get_with(key, &mut *proof_recorder).map(|x| x.map(|val| val.to_vec())).map_err(map_e)
}
@@ -77,21 +82,29 @@ impl Backend for ProvingBackend {
self.backend.pairs()
}
fn storage_root<I>(&self, delta: I) -> ([u8; 32], MemoryDB)
fn storage_root<I>(&self, delta: I) -> (H::Out, MemoryDB<H>)
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
{
self.backend.storage_root(delta)
}
}
impl TryIntoTrieBackend for ProvingBackend {
fn try_into_trie_backend(self) -> Option<TrieBackend> {
impl<H: Hasher, C: NodeCodec<H>> TryIntoTrieBackend<H, C> for ProvingBackend<H, C> {
fn try_into_trie_backend(self) -> Option<TrieBackend<H, C>> {
None
}
}
/// Create proof check backend.
pub fn create_proof_check_backend(root: TrieH256, proof: Vec<Vec<u8>>) -> Result<TrieBackend, Box<Error>> {
pub fn create_proof_check_backend<H, C>(
root: H::Out,
proof: Vec<Vec<u8>>
) -> Result<TrieBackend<H, C>, Box<Error>>
where
H: Hasher,
C: NodeCodec<H>,
H::Out: HeapSizeOf,
{
let mut db = MemoryDB::new();
for item in proof {
db.insert(&item);
@@ -110,8 +123,9 @@ mod tests {
use backend::{InMemory};
use trie_backend::tests::test_trie;
use super::*;
use primitives::{KeccakHasher, RlpCodec};
fn test_proving() -> ProvingBackend {
fn test_proving() -> ProvingBackend<KeccakHasher, RlpCodec> {
ProvingBackend::new(test_trie())
}
@@ -129,7 +143,7 @@ mod tests {
#[test]
fn proof_is_invalid_when_does_not_contains_root() {
assert!(create_proof_check_backend(1.into(), vec![]).is_err());
assert!(create_proof_check_backend::<KeccakHasher, RlpCodec>(1.into(), vec![]).is_err());
}
#[test]
@@ -148,7 +162,7 @@ mod tests {
#[test]
fn proof_recorded_and_checked() {
let contents = (0..64).map(|i| (vec![i], Some(vec![i]))).collect::<Vec<_>>();
let in_memory = InMemory::default();
let in_memory = InMemory::<KeccakHasher, RlpCodec>::default();
let in_memory = in_memory.update(contents);
let in_memory_root = in_memory.storage_root(::std::iter::empty()).0;
(0..64).for_each(|i| assert_eq!(in_memory.storage(&[i]).unwrap().unwrap(), vec![i]));
@@ -163,7 +177,7 @@ mod tests {
let proof = proving.extract_proof();
let proof_check = create_proof_check_backend(in_memory_root.into(), proof).unwrap();
let proof_check = create_proof_check_backend::<KeccakHasher, RlpCodec>(in_memory_root.into(), proof).unwrap();
assert_eq!(proof_check.storage(&[42]).unwrap().unwrap(), vec![42]);
}
}
@@ -17,48 +17,105 @@
//! Test implementation for Externalities.
use std::collections::HashMap;
use std::cmp::Ord;
use super::Externalities;
use triehash::trie_root;
use hashdb::Hasher;
use rlp::Encodable;
use std::marker::PhantomData;
use std::iter::FromIterator;
/// Simple HashMap based Externalities impl.
pub type TestExternalities = HashMap<Vec<u8>, Vec<u8>>;
/// Simple HashMap-based Externalities impl.
#[derive(Debug)]
pub struct TestExternalities<H> {
inner: HashMap<Vec<u8>, Vec<u8>>,
_hasher: PhantomData<H>,
}
impl Externalities for TestExternalities {
impl<H: Hasher> TestExternalities<H> {
/// Create a new instance of `TestExternalities`
pub fn new() -> Self {
TestExternalities {inner: HashMap::new(), _hasher: PhantomData}
}
/// Insert key/value
pub fn insert(&mut self, k: Vec<u8>, v: Vec<u8>) -> Option<Vec<u8>> {
self.inner.insert(k, v)
}
}
impl<H: Hasher> PartialEq for TestExternalities<H> {
fn eq(&self, other: &TestExternalities<H>) -> bool {
self.inner.eq(&other.inner)
}
}
impl<H: Hasher> FromIterator<(Vec<u8>, Vec<u8>)> for TestExternalities<H> {
fn from_iter<I: IntoIterator<Item=(Vec<u8>, Vec<u8>)>>(iter: I) -> Self {
let mut t = Self::new();
for i in iter {
t.inner.insert(i.0, i.1);
}
t
}
}
impl<H: Hasher> Default for TestExternalities<H> {
fn default() -> Self { Self::new() }
}
impl<H: Hasher> From<TestExternalities<H>> for HashMap<Vec<u8>, Vec<u8>> {
fn from(tex: TestExternalities<H>) -> Self {
tex.inner.into()
}
}
impl<H: Hasher> From< HashMap<Vec<u8>, Vec<u8>> > for TestExternalities<H> {
fn from(hashmap: HashMap<Vec<u8>, Vec<u8>>) -> Self {
TestExternalities { inner: hashmap, _hasher: PhantomData }
}
}
impl<H: Hasher> Externalities<H> for TestExternalities<H> where H::Out: Ord + Encodable {
fn storage(&self, key: &[u8]) -> Option<Vec<u8>> {
self.get(key).map(|x| x.to_vec())
self.inner.get(key).map(|x| x.to_vec())
}
fn place_storage(&mut self, key: Vec<u8>, maybe_value: Option<Vec<u8>>) {
match maybe_value {
Some(value) => { self.insert(key, value); }
None => { self.remove(&key); }
Some(value) => { self.inner.insert(key, value); }
None => { self.inner.remove(&key); }
}
}
fn clear_prefix(&mut self, prefix: &[u8]) {
self.retain(|key, _|
self.inner.retain(|key, _|
!key.starts_with(prefix)
)
}
fn chain_id(&self) -> u64 { 42 }
fn storage_root(&mut self) -> [u8; 32] {
trie_root(self.clone()).0
fn storage_root(&mut self) -> H::Out {
trie_root::<H, _, _, _>(self.inner.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
use primitives::{KeccakHasher, H256};
#[test]
fn commit_should_work() {
let mut ext = TestExternalities::new();
let mut ext = TestExternalities::<KeccakHasher>::new();
ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec());
ext.set_storage(b"dog".to_vec(), b"puppy".to_vec());
ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec());
// Blake
// const ROOT: [u8; 32] = hex!("6ca394ff9b13d6690a51dea30b1b5c43108e52944d30b9095227c49bae03ff8b");
// Keccak
const ROOT: [u8; 32] = hex!("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3");
assert_eq!(ext.storage_root(), ROOT);
assert_eq!(ext.storage_root(), H256(ROOT));
}
}
@@ -15,101 +15,104 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Trie-based state machine backend.
use Backend;
use hashdb::{Hasher, HashDB, AsHashDB};
use memorydb::MemoryDB;
use patricia_trie::{TrieDB, TrieDBMut, TrieError, Trie, TrieMut, NodeCodec};
use std::collections::HashMap;
use std::sync::Arc;
use hashdb::HashDB;
use memorydb::MemoryDB;
use patricia_trie::{TrieDB, TrieDBMut, TrieError, Trie, TrieMut};
use {Backend};
pub use ethereum_types::H256 as TrieH256;
use std::marker::PhantomData;
use heapsize::HeapSizeOf;
pub use hashdb::DBValue;
/// Backend trie storage trait.
pub trait Storage: Send + Sync {
pub trait Storage<H: Hasher>: Send + Sync {
/// Get a trie node.
fn get(&self, key: &TrieH256) -> Result<Option<DBValue>, String>;
fn get(&self, key: &H::Out) -> Result<Option<DBValue>, String>;
}
/// Try convert into trie-based backend.
pub trait TryIntoTrieBackend {
pub trait TryIntoTrieBackend<H: Hasher, C: NodeCodec<H>> {
/// Try to convert self into trie backend.
fn try_into_trie_backend(self) -> Option<TrieBackend>;
fn try_into_trie_backend(self) -> Option<TrieBackend<H, C>>;
}
/// Patricia trie-based backend. Transaction type is an overlay of changes to commit.
#[derive(Clone)]
pub struct TrieBackend {
storage: TrieBackendStorage,
root: TrieH256,
pub struct TrieBackend<H: Hasher, C: NodeCodec<H>> {
storage: TrieBackendStorage<H>,
root: H::Out,
_codec: PhantomData<C>
}
impl TrieBackend {
impl<H: Hasher, C: NodeCodec<H>> TrieBackend<H, C> where H::Out: HeapSizeOf {
/// Create new trie-based backend.
pub fn with_storage(db: Arc<Storage>, root: TrieH256) -> Self {
pub fn with_storage(db: Arc<Storage<H>>, root: H::Out) -> Self {
TrieBackend {
storage: TrieBackendStorage::Storage(db),
root,
_codec: PhantomData,
}
}
/// Create new trie-based backend for genesis block.
pub fn with_storage_for_genesis(db: Arc<Storage>) -> Self {
let mut root = TrieH256::default();
let mut mdb = MemoryDB::default();
TrieDBMut::new(&mut mdb, &mut root);
pub fn with_storage_for_genesis(db: Arc<Storage<H>>) -> Self {
let mut root = <H as Hasher>::Out::default();
let mut mdb = MemoryDB::<H>::new();
TrieDBMut::<H, C>::new(&mut mdb, &mut root);
Self::with_storage(db, root)
}
/// Create new trie-based backend backed by MemoryDb storage.
pub fn with_memorydb(db: MemoryDB, root: TrieH256) -> Self {
pub fn with_memorydb(db: MemoryDB<H>, root: H::Out) -> Self {
// TODO: check that root is a part of db???
TrieBackend {
storage: TrieBackendStorage::MemoryDb(db),
root,
_codec: PhantomData,
}
}
/// Get backend storage reference.
pub fn backend_storage(&self) -> &TrieBackendStorage {
pub fn backend_storage(&self) -> &TrieBackendStorage<H> {
&self.storage
}
/// Get trie root.
pub fn root(&self) -> &TrieH256 {
pub fn root(&self) -> &H::Out {
&self.root
}
}
impl super::Error for String {}
impl Backend for TrieBackend {
impl<H: Hasher, C: NodeCodec<H>> Backend<H, C> for TrieBackend<H, C> where H::Out: HeapSizeOf {
type Error = String;
type Transaction = MemoryDB;
type Transaction = MemoryDB<H>;
fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
let mut read_overlay = MemoryDB::default();
let mut read_overlay = MemoryDB::new();
let eph = Ephemeral {
storage: &self.storage,
overlay: &mut read_overlay,
};
let map_e = |e: Box<TrieError>| format!("Trie lookup error: {}", e);
TrieDB::new(&eph, &self.root).map_err(map_e)?
let map_e = |e| format!("Trie lookup error: {}", e);
TrieDB::<H, C>::new(&eph, &self.root).map_err(map_e)?
.get(key).map(|x| x.map(|val| val.to_vec())).map_err(map_e)
}
fn for_keys_with_prefix<F: FnMut(&[u8])>(&self, prefix: &[u8], mut f: F) {
let mut read_overlay = MemoryDB::default();
let mut read_overlay = MemoryDB::new();
let eph = Ephemeral {
storage: &self.storage,
overlay: &mut read_overlay,
};
let mut iter = move || -> Result<(), Box<TrieError>> {
let trie = TrieDB::new(&eph, &self.root)?;
let mut iter = move || -> Result<(), Box<TrieError<H::Out, C::Error>>> {
let trie = TrieDB::<H, C>::new(&eph, &self.root)?;
let mut iter = trie.iter()?;
iter.seek(prefix)?;
@@ -133,14 +136,14 @@ impl Backend for TrieBackend {
}
fn pairs(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
let mut read_overlay = MemoryDB::default();
let mut read_overlay = MemoryDB::new();
let eph = Ephemeral {
storage: &self.storage,
overlay: &mut read_overlay,
};
let collect_all = || -> Result<_, Box<TrieError>> {
let trie = TrieDB::new(&eph, &self.root)?;
let collect_all = || -> Result<_, Box<TrieError<H::Out, C::Error>>> {
let trie = TrieDB::<H, C>::new(&eph, &self.root)?;
let mut v = Vec::new();
for x in trie.iter()? {
let (key, value) = x?;
@@ -159,10 +162,10 @@ impl Backend for TrieBackend {
}
}
fn storage_root<I>(&self, delta: I) -> ([u8; 32], MemoryDB)
fn storage_root<I>(&self, delta: I) -> (H::Out, MemoryDB<H>)
where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
{
let mut write_overlay = MemoryDB::default();
let mut write_overlay = MemoryDB::new();
let mut root = self.root;
{
let mut eph = Ephemeral {
@@ -170,7 +173,7 @@ impl Backend for TrieBackend {
overlay: &mut write_overlay,
};
let mut trie = TrieDBMut::from_existing(&mut eph, &mut root).expect("prior state root to exist"); // TODO: handle gracefully
let mut trie = TrieDBMut::<H, C>::from_existing(&mut eph, &mut root).expect("prior state root to exist"); // TODO: handle gracefully
for (key, change) in delta {
let result = match change {
Some(val) => trie.insert(&key, &val),
@@ -183,23 +186,28 @@ impl Backend for TrieBackend {
}
}
(root.0.into(), write_overlay)
(root, write_overlay)
}
}
impl TryIntoTrieBackend for TrieBackend {
fn try_into_trie_backend(self) -> Option<TrieBackend> {
impl<H: Hasher, C: NodeCodec<H>> TryIntoTrieBackend<H, C> for TrieBackend<H, C> {
fn try_into_trie_backend(self) -> Option<TrieBackend<H, C>> {
Some(self)
}
}
pub struct Ephemeral<'a> {
storage: &'a TrieBackendStorage,
overlay: &'a mut MemoryDB,
pub struct Ephemeral<'a, H: 'a + Hasher> {
storage: &'a TrieBackendStorage<H>,
overlay: &'a mut MemoryDB<H>,
}
impl<'a> Ephemeral<'a> {
pub fn new(storage: &'a TrieBackendStorage, overlay: &'a mut MemoryDB) -> Self {
impl<'a, H: Hasher> AsHashDB<H> for Ephemeral<'a, H> where H::Out: HeapSizeOf {
fn as_hashdb(&self) -> &HashDB<H> { self }
fn as_hashdb_mut(&mut self) -> &mut HashDB<H> { self }
}
impl<'a, H: Hasher> Ephemeral<'a, H> {
pub fn new(storage: &'a TrieBackendStorage<H>, overlay: &'a mut MemoryDB<H>) -> Self {
Ephemeral {
storage,
overlay,
@@ -207,12 +215,12 @@ impl<'a> Ephemeral<'a> {
}
}
impl<'a> HashDB for Ephemeral<'a> {
fn keys(&self) -> HashMap<TrieH256, i32> {
impl<'a, H: Hasher> HashDB<H> for Ephemeral<'a, H> where H::Out: HeapSizeOf {
fn keys(&self) -> HashMap<H::Out, i32> {
self.overlay.keys() // TODO: iterate backing
}
fn get(&self, key: &TrieH256) -> Option<DBValue> {
fn get(&self, key: &H::Out) -> Option<DBValue> {
match self.overlay.raw(key) {
Some((val, i)) => {
if i <= 0 {
@@ -221,7 +229,7 @@ impl<'a> HashDB for Ephemeral<'a> {
Some(val)
}
}
None => match self.storage.get(&key) {
None => match self.storage.get(key) {
Ok(x) => x,
Err(e) => {
warn!(target: "trie", "Failed to read from DB: {}", e);
@@ -231,33 +239,33 @@ impl<'a> HashDB for Ephemeral<'a> {
}
}
fn contains(&self, key: &TrieH256) -> bool {
fn contains(&self, key: &H::Out) -> bool {
self.get(key).is_some()
}
fn insert(&mut self, value: &[u8]) -> TrieH256 {
fn insert(&mut self, value: &[u8]) -> H::Out {
self.overlay.insert(value)
}
fn emplace(&mut self, key: TrieH256, value: DBValue) {
fn emplace(&mut self, key: H::Out, value: DBValue) {
self.overlay.emplace(key, value)
}
fn remove(&mut self, key: &TrieH256) {
fn remove(&mut self, key: &H::Out) {
self.overlay.remove(key)
}
}
#[derive(Clone)]
pub enum TrieBackendStorage {
pub enum TrieBackendStorage<H: Hasher> {
/// Key value db + storage column.
Storage(Arc<Storage>),
Storage(Arc<Storage<H>>),
/// Hash db.
MemoryDb(MemoryDB),
MemoryDb(MemoryDB<H>),
}
impl TrieBackendStorage {
pub fn get(&self, key: &TrieH256) -> Result<Option<DBValue>, String> {
impl<H: Hasher> TrieBackendStorage<H> {
pub fn get(&self, key: &H::Out) -> Result<Option<DBValue>, String> {
match *self {
TrieBackendStorage::Storage(ref db) =>
db.get(key)
@@ -272,24 +280,25 @@ impl TrieBackendStorage {
pub mod tests {
use super::*;
use std::collections::HashSet;
use primitives::{KeccakHasher, RlpCodec, H256};
fn test_db() -> (MemoryDB, TrieH256) {
let mut root = TrieH256::default();
let mut mdb = MemoryDB::default();
fn test_db() -> (MemoryDB<KeccakHasher>, H256) {
let mut root = H256::default();
let mut mdb = MemoryDB::<KeccakHasher>::new();
{
let mut trie = TrieDBMut::new(&mut mdb, &mut root);
trie.insert(b"key", b"value").unwrap();
trie.insert(b"value1", &[42]).unwrap();
trie.insert(b"value2", &[24]).unwrap();
trie.insert(b":code", b"return 42").unwrap();
for i in 128u8..255u8 {
trie.insert(&[i], &[i]).unwrap();
}
let mut trie = TrieDBMut::<_, RlpCodec>::new(&mut mdb, &mut root);
trie.insert(b"key", b"value").expect("insert failed");
trie.insert(b"value1", &[42]).expect("insert failed");
trie.insert(b"value2", &[24]).expect("insert failed");
trie.insert(b":code", b"return 42").expect("insert failed");
for i in 128u8..255u8 {
trie.insert(&[i], &[i]).unwrap();
}
}
(mdb, root)
}
pub fn test_trie() -> TrieBackend {
pub(crate) fn test_trie() -> TrieBackend<KeccakHasher, RlpCodec> {
let (mdb, root) = test_db();
TrieBackend::with_memorydb(mdb, root)
}
@@ -311,12 +320,16 @@ pub mod tests {
#[test]
fn pairs_are_empty_on_empty_storage() {
assert!(TrieBackend::with_memorydb(MemoryDB::new(), Default::default()).pairs().is_empty());
let db = TrieBackend::<KeccakHasher, RlpCodec>::with_memorydb(
MemoryDB::new(),
Default::default()
);
assert!(db.pairs().is_empty());
}
#[test]
fn storage_root_is_non_default() {
assert!(test_trie().storage_root(::std::iter::empty()).0 != [0; 32]);
assert!(test_trie().storage_root(::std::iter::empty()).0 != H256([0; 32]));
}
#[test]
+1 -1
View File
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Telemtetry utils.
//! Telemetry utils.
//!
//! `telemetry` macro be used from whereever in the Substrate codebase
//! in order to send real-time logging information to the telemetry
@@ -14,3 +14,5 @@ substrate-primitives = { path = "../primitives" }
substrate-runtime-support = { path = "../runtime-support" }
substrate-test-runtime = { path = "../test-runtime" }
substrate-runtime-primitives = { path = "../runtime/primitives" }
hashdb = { git = "https://github.com/paritytech/parity-common" }
@@ -22,6 +22,7 @@ use keyring;
use runtime;
use {Backend, Executor};
use primitives::{KeccakHasher, RlpCodec};
/// Extension trait for test block builder.
pub trait BlockBuilderExt {
@@ -29,7 +30,7 @@ pub trait BlockBuilderExt {
fn push_transfer(&mut self, transfer: runtime::Transfer) -> Result<(), client::error::Error>;
}
impl BlockBuilderExt for client::block_builder::BlockBuilder<Backend, Executor, runtime::Block> {
impl BlockBuilderExt for client::block_builder::BlockBuilder<Backend, Executor, runtime::Block, KeccakHasher, RlpCodec> {
fn push_transfer(&mut self, transfer: runtime::Transfer) -> Result<(), client::error::Error> {
self.push(sign_tx(transfer))
}
+5 -2
View File
@@ -25,6 +25,7 @@ extern crate substrate_primitives as primitives;
extern crate substrate_runtime_support as runtime_support;
extern crate substrate_runtime_primitives as runtime_primitives;
#[macro_use] extern crate substrate_executor as executor;
extern crate hashdb;
pub extern crate substrate_client as client;
pub extern crate substrate_keyring as keyring;
@@ -36,10 +37,12 @@ mod block_builder_ext;
pub use client_ext::TestClient;
pub use block_builder_ext::BlockBuilderExt;
use primitives::{KeccakHasher, RlpCodec};
mod local_executor {
#![allow(missing_docs)]
use super::runtime;
// TODO: change the macro and pass in the `BlakeHasher` that dispatch needs from here instead
native_executor_instance!(pub LocalExecutor, runtime::api::dispatch, runtime::VERSION, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm"));
}
@@ -47,7 +50,7 @@ mod local_executor {
pub use local_executor::LocalExecutor;
/// Test client database backend.
pub type Backend = client::in_mem::Backend<runtime::Block>;
pub type Backend = client::in_mem::Backend<runtime::Block, KeccakHasher, RlpCodec>;
/// Test client executor.
pub type Executor = client::LocalCallExecutor<Backend, executor::NativeExecutor<LocalExecutor>>;
+11 -1
View File
@@ -171,8 +171,9 @@ mod tests {
use codec::{Joiner, KeyedVec};
use keyring::Keyring;
use ::{Header, Digest, Extrinsic, Transfer};
use primitives::KeccakHasher;
fn new_test_ext() -> TestExternalities {
fn new_test_ext() -> TestExternalities<KeccakHasher> {
map![
twox_128(b"latest").to_vec() => vec![69u8; 32],
twox_128(b":auth:len").to_vec() => vec![].and(&3u32),
@@ -195,6 +196,9 @@ mod tests {
let h = Header {
parent_hash: [69u8; 32].into(),
number: 1,
// Blake
// state_root: hex!("0c22599e15fb5e052c84f79a2aab179ba6bb238218fd86bdd4a74ebcc87adfcd").into(),
// Keccak
state_root: hex!("97dfcd1f8cbf8845fcb544f89332f1a94c1137f7d1b199ef0b0a6ed217015c3e").into(),
extrinsics_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
digest: Digest { logs: vec![], },
@@ -223,6 +227,9 @@ mod tests {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
// Blake
// state_root: hex!("0425393fd07e2a806cfd7e990ee91dc92fe6bba34eab2bf45d5be7d67e24d467").into(),
// Keccak
state_root: hex!("0dd8210adaf581464cc68555814a787ed491f8c608d0a0dbbf2208a6d44190b1").into(),
extrinsics_root: hex!("951508f2cc0071500a74765ab0fb2f280fdcdd329d5f989dda675010adee99d6").into(),
digest: Digest { logs: vec![], },
@@ -248,6 +255,9 @@ mod tests {
header: Header {
parent_hash: b.header.hash(),
number: 2,
// Blake
// state_root: hex!("e32dd1d84d9133ca48078d2d83f2b0db19f9d47229ba98bf5ced0e9f86fac2c7").into(),
// Keccak
state_root: hex!("c93f2fd494c386fa32ee76b6198a7ccf5db12c02c3a79755fd2d4646ec2bf8d7").into(),
extrinsics_root: hex!("3563642676d7e042c894eedc579ba2d6eeedf9a6c66d9d557599effc9f674372").into(),
digest: Digest { logs: vec![], },