Skip to content

Commit

Permalink
feat: implement Arbitrary for transaction types (#1603)
Browse files Browse the repository at this point in the history
* feat: Arbitrary for transaction types

* fix
  • Loading branch information
klkvr authored Nov 1, 2024
1 parent 8399c86 commit 386e855
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 3 deletions.
8 changes: 6 additions & 2 deletions crates/consensus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ alloy-primitives = { workspace = true, features = ["rlp"] }
alloy-rlp.workspace = true
alloy-serde = { workspace = true, optional = true }

# k256
k256 = { workspace = true, features = ["ecdsa"], optional = true }

# kzg
c-kzg = { workspace = true, features = ["serde"], optional = true }

# arbitrary
arbitrary = { workspace = true, features = ["derive"], optional = true }
rand = { workspace = true, optional = true }

# serde
serde = { workspace = true, features = ["derive"], optional = true }
Expand Down Expand Up @@ -58,9 +62,9 @@ tokio = { workspace = true, features = ["macros"] }
[features]
default = ["std"]
std = ["alloy-eips/std", "c-kzg?/std"]
k256 = ["alloy-primitives/k256", "alloy-eips/k256"]
k256 = ["dep:k256", "alloy-primitives/k256", "alloy-eips/k256"]
kzg = ["dep:c-kzg", "alloy-eips/kzg", "std"]
arbitrary = ["std", "dep:arbitrary", "alloy-eips/arbitrary"]
arbitrary = ["std", "dep:rand", "dep:arbitrary", "alloy-eips/arbitrary"]
serde = [
"dep:serde",
"alloy-primitives/serde",
Expand Down
25 changes: 25 additions & 0 deletions crates/consensus/src/signed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,28 @@ impl<T: SignableTransaction<Signature>> Signed<T, Signature> {
self.signature.recover_address_from_prehash(&sighash)
}
}

#[cfg(all(any(test, feature = "arbitrary"), feature = "k256"))]
impl<'a, T: SignableTransaction<Signature> + arbitrary::Arbitrary<'a>> arbitrary::Arbitrary<'a>
for Signed<T, Signature>
{
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
use k256::{
ecdsa::{signature::hazmat::PrehashSigner, SigningKey},
NonZeroScalar,
};
use rand::{rngs::StdRng, SeedableRng};

let rng_seed = u.arbitrary::<[u8; 32]>()?;
let mut rand_gen = StdRng::from_seed(rng_seed);
let signing_key: SigningKey = NonZeroScalar::random(&mut rand_gen).into();

let tx = T::arbitrary(u)?;

let (recoverable_sig, recovery_id) =
signing_key.sign_prehash(tx.signature_hash().as_ref()).unwrap();
let signature: Signature = (recoverable_sig, recovery_id).into();

Ok(tx.into_signed(signature))
}
}
11 changes: 11 additions & 0 deletions crates/consensus/src/transaction/envelope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ impl TryFrom<u8> for TxType {
feature = "serde",
serde(into = "serde_from::TaggedTxEnvelope", from = "serde_from::MaybeTaggedTxEnvelope")
)]
#[cfg_attr(all(any(test, feature = "arbitrary"), feature = "k256"), derive(arbitrary::Arbitrary))]
#[doc(alias = "TransactionEnvelope")]
#[non_exhaustive]
pub enum TxEnvelope {
Expand Down Expand Up @@ -615,6 +616,7 @@ mod tests {
#[allow(unused_imports)]
use alloy_primitives::{b256, Bytes, TxKind};
use alloy_primitives::{hex, Address, Parity, Signature, U256};
use arbitrary::Arbitrary;
use std::{fs, path::PathBuf, str::FromStr, vec};

#[cfg(not(feature = "std"))]
Expand Down Expand Up @@ -1150,4 +1152,13 @@ mod tests {
)
);
}

#[test]
#[cfg(feature = "k256")]
fn test_arbitrary_envelope() {
let mut unstructured = arbitrary::Unstructured::new(b"arbitrary tx envelope");
let tx = TxEnvelope::arbitrary(&mut unstructured).unwrap();

assert!(tx.recover_signer().is_ok());
}
}
1 change: 1 addition & 0 deletions crates/consensus/src/transaction/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::{
into = "serde_from::TaggedTypedTransaction"
)
)]
#[cfg_attr(all(any(test, feature = "arbitrary"), feature = "k256"), derive(arbitrary::Arbitrary))]
#[doc(alias = "TypedTx", alias = "TxTyped", alias = "TransactionTyped")]
pub enum TypedTransaction {
/// Legacy transaction
Expand Down
2 changes: 1 addition & 1 deletion crates/rpc-types-eth/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub use alloy_consensus::{
/// Transaction object used in RPC
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
// #[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
#[cfg_attr(all(any(test, feature = "arbitrary"), feature = "k256"), derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
#[doc(alias = "Tx")]
pub struct Transaction<T = TxEnvelope> {
Expand Down

0 comments on commit 386e855

Please sign in to comment.