Skip to content

Commit

Permalink
feat: add key gen util and simple fcu validation test with custom all…
Browse files Browse the repository at this point in the history
…oc (#3842)
  • Loading branch information
Rjected authored Jul 18, 2023
1 parent b8587a2 commit 314e561
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 13 deletions.
57 changes: 55 additions & 2 deletions crates/consensus/beacon/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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::<NoopFullBlockClient>::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();
Expand Down
14 changes: 10 additions & 4 deletions crates/interfaces/src/test_utils/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<R: Rng>(rng: &mut R, count: usize) -> Vec<KeyPair> {
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.
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
17 changes: 11 additions & 6 deletions crates/primitives/src/transaction/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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.
Expand All @@ -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 {
Expand Down

0 comments on commit 314e561

Please sign in to comment.