feat: Consensus crate and verification functions. (#152)

* wip executor

* wip

* Cleanup added some checks and structure to executor

* adding additional block/header checks

* add basefee calculation and check

* some cleanup

* Sanity check test

* Test for sanity check

* move verification to consensus crate

* cleanup

* Better Error handling
This commit is contained in:
rakita
2022-11-02 12:59:51 +01:00
committed by GitHub
parent 1ea98d40cf
commit ac2f3fcd8a
26 changed files with 755 additions and 59 deletions

View File

@@ -1,6 +1,5 @@
use async_trait::async_trait;
use reth_primitives::Header;
use thiserror::Error;
use reth_primitives::{BlockHash, BlockNumber, HeaderLocked, H256};
use tokio::sync::watch::Receiver;
/// Re-export forkchoice state
@@ -15,13 +14,40 @@ pub trait Consensus: Send + Sync {
fn fork_choice_state(&self) -> Receiver<ForkchoiceState>;
/// Validate if header is correct and follows consensus specification
fn validate_header(&self, header: &Header, parent: &Header) -> Result<(), Error>;
fn validate_header(&self, header: &HeaderLocked, parent: &HeaderLocked) -> Result<(), Error>;
}
/// Consensus errors (TODO)
#[derive(Error, Debug)]
/// Consensus Errors
#[allow(missing_docs)]
#[derive(thiserror::Error, Debug, PartialEq, Eq, Clone)]
pub enum Error {
/// Explanatory
#[error("Example of consensus error")]
ConsensusError,
#[error("Block used gas ({gas_used:?}) is greater then gas limit ({gas_limit:?})")]
HeaderGasUsedExceedsGasLimit { gas_used: u64, gas_limit: u64 },
#[error("Block ommner hash ({got:?}) is different then expected: ({expected:?})")]
BodyOmmnersHashDiff { got: H256, expected: H256 },
#[error("Block transaction root ({got:?}) is different then expected: ({expected:?})")]
BodyTransactionRootDiff { got: H256, expected: H256 },
#[error("Block receipts root ({got:?}) is different then expected: ({expected:?})")]
BodyReceiptsRootDiff { got: H256, expected: H256 },
#[error("Block with [hash:{hash:?},number: {number:}] is already known")]
BlockKnown { hash: BlockHash, number: BlockNumber },
#[error("Block parent [hash:{hash:?}] is not known")]
ParentUnknown { hash: BlockHash },
#[error("Block number {block_number:?} is missmatch with parent block number {parent_block_number:?}")]
ParentBlockNumberMissmatch { parent_block_number: BlockNumber, block_number: BlockNumber },
#[error(
"Block timestamp {timestamp:?} is in past in comparison with parent timestamp {parent_timestamp:?}"
)]
TimestampIsInPast { parent_timestamp: u64, timestamp: u64 },
#[error("Block timestamp {timestamp:?} is in future in comparison of our clock time {present_timestamp:?}")]
TimestampIsInFuture { timestamp: u64, present_timestamp: u64 },
// TODO make better error msg :)
#[error("Child gas_limit {child_gas_limit:?} max increase is {parent_gas_limit}/1024")]
GasLimitInvalidIncrease { parent_gas_limit: u64, child_gas_limit: u64 },
#[error("Child gas_limit {child_gas_limit:?} max decrease is {parent_gas_limit}/1024")]
GasLimitInvalidDecrease { parent_gas_limit: u64, child_gas_limit: u64 },
#[error("Base fee missing")]
BaseFeeMissing,
#[error("Block base fee ({got:?}) is different then expected: ({expected:?})")]
BaseFeeDiff { expected: u64, got: u64 },
}

View File

@@ -2,7 +2,7 @@
pub type Result<T> = std::result::Result<T, Error>;
/// Core error variants possible when interacting with the blockchain
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]

View File

@@ -14,7 +14,7 @@ pub trait BlockExecutor {
}
/// BlockExecutor Errors
#[derive(Error, Debug, Clone)]
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum Error {
/// Example of error
#[error("Example of error.")]

View File

@@ -1,9 +1,22 @@
use crate::Result;
use auto_impl::auto_impl;
use reth_primitives::{
rpc::{BlockId, BlockNumber},
Block, H256, U256,
Block, BlockHash, Header, H256, U256,
};
/// Client trait for fetching `Header` related data.
#[auto_impl(&)]
pub trait HeaderProvider: Send + Sync + 'static {
/// Check if block is known
fn is_known(&self, block_hash: &BlockHash) -> Result<bool> {
self.header(block_hash).map(|header| header.is_some())
}
/// Get header by block hash
fn header(&self, block_hash: &BlockHash) -> Result<Option<Header>>;
}
/// Client trait for fetching `Block` related data.
pub trait BlockProvider: Send + Sync + 'static {
/// Returns the current info for the chain.

View File

@@ -1,5 +1,5 @@
mod block;
mod storage;
pub use block::BlockProvider;
pub use block::{BlockProvider, HeaderProvider};
pub use storage::StorageProvider;

View File

@@ -155,9 +155,13 @@ impl Consensus for TestConsensus {
self.channel.1.clone()
}
fn validate_header(&self, _header: &Header, _parent: &Header) -> Result<(), consensus::Error> {
fn validate_header(
&self,
_header: &HeaderLocked,
_parent: &HeaderLocked,
) -> Result<(), consensus::Error> {
if self.fail_validation {
Err(consensus::Error::ConsensusError)
Err(consensus::Error::BaseFeeMissing)
} else {
Ok(())
}