Skip to content

Commit

Permalink
PoA warp implementation (openethereum#5488)
Browse files Browse the repository at this point in the history
* separate modules for consensus snapshot chunks

* bulk of authority warp logic

* finish authority warp implementation

* squash warnings and enable authority snapshot mode

* test harness for PoA

* fiddle with harness

* epoch generation proof fixes

* update constructor code

* store epoch transition proof after block commit

* basic snap and restore test

* use keyvaluedb in state restoration

* decompress chunks

* fix encoding issues

* fixed-to-contract-to-contract test

* implement ancient block import

* restore genesis transition in PoW snapshot

* add format version method to snapshot components

* supported version numbers in snapshot_components

* allow returning of ancient epoch transitions

* genesis hash mismatch check

* remove commented code
  • Loading branch information
rphmeier authored and keorn committed May 17, 2017
1 parent 5d973f8 commit 4c5e4ac
Show file tree
Hide file tree
Showing 35 changed files with 1,547 additions and 347 deletions.
2 changes: 1 addition & 1 deletion devtools/src/random_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl Drop for RandomTempPath {

pub struct GuardedTempResult<T> {
pub result: Option<T>,
pub _temp: RandomTempPath
pub _temp: RandomTempPath,
}

impl<T> GuardedTempResult<T> {
Expand Down
3 changes: 3 additions & 0 deletions ethcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ stats = { path = "../util/stats" }
time = "0.1"
transient-hashmap = "0.4"

[dev-dependencies]
native-contracts = { path = "native_contracts", features = ["test_contracts"] }

[features]
jit = ["evmjit"]
evm-debug = ["slow-blocks"]
Expand Down
3 changes: 3 additions & 0 deletions ethcore/native_contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ ethcore-util = { path = "../../util" }

[build-dependencies]
native-contract-generator = { path = "generator" }

[features]
default = []
8 changes: 8 additions & 0 deletions ethcore/native_contracts/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ const VALIDATOR_SET_ABI: &'static str = r#"[{"constant":true,"inputs":[],"name":

const VALIDATOR_REPORT_ABI: &'static str = r#"[{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"},{"name":"proof","type":"bytes"}],"name":"reportMalicious","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"}],"name":"reportBenign","outputs":[],"payable":false,"type":"function"}]"#;

const TEST_VALIDATOR_SET_ABI: &'static str = r#"[{"constant":true,"inputs":[],"name":"transitionNonce","outputs":[{"name":"n","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"newValidators","type":"address[]"}],"name":"setValidators","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"vals","type":"address[]"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_parent_hash","type":"bytes32"},{"indexed":true,"name":"_nonce","type":"uint256"},{"indexed":false,"name":"_new_set","type":"address[]"}],"name":"ValidatorsChanged","type":"event"}]"#;

fn build_file(name: &str, abi: &str, filename: &str) {
let code = ::native_contract_generator::generate_module(name, abi).unwrap();

Expand All @@ -43,10 +45,16 @@ fn build_file(name: &str, abi: &str, filename: &str) {
f.write_all(code.as_bytes()).unwrap();
}

fn build_test_contracts() {
build_file("ValidatorSet", TEST_VALIDATOR_SET_ABI, "test_validator_set.rs");
}

fn main() {
build_file("Registry", REGISTRY_ABI, "registry.rs");
build_file("ServiceTransactionChecker", SERVICE_TRANSACTION_ABI, "service_transaction.rs");
build_file("SecretStoreAclStorage", SECRETSTORE_ACL_STORAGE_ABI, "secretstore_acl_storage.rs");
build_file("ValidatorSet", VALIDATOR_SET_ABI, "validator_set.rs");
build_file("ValidatorReport", VALIDATOR_REPORT_ABI, "validator_report.rs");

build_test_contracts();
}
2 changes: 2 additions & 0 deletions ethcore/native_contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ mod secretstore_acl_storage;
mod validator_set;
mod validator_report;

pub mod test_contracts;

pub use self::registry::Registry;
pub use self::service_transaction::ServiceTransactionChecker;
pub use self::secretstore_acl_storage::SecretStoreAclStorage;
Expand Down
21 changes: 21 additions & 0 deletions ethcore/native_contracts/src/test_contracts/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity 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.

// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.

//! Contracts used for testing.
pub mod validator_set;

pub use self::validator_set::ValidatorSet;
21 changes: 21 additions & 0 deletions ethcore/native_contracts/src/test_contracts/validator_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity 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.

// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.

#![allow(unused_mut, unused_variables, unused_imports)]

//! Test validator set contract.
include!(concat!(env!("OUT_DIR"), "/test_validator_set.rs"));
18 changes: 17 additions & 1 deletion ethcore/src/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,12 @@ impl<'a> Iterator for EpochTransitionIter<'a> {
let is_in_canon_chain = self.chain.block_hash(transition.block_number)
.map_or(false, |hash| hash == transition.block_hash);

if is_in_canon_chain {
// if the transition is within the block gap, there will only be
// one candidate, and it will be from a snapshot restored from.
let is_ancient = self.chain.first_block_number()
.map_or(false, |first| first > transition.block_number);

if is_ancient || is_in_canon_chain {
return Some((transitions.number, transition))
}
}
Expand Down Expand Up @@ -864,6 +869,7 @@ impl BlockChain {
}

/// Iterate over all epoch transitions.
/// This will only return transitions within the canonical chain.
pub fn epoch_transitions(&self) -> EpochTransitionIter {
let iter = self.db.iter_from_prefix(db::COL_EXTRA, &EPOCH_KEY_PREFIX[..]);
EpochTransitionIter {
Expand All @@ -872,6 +878,16 @@ impl BlockChain {
}
}

/// Get a specific epoch transition by epoch number and provided block hash.
pub fn epoch_transition(&self, epoch_num: u64, block_hash: H256) -> Option<EpochTransition> {
trace!(target: "blockchain", "Loading epoch {} transition at block {}",
epoch_num, block_hash);

self.db.read(db::COL_EXTRA, &epoch_num).and_then(|transitions: EpochTransitions| {
transitions.candidates.into_iter().find(|c| c.block_hash == block_hash)
})
}

/// Add a child to a given block. Assumes that the block hash is in
/// the chain and the child's parent is this block.
///
Expand Down
68 changes: 68 additions & 0 deletions ethcore/src/client/ancient_import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity 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.

// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.

//! Helper for ancient block import.
use std::sync::Arc;

use engines::{Engine, EpochVerifier, EpochChange};
use error::Error;
use header::Header;

use rand::Rng;
use util::RwLock;

// do "heavy" verification on ~1/50 blocks, randomly sampled.
const HEAVY_VERIFY_RATE: f32 = 0.02;

/// Ancient block verifier: import an ancient sequence of blocks in order from a starting
/// epoch.
pub struct AncientVerifier {
cur_verifier: RwLock<Box<EpochVerifier>>,
engine: Arc<Engine>,
}

impl AncientVerifier {
/// Create a new ancient block verifier with the given engine and initial verifier.
pub fn new(engine: Arc<Engine>, start_verifier: Box<EpochVerifier>) -> Self {
AncientVerifier {
cur_verifier: RwLock::new(start_verifier),
engine: engine,
}
}

/// Verify the next block header, randomly choosing whether to do heavy or light
/// verification. If the block is the end of an epoch, updates the epoch verifier.
pub fn verify<R: Rng, F: Fn(u64) -> Result<Box<EpochVerifier>, Error>>(
&self,
rng: &mut R,
header: &Header,
block: &[u8],
receipts: &[::receipt::Receipt],
load_verifier: F,
) -> Result<(), ::error::Error> {
match rng.gen::<f32>() <= HEAVY_VERIFY_RATE {
true => self.cur_verifier.read().verify_heavy(header)?,
false => self.cur_verifier.read().verify_light(header)?,
}

if let EpochChange::Yes(num) = self.engine.is_epoch_end(header, Some(block), Some(receipts)) {
*self.cur_verifier.write() = load_verifier(num)?;
}

Ok(())
}
}
Loading

0 comments on commit 4c5e4ac

Please sign in to comment.