diff --git a/crates/consensus/beacon/src/engine/mod.rs b/crates/consensus/beacon/src/engine/mod.rs index 4e1e6668261b..8be81f2bbdce 100644 --- a/crates/consensus/beacon/src/engine/mod.rs +++ b/crates/consensus/beacon/src/engine/mod.rs @@ -2538,8 +2538,11 @@ mod tests { mod new_payload { use super::*; - use reth_interfaces::test_utils::{generators, generators::random_block}; - use reth_primitives::{Hardfork, U256}; + use reth_interfaces::test_utils::{ + generators, + generators::{generate_keys, random_block}, + }; + use reth_primitives::{public_key_to_address, Genesis, GenesisAccount, Hardfork, U256}; use reth_provider::test_utils::blocks::BlockChainTestData; #[tokio::test] @@ -2629,6 +2632,56 @@ mod tests { assert_matches!(engine_rx.try_recv(), Err(TryRecvError::Empty)); } + #[tokio::test] + async fn simple_validate_block() { + let mut rng = generators::rng(); + let genesis_keys = generate_keys(&mut rng, 16); + let amount = 1000000000000000000u64; + let alloc = genesis_keys.iter().map(|pair| { + ( + public_key_to_address(pair.public_key()), + GenesisAccount::default().with_balance(U256::from(amount)), + ) + }); + + let genesis = Genesis::default().extend_accounts(alloc); + + let chain_spec = Arc::new( + ChainSpecBuilder::default() + .chain(MAINNET.chain) + .genesis(genesis) + .shanghai_activated() + .build(), + ); + + let (consensus_engine, env) = + TestConsensusEngineBuilder::::new(chain_spec.clone()).build(); + + let genesis = + SealedBlock { header: chain_spec.sealed_genesis_header(), ..Default::default() }; + let block1 = random_block(&mut rng, 1, Some(chain_spec.genesis_hash()), None, Some(0)); + + // TODO: add transactions that transfer from the alloc accounts, generating the new + // block tx and state root + + insert_blocks(env.db.as_ref(), chain_spec.clone(), [&genesis, &block1].into_iter()); + + let mut engine_rx = spawn_consensus_engine(consensus_engine); + + // Send forkchoice + let res = env + .send_forkchoice_updated(ForkchoiceState { + head_block_hash: block1.hash, + finalized_block_hash: block1.hash, + ..Default::default() + }) + .await; + let expected_result = PayloadStatus::from_status(PayloadStatusEnum::Valid) + .with_latest_valid_hash(block1.hash); + assert_matches!(res, Ok(ForkchoiceUpdated { payload_status, .. }) => assert_eq!(payload_status, expected_result)); + assert_matches!(engine_rx.try_recv(), Err(TryRecvError::Empty)); + } + #[tokio::test] async fn payload_parent_unknown() { let mut rng = generators::rng(); diff --git a/crates/interfaces/src/test_utils/generators.rs b/crates/interfaces/src/test_utils/generators.rs index dfcdf39a0c51..fbbdf42a2129 100644 --- a/crates/interfaces/src/test_utils/generators.rs +++ b/crates/interfaces/src/test_utils/generators.rs @@ -104,6 +104,12 @@ pub fn sign_tx_with_key_pair(key_pair: KeyPair, tx: Transaction) -> TransactionS TransactionSigned::from_transaction_and_signature(tx, signature) } +/// Generates a set of [KeyPair]s based on the desired count. +pub fn generate_keys(rng: &mut R, count: usize) -> Vec { + let secp = Secp256k1::new(); + (0..count).map(|_| KeyPair::new(&secp, rng)).collect() +} + /// Generate a random block filled with signed transactions (generated using /// [random_signed_tx]). If no transaction count is provided, the number of transactions /// will be random, otherwise the provided count will be used. @@ -363,7 +369,9 @@ mod test { use super::*; use hex_literal::hex; - use reth_primitives::{keccak256, AccessList, Address, TransactionKind, TxEip1559}; + use reth_primitives::{ + keccak256, public_key_to_address, AccessList, Address, TransactionKind, TxEip1559, + }; use secp256k1::KeyPair; #[test] @@ -393,9 +401,7 @@ mod test { let signed = TransactionSigned::from_transaction_and_signature(tx.clone(), signature); let recovered = signed.recover_signer().unwrap(); - let public_key_hash = keccak256(&key_pair.public_key().serialize_uncompressed()[1..]); - let expected = Address::from_slice(&public_key_hash[12..]); - + let expected = public_key_to_address(key_pair.public_key()); assert_eq!(recovered, expected); } } diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 753c1435fe73..0248f008a24c 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -84,7 +84,7 @@ pub use revm_primitives::JumpMap; pub use serde_helper::JsonU256; pub use storage::StorageEntry; pub use transaction::{ - util::secp256k1::{recover_signer, sign_message}, + util::secp256k1::{public_key_to_address, recover_signer, sign_message}, AccessList, AccessListItem, AccessListWithGasUsed, FromRecoveredTransaction, IntoRecoveredTransaction, InvalidTransactionError, Signature, Transaction, TransactionKind, TransactionMeta, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, diff --git a/crates/primitives/src/transaction/util.rs b/crates/primitives/src/transaction/util.rs index f67e152b5826..da3fb63494c5 100644 --- a/crates/primitives/src/transaction/util.rs +++ b/crates/primitives/src/transaction/util.rs @@ -6,7 +6,7 @@ pub(crate) mod secp256k1 { pub(crate) use ::secp256k1::Error; use ::secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, - Message, SecretKey, SECP256K1, + Message, PublicKey, SecretKey, SECP256K1, }; use revm_primitives::{B256, U256}; @@ -18,11 +18,7 @@ pub(crate) mod secp256k1 { RecoverableSignature::from_compact(&sig[0..64], RecoveryId::from_i32(sig[64] as i32)?)?; let public = SECP256K1.recover_ecdsa(&Message::from_slice(&msg[..32])?, &sig)?; - - // strip out the first byte because that should be the SECP256K1_TAG_PUBKEY_UNCOMPRESSED - // tag returned by libsecp's uncompressed pubkey serialization - let hash = keccak256(&public.serialize_uncompressed()[1..]); - Ok(Address::from_slice(&hash[12..])) + Ok(public_key_to_address(public)) } /// Signs message with the given secret key. @@ -39,6 +35,15 @@ pub(crate) mod secp256k1 { }; Ok(signature) } + + /// Converts a public key into an ethereum address by hashing the encoded public key with + /// keccak256. + pub fn public_key_to_address(public: PublicKey) -> Address { + // strip out the first byte because that should be the SECP256K1_TAG_PUBKEY_UNCOMPRESSED + // tag returned by libsecp's uncompressed pubkey serialization + let hash = keccak256(&public.serialize_uncompressed()[1..]); + Address::from_slice(&hash[12..]) + } } #[cfg(test)] mod tests {