PoA warp implementation (#5488)

* 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
This commit is contained in:
Robert Habermeier
2017-05-17 12:41:33 +02:00
committed by keorn
parent 5d973f8ef5
commit 4c5e4ac8da
35 changed files with 1547 additions and 347 deletions

View File

@@ -452,6 +452,10 @@ impl Engine for AuthorityRound {
fn sign(&self, hash: H256) -> Result<Signature, Error> {
self.signer.sign(hash).map_err(Into::into)
}
fn snapshot_components(&self) -> Option<Box<::snapshot::SnapshotComponents>> {
Some(Box::new(::snapshot::PoaSnapshot))
}
}
#[cfg(test)]

View File

@@ -216,6 +216,10 @@ impl Engine for BasicAuthority {
fn sign(&self, hash: H256) -> Result<Signature, Error> {
self.signer.sign(hash).map_err(Into::into)
}
fn snapshot_components(&self) -> Option<Box<::snapshot::SnapshotComponents>> {
Some(Box::new(::snapshot::PoaSnapshot))
}
}
#[cfg(test)]

View File

@@ -22,7 +22,7 @@ use header::Header;
/// Verifier for all blocks within an epoch with self-contained state.
///
/// See docs on `Engine` relating to proving functions for more details.
pub trait EpochVerifier: Sync {
pub trait EpochVerifier: Send + Sync {
/// Get the epoch number.
fn epoch_number(&self) -> u64;

View File

@@ -107,8 +107,8 @@ pub enum EpochChange {
Unsure(Unsure),
/// No epoch change.
No,
/// Validation proof required, and the new epoch number and expected proof.
Yes(u64, Bytes),
/// Validation proof required, and the new epoch number.
Yes(u64),
}
/// More data required to determine if an epoch change occurred at a given block.
@@ -227,6 +227,9 @@ pub trait Engine : Sync + Send {
/// For example, for PoA chains the proof will be a validator set,
/// and the corresponding `EpochVerifier` can be used to correctly validate
/// all blocks produced under that `ValidatorSet`
///
/// It must be possible to generate an epoch proof for any block in an epoch,
/// and it should always be equivalent to the proof of the transition block.
fn epoch_proof(&self, _header: &Header, _caller: &Call)
-> Result<Vec<u8>, Error>
{
@@ -234,6 +237,11 @@ pub trait Engine : Sync + Send {
}
/// Whether an epoch change occurred at the given header.
///
/// If the block or receipts are required, return `Unsure` and the function will be
/// called again with them.
/// Return `Yes` or `No` when the answer is definitively known.
///
/// Should not interact with state.
fn is_epoch_end(&self, _header: &Header, _block: Option<&[u8]>, _receipts: Option<&[Receipt]>)
-> EpochChange

View File

@@ -76,23 +76,45 @@ impl ValidatorSet for Multi {
-> EpochChange
{
let (set_block, set) = self.correct_set_by_number(header.number());
let (next_set_block, _) = self.correct_set_by_number(header.number() + 1);
// multi-set transitions require epoch changes.
if next_set_block != set_block {
return EpochChange::Yes(next_set_block);
}
match set.is_epoch_end(header, block, receipts) {
EpochChange::Yes(num, proof) => EpochChange::Yes(set_block + num, proof),
EpochChange::Yes(num) => EpochChange::Yes(set_block + num),
other => other,
}
}
fn epoch_proof(&self, header: &Header, caller: &Call) -> Result<Vec<u8>, String> {
self.correct_set_by_number(header.number()).1.epoch_proof(header, caller)
let (set_block, set) = self.correct_set_by_number(header.number());
let (next_set_block, next_set) = self.correct_set_by_number(header.number() + 1);
if next_set_block != set_block {
return next_set.epoch_proof(header, caller);
}
set.epoch_proof(header, caller)
}
fn epoch_set(&self, header: &Header, proof: &[u8]) -> Result<(u64, super::SimpleList), ::error::Error> {
// "multi" epoch is the inner set's epoch plus the transition block to that set.
// ensures epoch increases monotonically.
let (set_block, set) = self.correct_set_by_number(header.number());
let (inner_epoch, list) = set.epoch_set(header, proof)?;
Ok((set_block + inner_epoch, list))
let (next_set_block, next_set) = self.correct_set_by_number(header.number() + 1);
// this block kicks off a new validator set -- get the validator set
// starting there.
if next_set_block != set_block {
let (inner_epoch, list) = next_set.epoch_set(header, proof)?;
Ok((next_set_block + inner_epoch, list))
} else {
let (inner_epoch, list) = set.epoch_set(header, proof)?;
Ok((set_block + inner_epoch, list))
}
}
fn contains_with_caller(&self, bh: &H256, address: &Address, caller: &Call) -> bool {

View File

@@ -182,10 +182,9 @@ impl ValidatorSet for ValidatorSafeContract {
);
match (nonce, validators) {
(Some(nonce), Some(validators)) => {
let proof = encode_proof(nonce, &validators);
(Some(nonce), Some(_)) => {
let new_epoch = nonce.low_u64();
::engines::EpochChange::Yes(new_epoch, proof)
::engines::EpochChange::Yes(new_epoch)
}
_ => {
debug!(target: "engine", "Successfully decoded log turned out to be bad.");