diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ee79fe8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,31 @@ +# Signet Node Components + +## Commands + +- `cargo +nightly fmt` - format +- `cargo clippy -p --all-features --all-targets` - lint with features +- `cargo clippy -p --no-default-features --all-targets` - lint without +- `cargo t -p ` - test specific crate + +Pre-commit: clippy (both feature sets where applicable) + fmt. Never use `cargo check/build`. + +## Style + +- Functional combinators over imperative control flow +- `let else` for early returns, avoid nesting +- No glob imports; group imports from same crate; no blank lines between imports +- Private by default, `pub(crate)` for internal, `pub` for API only; never `pub(super)` +- `thiserror` for library errors, `eyre` for apps, never `anyhow` +- `tracing` for instrumentation: instrument work items not long-lived tasks; `skip(self)` on methods +- Builders for structs with >4 fields or multiple same-type fields +- Tests: fail fast with `unwrap()`, never return `Result`; unit tests in `mod tests` +- Rustdoc on all public items with usage examples; hide scaffolding with `#` +- `// SAFETY:` comments on all unsafe blocks + +## Workspace Crates + +All crates use `signet-` prefix. Features exist in: +- `signet-blobber`: `test-utils` +- `signet-node-config`: `test_utils` + +Other crates (`signet-node`, `signet-node-types`, `signet-rpc`, `signet-db`, `signet-block-processor`, `signet-genesis`, `signet-node-tests`) have no feature flags — lint with `--all-features` only. diff --git a/crates/blobber/src/shim.rs b/crates/blobber/src/shim.rs index 0c56d90..a7ac340 100644 --- a/crates/blobber/src/shim.rs +++ b/crates/blobber/src/shim.rs @@ -59,8 +59,10 @@ impl From for RecoveredBlockShim { } impl HasTxns for RecoveredBlockShim { - fn transactions(&self) -> &[signet_types::primitives::TransactionSigned] { - &self.block.sealed_block().body().transactions + fn transactions( + &self, + ) -> impl ExactSizeIterator { + self.block.sealed_block().body().transactions.iter() } } diff --git a/crates/db/src/convert.rs b/crates/db/src/convert.rs index 7737b84..53f2ccc 100644 --- a/crates/db/src/convert.rs +++ b/crates/db/src/convert.rs @@ -104,6 +104,6 @@ impl DataCompat for reth::primitives::Se impl DataCompat for signet_types::primitives::SealedHeader { fn convert(self) -> reth::primitives::SealedHeader { - reth::primitives::SealedHeader::new_unhashed(self.header().to_owned()) + reth::primitives::SealedHeader::new_unhashed(self.clone_inner()) } } diff --git a/crates/db/src/journal/trait.rs b/crates/db/src/journal/trait.rs index 014714f..1187e55 100644 --- a/crates/db/src/journal/trait.rs +++ b/crates/db/src/journal/trait.rs @@ -1,9 +1,9 @@ use crate::RuWriter; -use alloy::consensus::{BlockHeader, Header}; +use alloy::consensus::BlockHeader; use reth::{providers::ProviderResult, revm::db::BundleState}; use signet_evm::{BlockResult, ExecutionOutcome}; use signet_journal::HostJournal; -use signet_types::primitives::{RecoveredBlock, SealedBlock, SealedHeader, TransactionSigned}; +use signet_types::primitives::{SealedBlock, SealedHeader}; /// A database that can be updated with journals. pub trait JournalDb: RuWriter { @@ -31,13 +31,8 @@ pub trait JournalDb: RuWriter { let bundle_state: BundleState = bsi.into(); let execution_outcome = ExecutionOutcome::new(bundle_state, vec![], header.number()); - let block: SealedBlock = - SealedBlock { header: SealedHeader::new(header), body: Default::default() }; - let block_result = BlockResult { - sealed_block: RecoveredBlock::new(block, vec![]), - execution_outcome, - host_height, - }; + let block = SealedBlock::new(SealedHeader::new(header), vec![]); + let block_result = BlockResult { sealed_block: block, execution_outcome, host_height }; self.append_host_block( None, diff --git a/crates/db/src/provider.rs b/crates/db/src/provider.rs index f2cd7da..21daf90 100644 --- a/crates/db/src/provider.rs +++ b/crates/db/src/provider.rs @@ -163,8 +163,8 @@ where // Put journal hash into the DB self.tx_ref().put::(block_number, journal_hash)?; - let block_hash = block.block.header.hash(); - let block_header = block.block.header.header(); + let block_hash = block.header.seal(); + let block_header = block.header.inner(); self.static_file_provider() .get_writer(block_number, StaticFileSegment::Headers)? @@ -179,14 +179,14 @@ where .map(|(n, _)| n + 1) .unwrap_or_default(); let first_tx_num = next_tx_num; - let tx_count = block.block.body.transactions.len() as u64; + let tx_count = block.transactions.len() as u64; - for (sender, transaction) in block.senders.iter().zip(block.block.body.transactions()) { + for (sender, transaction) in block.senders().zip(block.transactions()) { let hash = *transaction.hash(); debug_assert_ne!(hash, B256::ZERO, "transaction hash is zero"); if self.prune_modes_ref().sender_recovery.as_ref().is_none_or(|m| !m.is_full()) { - self.tx_ref().put::(next_tx_num, *sender)?; + self.tx_ref().put::(next_tx_num, sender)?; } if self.prune_modes_ref().transaction_lookup.is_none_or(|m| !m.is_full()) { @@ -231,7 +231,7 @@ where // Increment block on static file header tx_writer.increment_block(block_number)?; - let tx_count = block.block.body.transactions.len() as u64; + let tx_count = block.transactions.len() as u64; let block_indices = StoredBlockBodyIndices { first_tx_num: next_tx_num, tx_count }; // insert block meta @@ -243,7 +243,7 @@ where } // Write transactions - for transaction in block.block.body.transactions() { + for transaction in block.transactions() { tx_writer.append_transaction(next_tx_num, transaction)?; // Increment transaction id for each transaction diff --git a/crates/db/tests/db.rs b/crates/db/tests/db.rs index 6d4f769..e8123f9 100644 --- a/crates/db/tests/db.rs +++ b/crates/db/tests/db.rs @@ -2,14 +2,14 @@ mod test_common; use alloy::{ - consensus::{BlockBody, BlockHeader, Signed, TxEip1559, TxEnvelope}, + consensus::{BlockHeader, Signed, TxEip1559, TxEnvelope}, primitives::{Address, B256, U256}, signers::Signature, }; use reth::providers::{BlockNumReader, BlockReader}; use signet_constants::test_utils::{DEPLOY_HEIGHT, RU_CHAIN_ID}; use signet_db::RuWriter; -use signet_types::primitives::{RecoveredBlock, SealedBlock, SealedHeader, TransactionSigned}; +use signet_types::primitives::{SealedBlock, SealedHeader, TransactionSigned}; use signet_zenith::Zenith; #[test] @@ -35,25 +35,19 @@ fn test_insert_signet_block() { blockDataHash: B256::repeat_byte(0x22), }); - let block = RecoveredBlock { - block: SealedBlock { - header: SealedHeader::new(alloy::consensus::Header::default()), - body: BlockBody { - transactions: std::iter::repeat_n( - TxEnvelope::Eip1559(Signed::new_unhashed( - TxEip1559::default(), - Signature::test_signature(), - )) - .into(), - 10, - ) - .collect(), - ommers: vec![], - withdrawals: None, - }, - }, - senders: std::iter::repeat_n(Address::repeat_byte(0x33), 10).collect(), - }; + let transactions: Vec = std::iter::repeat_n( + TxEnvelope::Eip1559(Signed::new_unhashed( + TxEip1559::default(), + Signature::test_signature(), + )) + .into(), + 10, + ) + .collect(); + let senders: Vec
= std::iter::repeat_n(Address::repeat_byte(0x33), 10).collect(); + let sealed = + SealedBlock::new(SealedHeader::new(alloy::consensus::Header::default()), transactions); + let block = sealed.recover_unchecked(senders); writer.insert_signet_block(header, &block, journal_hash).unwrap(); writer.commit().unwrap(); @@ -74,8 +68,8 @@ fn test_insert_signet_block() { .first() .cloned() .unwrap(); - assert_eq!(loaded_block.header(), block.block.header.header()); - assert_eq!(loaded_block.body().transactions.len(), block.block.body.transactions.len()); + assert_eq!(loaded_block.header(), block.header.inner()); + assert_eq!(loaded_block.body().transactions.len(), block.transactions.len()); // Check that the ZenithHeader can be loaded back let loaded_header = reader.get_signet_header(block.number()).unwrap(); @@ -111,13 +105,10 @@ fn test_transaction_hash_indexing() { let expected_hashes: Vec = transactions.iter().map(|tx: &TransactionSigned| *tx.hash()).collect(); - let block = RecoveredBlock { - block: SealedBlock { - header: SealedHeader::new(alloy::consensus::Header::default()), - body: BlockBody { transactions, ommers: vec![], withdrawals: None }, - }, - senders: std::iter::repeat_n(Address::repeat_byte(0x33), 5).collect(), - }; + let senders: Vec
= std::iter::repeat_n(Address::repeat_byte(0x33), 5).collect(); + let sealed = + SealedBlock::new(SealedHeader::new(alloy::consensus::Header::default()), transactions); + let block = sealed.recover_unchecked(senders); writer.insert_signet_block(header, &block, journal_hash).unwrap(); writer.commit().unwrap(); diff --git a/crates/node-tests/src/convert.rs b/crates/node-tests/src/convert.rs index 8b6977c..8d6e640 100644 --- a/crates/node-tests/src/convert.rs +++ b/crates/node-tests/src/convert.rs @@ -46,9 +46,14 @@ impl ToRethPrimitive for SealedBlock { type RethPrimitive = reth::primitives::SealedBlock; fn to_reth(self) -> Self::RethPrimitive { - let (hash, header) = self.header.split(); + let (header, hash) = self.header.into_parts(); + let body = alloy::consensus::BlockBody { + transactions: self.transactions, + ommers: vec![], + withdrawals: None, + }; reth::primitives::SealedBlock::new_unchecked( - reth::primitives::Block::new(header, self.body), + reth::primitives::Block::new(header, body), hash, ) } @@ -58,8 +63,21 @@ impl ToRethPrimitive for RecoveredBlock { type RethPrimitive = reth::primitives::RecoveredBlock; fn to_reth(self) -> Self::RethPrimitive { - let hash = self.block.header.hash(); - reth::primitives::RecoveredBlock::new(self.block.to_reth().into_block(), self.senders, hash) + let (header, hash) = self.header.into_parts(); + let (senders, transactions): (Vec<_>, Vec<_>) = self + .transactions + .into_iter() + .map(|r| { + let (tx, sender) = r.into_parts(); + (sender, tx) + }) + .unzip(); + let body = alloy::consensus::BlockBody { transactions, ommers: vec![], withdrawals: None }; + reth::primitives::RecoveredBlock::new( + reth::primitives::Block::new(header, body), + senders, + hash, + ) } }