Fetching changes proof from remote nodes (#769)

* changes_trie

* changs_trie: continue

* changes_trie: adding tests

* fixed TODO

* removed obsolete ExtrinsicChanges

* encodable ChangesTrieConfiguration

* removed polkadot fle

* fixed grumbles

* ext_storage_changes_root returns u32

* moved changes trie root to digest

* removed commented code

* read storage values from native code

* fixed grumbles

* fixed grumbles

* missing comma

* key changes proof generation + query

* fix grumbles

* check that changes trie config is not changed by block.finalize()

* fixed changes trie config check
This commit is contained in:
Svyatoslav Nikolsky
2018-09-29 11:47:29 +03:00
committed by Gav Wood
parent fdfd4672c1
commit c54350661d
20 changed files with 753 additions and 107 deletions
+17 -4
View File
@@ -18,20 +18,29 @@
use std::collections::HashMap;
use runtime_io::twox_128;
use codec::{KeyedVec, Joiner};
use primitives::AuthorityId;
use codec::{Encode, KeyedVec, Joiner};
use primitives::{AuthorityId, ChangesTrieConfiguration};
use primitives::storage::well_known_keys;
use runtime_primitives::traits::Block;
/// Configuration of a general Substrate test genesis block.
pub struct GenesisConfig {
pub changes_trie_config: Option<ChangesTrieConfiguration>,
pub authorities: Vec<AuthorityId>,
pub balances: Vec<(AuthorityId, u64)>,
}
impl GenesisConfig {
pub fn new_simple(authorities: Vec<AuthorityId>, balance: u64) -> Self {
Self::new(false, authorities, balance)
}
pub fn new(support_changes_trie: bool, authorities: Vec<AuthorityId>, balance: u64) -> Self {
GenesisConfig {
changes_trie_config: match support_changes_trie {
true => Some(super::changes_trie_config()),
false => None,
},
authorities: authorities.clone(),
balances: authorities.into_iter().map(|a| (a, balance)).collect(),
}
@@ -39,7 +48,7 @@ impl GenesisConfig {
pub fn genesis_map(&self) -> HashMap<Vec<u8>, Vec<u8>> {
let wasm_runtime = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm").to_vec();
self.balances.iter()
let mut map: HashMap<Vec<u8>, Vec<u8>> = self.balances.iter()
.map(|&(account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance)))
.map(|(k, v)| (twox_128(&k[..])[..].to_vec(), v.to_vec()))
.chain(vec![
@@ -51,7 +60,11 @@ impl GenesisConfig {
.enumerate()
.map(|(i, account)| ((i as u32).to_keyed_vec(well_known_keys::AUTHORITY_PREFIX), vec![].and(account)))
)
.collect()
.collect();
if let Some(ref changes_trie_config) = self.changes_trie_config {
map.insert(well_known_keys::CHANGES_TRIE_CONFIG.to_vec(), changes_trie_config.encode());
}
map
}
}
+8
View File
@@ -141,6 +141,14 @@ pub fn run_tests(mut input: &[u8]) -> Vec<u8> {
[stxs.len() as u8].encode()
}
/// Changes trie configuration (optionally) used in tests.
pub fn changes_trie_config() -> primitives::ChangesTrieConfiguration {
primitives::ChangesTrieConfiguration {
digest_interval: 4,
digest_levels: 2,
}
}
pub mod api {
use system;
impl_stubs!(
+24 -9
View File
@@ -18,7 +18,7 @@
//! and depositing logs.
use rstd::prelude::*;
use runtime_io::{storage_root, enumerated_trie_root};
use runtime_io::{storage_root, enumerated_trie_root, storage_changes_root};
use runtime_support::storage::{self, StorageValue, StorageMap};
use runtime_primitives::traits::{Hash as HashT, BlakeTwo256, Digest as DigestT};
use runtime_primitives::generic;
@@ -32,15 +32,18 @@ const NONCE_OF: &[u8] = b"nonce:";
const BALANCE_OF: &[u8] = b"balance:";
storage_items! {
ExtrinsicIndex: b"sys:xti" => required u32;
ExtrinsicData: b"sys:xtd" => required map [ u32 => Vec<u8> ];
// The current block number being processed. Set by `execute_block`.
Number: b"sys:num" => required BlockNumber;
ParentHash: b"sys:pha" => required Hash;
}
pub fn balance_of_key(who: AccountId) -> Vec<u8> {
who.to_keyed_vec(BALANCE_OF)
}
pub fn balance_of(who: AccountId) -> u64 {
storage::get_or(&who.to_keyed_vec(BALANCE_OF), 0)
storage::get_or(&balance_of_key(who), 0)
}
pub fn nonce_of(who: AccountId) -> u64 {
@@ -62,7 +65,7 @@ pub fn initialise_block(header: Header) {
// populate environment.
<Number>::put(&header.number);
<ParentHash>::put(&header.parent_hash);
<ExtrinsicIndex>::put(0);
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &0u32);
}
/// Actually execute all transitioning for `block`.
@@ -77,26 +80,38 @@ pub fn execute_block(block: Block) {
assert!(txs_root == header.extrinsics_root, "Transaction trie root must be valid.");
// execute transactions
block.extrinsics.iter().for_each(|e| { execute_transaction_backend(e).map_err(|_| ()).expect("Extrinsic error"); });
block.extrinsics.iter().enumerate().for_each(|(i, e)| {
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(i as u32));
execute_transaction_backend(e).map_err(|_| ()).expect("Extrinsic error");
storage::unhashed::kill(well_known_keys::EXTRINSIC_INDEX);
});
// check storage root.
let storage_root = storage_root().into();
info_expect_equal_hash(&storage_root, &header.state_root);
assert!(storage_root == header.state_root, "Storage root must match that calculated.");
// check digest
let mut digest = Digest::default();
if let Some(storage_changes_root) = storage_changes_root(header.number) {
digest.push(generic::DigestItem::ChangesTrieRoot::<Hash, u64>(storage_changes_root.into()));
}
assert!(digest == header.digest, "Header digest items must match that calculated.");
}
/// Execute a transaction outside of the block execution function.
/// This doesn't attempt to validate anything regarding the block.
pub fn execute_transaction(utx: Extrinsic) -> ApplyResult {
let extrinsic_index = ExtrinsicIndex::get();
let extrinsic_index: u32 = storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX).unwrap();
let result = execute_transaction_backend(&utx);
ExtrinsicData::insert(extrinsic_index, utx.encode());
ExtrinsicIndex::put(extrinsic_index + 1);
execute_transaction_backend(&utx)
storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(extrinsic_index + 1));
result
}
/// Finalise the block.
pub fn finalise_block() -> Header {
let extrinsic_index = ExtrinsicIndex::take();
let extrinsic_index: u32 = storage::unhashed::take(well_known_keys::EXTRINSIC_INDEX).unwrap();
let txs: Vec<_> = (0..extrinsic_index).map(ExtrinsicData::take).collect();
let txs = txs.iter().map(Vec::as_slice).collect::<Vec<_>>();
let extrinsics_root = enumerated_trie_root::<Blake2Hasher>(&txs).into();