-
Notifications
You must be signed in to change notification settings - Fork 857
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
26 changed files
with
755 additions
and
59 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
[package] | ||
name = "reth-consensus" | ||
version = "0.1.0" | ||
edition = "2021" | ||
license = "MIT OR Apache-2.0" | ||
repository = "https://github.com/foundry-rs/reth" | ||
readme = "README.md" | ||
|
||
[dependencies] | ||
# reth | ||
reth-primitives = { path = "../primitives" } | ||
reth-interfaces = { path = "../interfaces" } | ||
reth-rlp = {path = "../common/rlp"} | ||
|
||
# common | ||
async-trait = "0.1.57" | ||
thiserror = "1.0.37" | ||
eyre = "0.6.8" | ||
auto_impl = "1.0" | ||
tokio = { version = "1.21.2", features = ["sync"] } | ||
|
||
# proof related | ||
triehash = "0.8" | ||
# See to replace hashers to simplify libraries | ||
plain_hasher = "0.2" | ||
hash-db = "0.15" | ||
# todo replace with faster rlp impl | ||
rlp = { version = "0.5", default-features = false } | ||
# replace with tiny-keccak (it is faster hasher) | ||
sha3 = { version = "0.10", default-features = false } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
//! Reth block execution/validation configuration and constants | ||
use reth_primitives::BlockNumber; | ||
|
||
/// Initial base fee as defined in: https://eips.ethereum.org/EIPS/eip-1559 | ||
pub const EIP1559_INITIAL_BASE_FEE: u64 = 1_000_000_000; | ||
/// Base fee max change denominator as defined in: https://eips.ethereum.org/EIPS/eip-1559 | ||
pub const EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR: u64 = 8; | ||
/// Elasticity multiplier as defined in: https://eips.ethereum.org/EIPS/eip-1559 | ||
pub const EIP1559_ELASTICITY_MULTIPLIER: u64 = 2; | ||
|
||
/// Configuration for consensus | ||
#[derive(Debug, Clone)] | ||
pub struct Config { | ||
/// EIP-1559 hard fork number | ||
pub london_hard_fork_block: BlockNumber, | ||
/// The Merge/Paris hard fork block number | ||
pub paris_hard_fork_block: BlockNumber, | ||
} | ||
|
||
impl Default for Config { | ||
fn default() -> Self { | ||
Self { london_hard_fork_block: 12965000, paris_hard_fork_block: 15537394 } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
//! Consensus for ethereum network | ||
|
||
use crate::{verification, Config}; | ||
use reth_interfaces::consensus::{Consensus, Error, ForkchoiceState}; | ||
use reth_primitives::{HeaderLocked, H256}; | ||
use tokio::sync::watch; | ||
|
||
/// Ethereum consensus | ||
pub struct EthConsensus { | ||
/// Watcher over the forkchoice state | ||
channel: (watch::Sender<ForkchoiceState>, watch::Receiver<ForkchoiceState>), | ||
/// Configuration | ||
config: Config, | ||
} | ||
|
||
impl EthConsensus { | ||
/// Create new object | ||
pub fn new(config: Config) -> Self { | ||
Self { | ||
channel: watch::channel(ForkchoiceState { | ||
head_block_hash: H256::zero(), | ||
finalized_block_hash: H256::zero(), | ||
safe_block_hash: H256::zero(), | ||
}), | ||
config, | ||
} | ||
} | ||
} | ||
|
||
impl Consensus for EthConsensus { | ||
fn fork_choice_state(&self) -> watch::Receiver<ForkchoiceState> { | ||
self.channel.1.clone() | ||
} | ||
|
||
fn validate_header(&self, header: &HeaderLocked, parent: &HeaderLocked) -> Result<(), Error> { | ||
verification::validate_header_standalone(header, &self.config)?; | ||
verification::validate_header_regarding_parent(parent, header, &self.config) | ||
|
||
// TODO Consensus checks for: | ||
// * mix_hash & nonce PoW stuf | ||
// * extra_data | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#![warn(missing_docs, unreachable_pub)] | ||
#![deny(unused_must_use, rust_2018_idioms)] | ||
#![doc(test( | ||
no_crate_inject, | ||
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables)) | ||
))] | ||
|
||
//! Reth consensus. | ||
pub mod config; | ||
pub mod consensus; | ||
pub mod verification; | ||
|
||
/// Helper function for calculating Merkle proofs and hashes | ||
pub mod proofs; | ||
|
||
pub use config::Config; | ||
pub use consensus::EthConsensus; | ||
pub use reth_interfaces::consensus::Error; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
use hash_db::Hasher; | ||
use plain_hasher::PlainHasher; | ||
use reth_primitives::{Bytes, Header, Log, Receipt, TransactionSigned, H256}; | ||
use reth_rlp::Encodable; | ||
use rlp::RlpStream; | ||
use sha3::{Digest, Keccak256}; | ||
use triehash::sec_trie_root; | ||
|
||
#[derive(Default, Debug, Clone, PartialEq, Eq)] | ||
struct KeccakHasher; | ||
impl Hasher for KeccakHasher { | ||
type Out = H256; | ||
type StdHasher = PlainHasher; | ||
const LENGTH: usize = 32; | ||
fn hash(x: &[u8]) -> Self::Out { | ||
let out = Keccak256::digest(x); | ||
// TODO make more performant, H256 from slice is not good enought. | ||
H256::from_slice(out.as_slice()) | ||
} | ||
} | ||
|
||
/// Calculate Transaction root. Iterate over transaction and create merkle trie of | ||
/// (rlp(index),encoded(tx)) pairs. | ||
pub fn calculate_transaction_root<'a>( | ||
transactions: impl IntoIterator<Item = &'a TransactionSigned>, | ||
) -> H256 { | ||
sec_trie_root::<KeccakHasher, _, _, _>( | ||
transactions | ||
.into_iter() | ||
.enumerate() | ||
.map(|(index, tx)| { | ||
// TODO replace with reth-rlp | ||
let mut stream = RlpStream::new(); | ||
stream.append(&index); | ||
let mut bytes = Vec::new(); | ||
tx.encode(&mut bytes); | ||
(stream.out().freeze().into(), bytes) | ||
}) | ||
.collect::<Vec<(Bytes, Vec<u8>)>>(), | ||
) | ||
} | ||
|
||
/// Create receipt root for header | ||
pub fn calculate_receipt_root<'a>(receipts: impl IntoIterator<Item = &'a Receipt>) -> H256 { | ||
sec_trie_root::<KeccakHasher, _, _, _>( | ||
receipts | ||
.into_iter() | ||
.enumerate() | ||
.map(|(index, receipt)| { | ||
let mut stream = RlpStream::new(); | ||
stream.append(&index); | ||
let mut bytes = Vec::new(); | ||
receipt.encode(&mut bytes); | ||
(stream.out().freeze().into(), bytes) | ||
}) | ||
.collect::<Vec<(Bytes, Vec<u8>)>>(), | ||
) | ||
} | ||
|
||
/// Create log hash for header | ||
pub fn calculate_log_root<'a>(logs: impl IntoIterator<Item = &'a Log>) -> H256 { | ||
//https://github.com/ethereum/go-ethereum/blob/356bbe343a30789e77bb38f25983c8f2f2bfbb47/cmd/evm/internal/t8ntool/execution.go#L255 | ||
let mut stream = RlpStream::new(); | ||
stream.begin_unbounded_list(); | ||
for log in logs { | ||
stream.begin_list(3); | ||
stream.append(&log.address); | ||
stream.append_list(&log.topics); | ||
stream.append(&log.data); | ||
} | ||
stream.finalize_unbounded_list(); | ||
let out = stream.out().freeze(); | ||
|
||
let out = Keccak256::digest(out); | ||
H256::from_slice(out.as_slice()) | ||
} | ||
|
||
/// Calculate hash over omners/uncles headers | ||
pub fn calculate_omners_root<'a>(_omners: impl IntoIterator<Item = &'a Header>) -> H256 { | ||
// RLP Encode | ||
let mut stream = RlpStream::new(); | ||
stream.begin_unbounded_list(); | ||
/* TODO | ||
for omner in omners { | ||
stream.append(omner) | ||
} | ||
*/ | ||
stream.finalize_unbounded_list(); | ||
let bytes = stream.out().freeze(); | ||
let out = Keccak256::digest(bytes); | ||
H256::from_slice(out.as_slice()) | ||
} | ||
|
||
// TODO state root | ||
|
||
// TODO bloom |
Oops, something went wrong.