Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c9fa764
chore: clean up `.gitignore`
onbjerg Nov 10, 2022
4a168d3
fix: make RO cursors `Send + Sync`
onbjerg Nov 10, 2022
3fa663d
feat(wip): bodies stage
onbjerg Nov 10, 2022
70c8c4e
driveby: improve docs
onbjerg Nov 10, 2022
317a0d0
chore: don't panic if we're the first stage
onbjerg Nov 10, 2022
ca1695f
chore: use `Vec` for ommers
onbjerg Nov 10, 2022
175d902
feat: error handling in bodies downloader
onbjerg Nov 10, 2022
b1ddc36
chore: remove stale comment
onbjerg Nov 10, 2022
794f2dc
chore: pascal-case stage id
onbjerg Nov 12, 2022
7df907b
refactor: remove unused new fns
onbjerg Nov 12, 2022
9125914
refactor: distinguish downloaders with prefix
onbjerg Nov 12, 2022
9d08695
refactor: move downloader errs to own module
onbjerg Nov 12, 2022
16d3bb8
refactor: `stream_bodies` -> `bodies_stream`
onbjerg Nov 12, 2022
447ebc3
test: fix borked imports in header stage
onbjerg Nov 12, 2022
8214e10
test: clean up header tests
onbjerg Nov 12, 2022
41cfe63
test: add basic body stage tests
onbjerg Nov 12, 2022
a2b1ad3
test: add 2 more body stage test skeletons
onbjerg Nov 12, 2022
e1b5724
test: move generator test utils to own module
onbjerg Nov 12, 2022
f66105e
refactor: move proof functions to primitives crate
onbjerg Nov 12, 2022
74fd799
feat: add block generator test utils
onbjerg Nov 12, 2022
32728a9
test: more body stage tests
onbjerg Nov 14, 2022
7245c3e
chore: fix typo (`Cannonical*` -> `Canonical`)
onbjerg Nov 14, 2022
f9184fd
docs: document `bodies_to_download`
onbjerg Nov 14, 2022
fe733fd
test: more body stage tests
onbjerg Nov 14, 2022
e1e05eb
test: more body stage tests
onbjerg Nov 14, 2022
be52c98
refactor: clean up body stage tests a bit
onbjerg Nov 14, 2022
683bf96
test: fix broken tests
onbjerg Nov 14, 2022
0e0e9cd
refactor: clean up body stage tests
onbjerg Nov 14, 2022
e38e193
test: more body stage tests
onbjerg Nov 14, 2022
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
.idea
/target
target
27 changes: 22 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ members = [
"crates/net/rpc-api",
"crates/net/rpc-types",
"crates/net/headers-downloaders",
"crates/net/bodies-downloaders",
"crates/primitives",
"crates/stages",
"crates/transaction-pool",
Expand Down
1 change: 0 additions & 1 deletion crates/.gitignore

This file was deleted.

12 changes: 1 addition & 11 deletions crates/consensus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,4 @@ 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 }
tokio = { version = "1.21.2", features = ["sync"] }
6 changes: 5 additions & 1 deletion crates/consensus/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{verification, Config};
use reth_interfaces::consensus::{Consensus, Error, ForkchoiceState};
use reth_primitives::{SealedHeader, H256};
use reth_primitives::{BlockLocked, SealedHeader, H256};
use tokio::sync::watch;

/// Ethereum consensus
Expand Down Expand Up @@ -40,4 +40,8 @@ impl Consensus for EthConsensus {
// * mix_hash & nonce PoW stuf
// * extra_data
}

fn pre_validate_block(&self, block: &BlockLocked) -> Result<(), Error> {
verification::validate_block_standalone(block, false)
}
}
3 changes: 0 additions & 3 deletions crates/consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ 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;
56 changes: 38 additions & 18 deletions crates/consensus/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,38 +115,58 @@ pub fn validate_transaction_regarding_state<AP: AccountProvider>(
Ok(())
}

/// Validate block standalone
pub fn validate_block_standalone(block: &BlockLocked) -> Result<(), Error> {
// check ommers hash
let ommers_hash = crate::proofs::calculate_ommers_root(block.ommers.iter().map(|h| h.as_ref()));
/// Validate a block without regard for state:
///
/// - Compares the ommer hash in the block header to the block body
/// - Compares the transactions root in the block header to the block body
/// - Pre-execution transaction validation
/// - (Optionally) Compares the receipts root in the block header to the block body
pub fn validate_block_standalone(
block: &BlockLocked,
validate_receipts: bool,
) -> Result<(), Error> {
// Check ommers hash
// TODO(onbjerg): This should probably be accessible directly on [Block]
let ommers_hash =
reth_primitives::proofs::calculate_ommers_root(block.ommers.iter().map(|h| h.as_ref()));
if block.header.ommers_hash != ommers_hash {
return Err(Error::BodyOmmersHashDiff {
got: ommers_hash,
expected: block.header.ommers_hash,
})
}

// check transaction root
let transaction_root = crate::proofs::calculate_transaction_root(block.body.iter());
// Check transaction root
// TODO(onbjerg): This should probably be accessible directly on [Block]
let transaction_root = reth_primitives::proofs::calculate_transaction_root(block.body.iter());
if block.header.transactions_root != transaction_root {
return Err(Error::BodyTransactionRootDiff {
got: transaction_root,
expected: block.header.transactions_root,
})
}

// TODO transaction verification, Maybe make it configurable as in check only
// TODO: transaction verification,maybe make it configurable as in check only
// signatures/limits/types

// check if all transactions limit does not goes over block limit

// check receipts root
let receipts_root = crate::proofs::calculate_receipt_root(block.receipts.iter());
if block.header.receipts_root != receipts_root {
return Err(Error::BodyReceiptsRootDiff {
got: receipts_root,
expected: block.header.receipts_root,
})
// Things to probably check:
// - Chain ID
// - Base fee per gas (if applicable)
// - Max priority fee per gas (if applicable)

// TODO: Check if all transaction gas total does not go over block limit

// Check receipts root
// TODO(onbjerg): This should probably be accessible directly on [Block]
// NOTE(onbjerg): Pre-validation does not validate the receipts root since we do not have the
// receipts yet (this validation is before execution). Maybe this should not be in here?
if validate_receipts {
let receipts_root = reth_primitives::proofs::calculate_receipt_root(block.receipts.iter());
if block.header.receipts_root != receipts_root {
return Err(Error::BodyReceiptsRootDiff {
got: receipts_root,
expected: block.header.receipts_root,
})
}
}

Ok(())
Expand Down Expand Up @@ -284,7 +304,7 @@ pub fn full_validation<PROV: HeaderProvider>(
config: &Config,
) -> RethResult<()> {
validate_header_standalone(&block.header, config)?;
validate_block_standalone(block)?;
validate_block_standalone(block, true)?;
let parent = validate_block_regarding_chain(block, &provider)?;
validate_header_regarding_parent(&parent, &block.header, config)?;
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion crates/db/src/kv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl<E: EnvironmentKind> Database for Env<E> {
impl<E: EnvironmentKind> Env<E> {
/// Opens the database at the specified path with the given `EnvKind`.
///
/// It does not create the tables, for that call [`create_tables`].
/// It does not create the tables, for that call [`Env::create_tables`].
pub fn open(path: &Path, kind: EnvKind) -> Result<Env<E>, Error> {
let mode = match kind {
EnvKind::RO => Mode::ReadOnly,
Expand Down
3 changes: 3 additions & 0 deletions crates/interfaces/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ auto_impl = "1.0"
tokio = { version = "1.21.2", features = ["sync"] }
bytes = "1.2"

# TODO(onbjerg): We only need this for [BlockBody]
reth-eth-wire = { path = "../net/eth-wire" }

# codecs
serde = { version = "1.0.*", default-features = false }
postcard = { version = "1.0.2", features = ["alloc"] }
Expand Down
16 changes: 13 additions & 3 deletions crates/interfaces/src/consensus.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
use async_trait::async_trait;
use reth_primitives::{BlockHash, BlockNumber, SealedHeader, H256};
use reth_primitives::{BlockHash, BlockLocked, BlockNumber, SealedHeader, H256};
use tokio::sync::watch::Receiver;

/// Re-export forkchoice state
pub use reth_rpc_types::engine::ForkchoiceState;

/// Consensus is a protocol that chooses canonical chain.
/// We are checking validity of block header here.
#[async_trait]
#[auto_impl::auto_impl(&, Arc)]
pub trait Consensus: Send + Sync {
/// Get a receiver for the fork choice state
fn fork_choice_state(&self) -> Receiver<ForkchoiceState>;

/// Validate if header is correct and follows consensus specification
/// Validate if header is correct and follows consensus specification.
///
/// **This should not be called for the genesis block**.
fn validate_header(&self, header: &SealedHeader, parent: &SealedHeader) -> Result<(), Error>;

/// Validate a block disregarding world state, i.e. things that can be checked before sender
/// recovery and execution.
///
/// See the Yellow Paper sections 4.3.2 "Holistic Validity", 4.3.4 "Block Header Validity", and
/// 11.1 "Ommer Validation".
///
/// **This should not be called for the genesis block**.
fn pre_validate_block(&self, block: &BlockLocked) -> Result<(), Error>;
}

/// Consensus Errors
Expand Down
16 changes: 14 additions & 2 deletions crates/interfaces/src/db/codecs/scale.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::db::{models::accounts::AccountBeforeTx, Compress, Decompress, Error};
use crate::db::{
models::{accounts::AccountBeforeTx, StoredBlockBody},
Compress, Decompress, Error,
};
use parity_scale_codec::decode_from_bytes;
use reth_primitives::*;

Expand Down Expand Up @@ -53,7 +56,16 @@ impl ScaleValue for Vec<u8> {}
impl sealed::Sealed for Vec<u8> {}

impl_scale!(U256, H256, H160);
impl_scale!(Header, Account, Log, Receipt, TxType, StorageEntry, TransactionSigned);
impl_scale!(
Header,
Account,
Log,
Receipt,
TxType,
StorageEntry,
TransactionSigned,
StoredBlockBody
);
impl_scale!(AccountBeforeTx);

impl_scale_value!(u8, u32, u16, u64);
19 changes: 13 additions & 6 deletions crates/interfaces/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ pub trait Database: for<'a> DatabaseGAT<'a> {
/// Sealed trait which cannot be implemented by 3rd parties, exposed only for implementers
pub trait DbTxGAT<'a, __ImplicitBounds: Sealed = Bounds<&'a Self>>: Send + Sync {
/// Cursor GAT
type Cursor<T: Table>: DbCursorRO<'a, T>;
type Cursor<T: Table>: DbCursorRO<'a, T> + Send + Sync;
/// DupCursor GAT
type DupCursor<T: DupSort>: DbDupCursorRO<'a, T> + DbCursorRO<'a, T>;
type DupCursor<T: DupSort>: DbDupCursorRO<'a, T> + DbCursorRO<'a, T> + Send + Sync;
}

/// Implements the GAT method from:
Expand All @@ -85,12 +85,14 @@ pub trait DbTxGAT<'a, __ImplicitBounds: Sealed = Bounds<&'a Self>>: Send + Sync
/// Sealed trait which cannot be implemented by 3rd parties, exposed only for implementers
pub trait DbTxMutGAT<'a, __ImplicitBounds: Sealed = Bounds<&'a Self>>: Send + Sync {
/// Cursor GAT
type CursorMut<T: Table>: DbCursorRW<'a, T> + DbCursorRO<'a, T>;
type CursorMut<T: Table>: DbCursorRW<'a, T> + DbCursorRO<'a, T> + Send + Sync;
/// DupCursor GAT
type DupCursorMut<T: DupSort>: DbDupCursorRW<'a, T>
+ DbCursorRW<'a, T>
+ DbDupCursorRO<'a, T>
+ DbCursorRO<'a, T>;
+ DbCursorRO<'a, T>
+ Send
+ Sync;
}

/// Read only transaction
Expand Down Expand Up @@ -190,7 +192,9 @@ pub trait DbCursorRW<'tx, T: Table> {
/// exists in a table, and insert a new row if the specified value doesn't already exist
fn upsert(&mut self, key: T::Key, value: T::Value) -> Result<(), Error>;

/// Append value to next cursor item
/// Append value to next cursor item.
///
/// This is efficient for pre-sorted data. If the data is not pre-sorted, use [`insert`].
fn append(&mut self, key: T::Key, value: T::Value) -> Result<(), Error>;

/// Delete current value that cursor points to
Expand All @@ -201,7 +205,10 @@ pub trait DbCursorRW<'tx, T: Table> {
pub trait DbDupCursorRW<'tx, T: DupSort> {
/// Append value to next cursor item
fn delete_current_duplicates(&mut self) -> Result<(), Error>;
/// Append duplicate value

/// Append duplicate value.
///
/// This is efficient for pre-sorted data. If the data is not pre-sorted, use [`insert`].
fn append_dup(&mut self, key: T::Key, value: T::Value) -> Result<(), Error>;
}

Expand Down
22 changes: 19 additions & 3 deletions crates/interfaces/src/db/models/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,30 @@ use crate::{
impl_fixed_arbitrary,
};
use bytes::Bytes;
use reth_primitives::{BlockHash, BlockNumber, H256};
use reth_codecs::main_codec;
use reth_primitives::{BlockHash, BlockNumber, Header, TxNumber, H256};
use serde::{Deserialize, Serialize};

/// Total chain number of transactions. Key for [`CumulativeTxCount`].
pub type NumTransactions = u64;

/// Number of transactions in the block. Value for [`BlockBodies`].
pub type NumTxesInBlock = u16;
/// The storage representation of a block body.
///
/// A block body is stored as a pointer to the first transaction in the block (`base_tx_id`), a
/// count of how many transactions are in the block, and the headers of the block's uncles.
///
/// The [TxNumber]s for all the transactions in the block are `base_tx_id..(base_tx_id +
/// tx_amount)`.
#[derive(Debug)]
#[main_codec]
pub struct StoredBlockBody {
/// The ID of the first transaction in the block.
pub base_tx_id: TxNumber,
/// The number of transactions in the block.
pub tx_amount: u64,
/// The block headers of this block's uncles.
pub ommers: Vec<Header>,
}

/// Hash of the block header. Value for [`CanonicalHeaders`]
pub type HeaderHash = H256;
Expand Down
Loading