Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
14 changes: 1 addition & 13 deletions core/src/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use super::headerchain::{HeaderChain, HeaderProvider};
use super::invoice_db::{InvoiceDB, InvoiceProvider};
use super::route::{tree_route, ImportRoute};
use crate::blockchain_info::BlockChainInfo;
use crate::consensus::epoch::{PendingTransition as PendingEpochTransition, Transition as EpochTransition};
use crate::consensus::epoch::Transition as EpochTransition;
use crate::consensus::CodeChainEngine;
use crate::db::{self, Readable, Writable};
use crate::encoded;
Expand Down Expand Up @@ -427,18 +427,6 @@ impl BlockChain {
None
}
}

/// Write a pending epoch transition by block hash.
pub fn insert_pending_transition(&self, batch: &mut DBTransaction, hash: H256, t: &PendingEpochTransition) {
batch.write(db::COL_EXTRA, &hash, t);
}

/// Get a pending epoch transition by block hash.
// TODO: implement removal safely: this can only be done upon finality of a block
// that _uses_ the pending transition.
pub fn get_pending_transition(&self, hash: H256) -> Option<PendingEpochTransition> {
self.db.read(db::COL_EXTRA, &hash)
}
}

/// An iterator which walks the blockchain towards the genesis.
Expand Down
13 changes: 2 additions & 11 deletions core/src/blockchain/extras.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use ctypes::BlockNumber;
use kvdb::PREFIX_LEN as DB_PREFIX_LEN;
use primitives::{H256, H264, U256};

use crate::consensus::epoch::{PendingTransition as PendingEpochTransition, Transition as EpochTransition};
use crate::consensus::epoch::Transition as EpochTransition;
use crate::db::Key;
use crate::types::TransactionId;

Expand All @@ -38,8 +38,7 @@ enum ExtrasIndex {
TransactionAddress = 3,
/// Epoch transition data index.
EpochTransitions = 4,
/// Pending epoch transition data index.
PendingEpochTransition = 5,
// (Reserved) = 5,
}

fn with_index(hash: &H256, i: ExtrasIndex) -> H264 {
Expand Down Expand Up @@ -130,14 +129,6 @@ impl Key<EpochTransitions> for u64 {
}
}

impl Key<PendingEpochTransition> for H256 {
type Target = H264;

fn key(&self) -> H264 {
with_index(self, ExtrasIndex::PendingEpochTransition)
}
}

/// Familial details concerning a block
#[derive(Debug, Clone, RlpEncodable, RlpDecodable)]
pub struct BlockDetails {
Expand Down
36 changes: 1 addition & 35 deletions core/src/client/importer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,6 @@ impl Importer {

let mut batch = DBTransaction::new();

// check epoch end signal
self.check_epoch_end_signal(block.header(), &chain, &mut batch);

block.state().journal_under(&mut batch, number).expect("DB commit failed");
let route = chain.insert_block(&mut batch, block_data, invoices.clone(), self.engine.borrow());

Expand All @@ -233,11 +230,7 @@ impl Importer {

// check for ending of epoch and write transition if it occurs.
fn check_epoch_end(&self, header: &Header, chain: &BlockChain, client: &Client) {
let is_epoch_end = self.engine.is_epoch_end(
header,
&(|hash| chain.block_header(&hash)),
&(|hash| chain.get_pending_transition(hash)), // TODO: limit to current epoch.
);
let is_epoch_end = self.engine.is_epoch_end(header, &(|hash| chain.block_header(&hash)));

if let Some(proof) = is_epoch_end {
cdebug!(CLIENT, "Epoch transition at block {}", header.hash());
Expand All @@ -256,33 +249,6 @@ impl Importer {
}
}

// check for epoch end signal and write pending transition if it occurs.
// state for the given block must be available.
fn check_epoch_end_signal(&self, header: &Header, chain: &BlockChain, batch: &mut DBTransaction) {
use crate::consensus::EpochChange;
let hash = header.hash();

match self.engine.signals_epoch_end(header) {
EpochChange::Yes(proof) => {
use crate::consensus::epoch::PendingTransition;
use crate::consensus::Proof;

let Proof::Known(proof) = proof;
cdebug!(CLIENT, "Block {} signals epoch end.", hash);

let pending = PendingTransition {
proof,
};
chain.insert_pending_transition(batch, hash, &pending);
}
EpochChange::No => {}
EpochChange::Unsure => {
cwarn!(CLIENT, "Detected invalid engine implementation.");
cwarn!(CLIENT, "Engine claims to require more block data, but everything provided.");
}
}
}

fn check_and_close_block(&self, block: &PreverifiedBlock, client: &Client) -> Result<LockedBlock, ()> {
let engine = &*self.engine;
let header = &block.header;
Expand Down
50 changes: 0 additions & 50 deletions core/src/consensus/epoch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,9 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use ctypes::machine::Machine;
use primitives::H256;
use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp};

/// Verifier for all blocks within an epoch with self-contained state.
pub trait EpochVerifier<M: Machine>: Send + Sync {
/// Lightly verify the next block header.
/// This may not be a header belonging to a different epoch.
fn verify_light(&self, header: &M::Header) -> Result<(), M::Error>;

/// Perform potentially heavier checks on the next block header.
fn verify_heavy(&self, header: &M::Header) -> Result<(), M::Error> {
self.verify_light(header)
}

/// Check a finality proof against this epoch verifier.
/// Returns `Some(hashes)` if the proof proves finality of these hashes.
/// Returns `None` if the proof doesn't prove anything.
fn check_finality_proof(&self, _proof: &[u8]) -> Option<Vec<H256>> {
None
}
}

/// Special "no-op" verifier for stateless, epoch-less engines.
pub struct NoOp;

impl<M: Machine> EpochVerifier<M> for NoOp {
fn verify_light(&self, _header: &M::Header) -> Result<(), M::Error> {
Ok(())
}
}

/// A full epoch transition.
#[derive(Debug, Clone)]
pub struct Transition {
Expand Down Expand Up @@ -79,24 +50,3 @@ impl Decodable for Transition {
})
}
}

/// An epoch transition pending a finality proof.
/// Not all transitions need one.
pub struct PendingTransition {
/// "transition/epoch" proof from the engine.
pub proof: Vec<u8>,
}

impl Encodable for PendingTransition {
fn rlp_append(&self, s: &mut RlpStream) {
s.append_single_value(&self.proof);
}
}

impl Decodable for PendingTransition {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
Ok(PendingTransition {
proof: rlp.as_val()?,
})
}
}
58 changes: 1 addition & 57 deletions core/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ use ctypes::transaction::Action;
use ctypes::util::unexpected::{Mismatch, OutOfBounds};
use primitives::{Bytes, H256, U256};

use self::epoch::{EpochVerifier, NoOp, PendingTransition};
use self::tendermint::types::{BitSet, View};
use crate::account_provider::AccountProvider;
use crate::block::SealedBlock;
Expand Down Expand Up @@ -202,42 +201,17 @@ pub trait ConsensusEngine<M: Machine>: Sync + Send {
Ok(())
}

/// Genesis epoch data.
fn genesis_epoch_data(&self, _header: &M::Header) -> Result<Vec<u8>, String> {
Ok(Vec::new())
}

/// Whether an epoch change is signalled at the given header but will require finality.
/// If a change can be enacted immediately then return `No` from this function but
/// `Yes` from `is_epoch_end`.
///
/// Return `Yes` or `No` when the answer is definitively known.
fn signals_epoch_end(&self, _header: &M::Header) -> EpochChange {
EpochChange::No
}

/// Whether a block is the end of an epoch.
///
/// This either means that an immediate transition occurs or a block signalling transition
/// has reached finality. The `Headers` given are not guaranteed to return any blocks
/// from any epoch other than the current.
///
/// Return optional transition proof.
fn is_epoch_end(
&self,
_chain_head: &M::Header,
_chain: &Headers<M::Header>,
_transition_store: &PendingTransitionStore,
) -> Option<Vec<u8>> {
fn is_epoch_end(&self, _chain_head: &M::Header, _chain: &Headers<M::Header>) -> Option<Vec<u8>> {
None
}

/// Create an epoch verifier from validation proof and a flag indicating
/// whether finality is required.
fn epoch_verifier<'a>(&self, _header: &M::Header, _proof: &'a [u8]) -> ConstructedVerifier<'a, M> {
ConstructedVerifier::Trusted(Box::new(NoOp))
}

/// Populate a header's fields based on its parent's header.
/// Usually implements the chain scoring rule based on weight.
fn populate_from_parent(&self, _header: &mut M::Header, _parent: &M::Header) {}
Expand Down Expand Up @@ -313,39 +287,9 @@ pub trait ConsensusEngine<M: Machine>: Sync + Send {
}
}

/// Results of a query of whether an epoch change occurred at the given block.
pub enum EpochChange {
/// Cannot determine until more data is passed.
Unsure,
/// No epoch change.
No,
/// The epoch will change, with proof.
Yes(Proof),
}

/// Proof generated on epoch change.
pub enum Proof {
/// Known proof (extracted from signal)
Known(Vec<u8>),
}

/// Generated epoch verifier.
pub enum ConstructedVerifier<'a, M: Machine> {
/// Fully trusted verifier.
Trusted(Box<EpochVerifier<M>>),
/// Verifier unconfirmed. Check whether given finality proof finalizes given hash
/// under previous epoch.
Unconfirmed(Box<EpochVerifier<M>>, &'a [u8], H256),
/// Error constructing verifier.
Err(Error),
}

/// Type alias for a function we can get headers by hash through.
pub type Headers<'a, H> = Fn(H256) -> Option<H> + 'a;

/// Type alias for a function we can query pending transitions by block hash through.
pub type PendingTransitionStore<'a> = Fn(H256) -> Option<PendingTransition> + 'a;

/// Voting errors.
#[derive(Debug)]
pub enum EngineError {
Expand Down
61 changes: 6 additions & 55 deletions core/src/consensus/simple_poa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use self::params::SimplePoAParams;
use super::signer::EngineSigner;
use super::validator_set::validator_list::ValidatorList;
use super::validator_set::ValidatorSet;
use super::{ConsensusEngine, ConstructedVerifier, EngineError, Seal};
use super::{ConsensusEngine, EngineError, Seal};
use crate::account_provider::AccountProvider;
use crate::block::{ExecutedBlock, IsBlock};
use crate::client::EngineClient;
Expand Down Expand Up @@ -55,16 +55,6 @@ impl SimplePoA {
}
}

struct EpochVerifier {
list: ValidatorList,
}

impl super::epoch::EpochVerifier<CodeChainMachine> for EpochVerifier {
fn verify_light(&self, header: &Header) -> Result<(), Error> {
verify_external(header, &self.list)
}
}

fn verify_external(header: &Header, validators: &ValidatorSet) -> Result<(), Error> {
use rlp::UntrustedRlp;

Expand Down Expand Up @@ -128,51 +118,12 @@ impl ConsensusEngine<CodeChainMachine> for SimplePoA {
verify_external(header, &*self.validators)
}

fn genesis_epoch_data(&self, header: &Header) -> Result<Vec<u8>, String> {
self.validators.genesis_epoch_data(header)
}

#[cfg(not(test))]
fn signals_epoch_end(&self, _header: &Header) -> super::EpochChange {
// don't bother signalling even though a contract might try.
super::EpochChange::No
}

#[cfg(test)]
fn signals_epoch_end(&self, header: &Header) -> super::EpochChange {
// in test mode, always signal even though they don't be finalized.
let first = header.number() == 0;
self.validators.signals_epoch_end(first, header)
}

fn is_epoch_end(
&self,
chain_head: &Header,
_chain: &super::Headers<Header>,
_transition_store: &super::PendingTransitionStore,
) -> Option<Vec<u8>> {
fn is_epoch_end(&self, chain_head: &Header, _chain: &super::Headers<Header>) -> Option<Vec<u8>> {
let first = chain_head.number() == 0;

// finality never occurs so only apply immediate transitions.
self.validators.is_epoch_end(first, chain_head)
}

fn epoch_verifier<'a>(&self, header: &Header, proof: &'a [u8]) -> ConstructedVerifier<'a, CodeChainMachine> {
let first = header.number() == 0;

match self.validators.epoch_set(first, &self.machine, header.number(), proof) {
Ok((list, finalize)) => {
let verifier = Box::new(EpochVerifier {
list,
});

// our epoch verifier will ensure no unverified verifier is ever verified.
match finalize {
Some(finalize) => ConstructedVerifier::Unconfirmed(verifier, proof, finalize),
None => ConstructedVerifier::Trusted(verifier),
}
}
Err(e) => ConstructedVerifier::Err(e),
if first {
Some(Vec::new())
} else {
None
}
}

Expand Down
Loading