mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Merge branch 'master' into split-substrate
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/target/
|
||||
**/target/
|
||||
**/*.rs.bk
|
||||
*.swp
|
||||
.wasm-binaries
|
||||
|
||||
Generated
+233
-212
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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(())
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>>> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>>) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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" }
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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,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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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>>;
|
||||
|
||||
@@ -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![], },
|
||||
|
||||
Reference in New Issue
Block a user