Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Fix sync: ensure block hash gets read from the DB correctly #152

Merged
merged 6 commits into from
May 11, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 87 additions & 42 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion polkadot/keystore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
authors = ["Parity Technologies <robert@parity.io>"]

[dependencies]
ethcore-crypto = { git = "https://github.com/paritytech/parity", default_features = false }
ethcore-crypto = { git = "https://github.com/paritytech/parity.git", default_features = false }
ed25519 = { path = "../../substrate/ed25519" }
error-chain = "0.11"
hex = "0.3"
Expand Down
6 changes: 4 additions & 2 deletions polkadot/keystore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ impl EncryptedKey {
let mut ciphertext = vec![0; PKCS_LEN];

// aes-128-ctr with initial vector of iv
crypto::aes::encrypt(&derived_left_bits, &iv, plain, &mut *ciphertext);
crypto::aes::encrypt_128_ctr(&derived_left_bits, &iv, plain, &mut *ciphertext)
.expect("input lengths of key and iv are both 16; qed");

// KECCAK(DK[16..31] ++ <ciphertext>), where DK[16..31] - derived_right_bits
let mac = crypto::derive_mac(&derived_right_bits, &*ciphertext).keccak256();
Expand All @@ -116,7 +117,8 @@ impl EncryptedKey {
}

let mut plain = [0; PKCS_LEN];
crypto::aes::decrypt(&derived_left_bits, &self.iv, &self.ciphertext, &mut plain[..]);
crypto::aes::decrypt_128_ctr(&derived_left_bits, &self.iv, &self.ciphertext, &mut plain[..])
.expect("input lengths of key and iv are both 16; qed");
Ok(plain)
}
}
Expand Down
6 changes: 3 additions & 3 deletions polkadot/service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ fn poc_1_testnet_config() -> ChainConfig {
parachains: Some(Default::default()),
};
let boot_nodes = vec![
"enode://ce29df27adace5c2a08efc2fd58ce1a2587f2157061e7788861dfef3c0cbf275af8476f93b5f10ecbcd7d6c2fdac109b581502dd7a67a361f9efa7593308bedd@104.211.54.233:30333".into(),
"enode://db86cdf0d653c774cb9f357ba99ee035b2dc3ae4313e93a79a38d9e0089dc5eacdf01a5cab7d41b6a44c83bc78599b76318bc59501f9d62cc6b08cfb74777032@104.211.48.51:30333".into(),
"enode://a9458a01ccc278eab98ee329f529ca3bcb88e13e4e0cda7318a63c6ae704b74eca7c5a05cff106d531cdc41facfbe63540de5f733108fbbbb7d0235131ca39a0@104.211.48.247:30333".into(),
"enode://a93a29fa68d965452bf0ff8c1910f5992fe2273a72a1ee8d3a3482f68512a61974211ba32bb33f051ceb1530b8ba3527fc36224ba6b9910329025e6d9153cf50@104.211.54.233:30333".into(),
"enode://051b18f63a316c4c5fef4631f8c550ae0adba179153588406fac3e5bbbbf534ebeda1bf475dceda27a531f6cdef3846ab6a010a269aa643a1fec7bff51af66bd@104.211.48.51:30333".into(),
"enode://c831ec9011d2c02d2c4620fc88db6d897a40d2f88fd75f47b9e4cf3b243999acb6f01b7b7343474650b34eeb1363041a422a91f1fc3850e43482983ee15aa582@104.211.48.247:30333".into(),
];
ChainConfig { genesis_config, boot_nodes }
}
Expand Down
1 change: 1 addition & 0 deletions substrate/client/db/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ substrate-runtime-support = { path = "../../../substrate/runtime-support" }
substrate-codec = { path = "../../../substrate/codec" }

[dev-dependencies]
kvdb-memorydb = { git = "https://github.com/paritytech/parity.git" }
91 changes: 73 additions & 18 deletions substrate/client/db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ extern crate substrate_state_machine as state_machine;
extern crate substrate_primitives as primitives;
extern crate substrate_runtime_support as runtime_support;
extern crate substrate_codec as codec;
#[macro_use] extern crate log;

#[macro_use]
extern crate log;

#[cfg(test)]
extern crate kvdb_memorydb;

use std::sync::Arc;
use std::path::PathBuf;
Expand All @@ -33,7 +38,7 @@ use parking_lot::RwLock;
use runtime_support::Hashable;
use primitives::blake2_256;
use kvdb_rocksdb::{Database, DatabaseConfig};
use kvdb::DBTransaction;
use kvdb::{KeyValueDB, DBTransaction};
use primitives::block::{self, Id as BlockId, HeaderHash};
use state_machine::backend::Backend as StateBackend;
use state_machine::CodeExecutor;
Expand Down Expand Up @@ -70,7 +75,7 @@ mod columns {
pub const HEADER: Option<u32> = Some(3);
pub const BODY: Option<u32> = Some(4);
pub const JUSTIFICATION: Option<u32> = Some(5);
pub const NUM_COLUMNS: Option<u32> = Some(6);
pub const NUM_COLUMNS: u32 = 6;
}

mod meta {
Expand All @@ -97,12 +102,6 @@ struct Meta {
genesis_hash: HeaderHash,
}

/// Block database
pub struct BlockchainDb {
db: Arc<Database>,
meta: RwLock<Meta>,
}

type BlockKey = [u8; 4];

// Little endian
Expand All @@ -125,6 +124,12 @@ fn db_err(err: kvdb::Error) -> client::error::Error {
}
}

/// Block database
pub struct BlockchainDb {
db: Arc<KeyValueDB>,
meta: RwLock<Meta>,
}

impl BlockchainDb {
fn id(&self, id: BlockId) -> Result<Option<BlockKey>, client::error::Error> {
match id {
Expand All @@ -145,7 +150,7 @@ impl BlockchainDb {
}
}

fn new(db: Arc<Database>) -> Result<BlockchainDb, client::error::Error> {
fn new(db: Arc<KeyValueDB>) -> Result<BlockchainDb, client::error::Error> {
let (best_hash, best_number) = if let Some(Some(header)) = db.get(columns::META, meta::BEST_BLOCK).and_then(|id|
match id {
Some(id) => db.get(columns::HEADER, &id).map(|h| h.map(|b| block::Header::decode(&mut &b[..]))),
Expand Down Expand Up @@ -243,9 +248,9 @@ impl client::blockchain::Backend for BlockchainDb {
}

fn hash(&self, number: block::Number) -> Result<Option<block::HeaderHash>, client::error::Error> {
Ok(self.db.get(columns::BLOCK_INDEX, &number_to_db_key(number))
.map_err(db_err)?
.map(|hash| block::HeaderHash::from_slice(&hash)))
self.read_db(BlockId::Number(number), columns::HEADER).map(|x|
x.map(|raw| blake2_256(&raw[..])).map(Into::into)
)
}
}

Expand Down Expand Up @@ -304,30 +309,43 @@ impl state_machine::Backend for DbState {

/// In-memory backend. Keeps all states and blocks in memory. Useful for testing.
pub struct Backend {
db: Arc<Database>,
db: Arc<KeyValueDB>,
blockchain: BlockchainDb,
old_states: RwLock<HashMap<BlockKey, state_machine::backend::InMemory>>,
}

impl Backend {
/// Create a new instance of in-mem backend.
/// Create a new instance of database backend.
pub fn new(config: &DatabaseSettings) -> Result<Backend, client::error::Error> {
let mut db_config = DatabaseConfig::with_columns(columns::NUM_COLUMNS);
let mut db_config = DatabaseConfig::with_columns(Some(columns::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 = Arc::new(Database::open(&db_config, &path).map_err(db_err)?);

Backend::from_kvdb(db as Arc<_>)
}

#[cfg(test)]
fn new_test() -> Backend {
let db = Arc::new(::kvdb_memorydb::create(columns::NUM_COLUMNS));

Backend::from_kvdb(db as Arc<_>).expect("failed to create test-db")
}

fn from_kvdb(db: Arc<KeyValueDB>) -> Result<Backend, client::error::Error> {
let blockchain = BlockchainDb::new(db.clone())?;

//load latest state
let mut state = state_machine::backend::InMemory::new();
let mut old_states = HashMap::new();
if let Some(iter) = db.iter(columns::STATE).map(|iter| iter.map(|(k, v)| (k.to_vec(), Some(v.to_vec())))) {

{
let iter = db.iter(columns::STATE).map(|(k, v)| (k.to_vec(), Some(v.to_vec())));
state.commit(iter);
old_states.insert(number_to_db_key(blockchain.meta.read().best_number), state);
}

debug!("DB Opened at {}", path);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's wrong with this log?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could add it back, but it would need to be in the wrapping function, not this one

Ok(Backend {
db,
blockchain,
Expand Down Expand Up @@ -397,3 +415,40 @@ impl client::backend::Backend for Backend {
}
}

#[cfg(test)]
mod tests {
use super::*;
use client::backend::Backend as BTrait;
use client::backend::BlockImportOperation as Op;
use client::blockchain::Backend as BCTrait;

#[test]
fn block_hash_inserted_correctly() {
let db = Backend::new_test();
for i in 1..10 {
assert!(db.blockchain().hash(i).unwrap().is_none());

{
let mut op = db.begin_operation(BlockId::Number(i - 1)).unwrap();
let header = block::Header {
number: i,
parent_hash: Default::default(),
state_root: Default::default(),
digest: Default::default(),
extrinsics_root: Default::default(),
};

op.set_block_data(
header,
Some(vec![]),
None,
true,
).unwrap();
op.set_storage(vec![].into_iter()).unwrap();
db.commit_operation(op).unwrap();
}

assert!(db.blockchain().hash(i).unwrap().is_some())
}
}
}
2 changes: 1 addition & 1 deletion substrate/network/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ impl ConsensusService for Service {

impl NetworkProtocolHandler for ProtocolHandler {
fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) {
io.register_timer(0, 1000).expect("Error registering sync timer");
io.register_timer(0, ::std::time::Duration::from_millis(1000)).expect("Error registering sync timer");
}

fn read(&self, io: &NetworkContext, peer: &PeerId, _packet_id: u8, data: &[u8]) {
Expand Down
2 changes: 2 additions & 0 deletions substrate/network/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ impl ChainSync {
PeerSyncState::AncestorSearch(n) => {
match response.blocks.get(0) {
Some(ref block) => {
trace!(target: "sync", "Got ancestry block #{} ({}) from peer {}", n, block.hash, peer_id);
match protocol.chain().block_hash(n) {
Ok(Some(block_hash)) if block_hash == block.hash => {
peer.common_hash = block.hash;
Expand Down Expand Up @@ -423,6 +424,7 @@ impl ChainSync {
}

fn request_ancestry(io: &mut SyncIo, protocol: &Protocol, peer_id: PeerId, block: BlockNumber) {
trace!(target: "sync", "Requesting ancestry block #{} from {}", block, peer_id);
let request = message::BlockRequest {
id: 0,
fields: vec![message::BlockAttribute::Header, message::BlockAttribute::Justification],
Expand Down