feat: adds arbitratry to BlobTransaction and KZG_TRUSTED_SETUP (#4116)

Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
joshieDo
2023-08-09 13:30:44 +01:00
committed by GitHub
parent 6581961d3f
commit 31d1288d40
5 changed files with 4269 additions and 2 deletions

View File

@ -1,5 +1,5 @@
//! Implements the `GetPooledTransactions` and `PooledTransactions` message types.
use reth_codecs::derive_arbitrary;
use reth_codecs::{add_arbitrary_tests, derive_arbitrary};
use reth_primitives::{
kzg::{self, Blob, Bytes48, KzgProof, KzgSettings},
TransactionSigned, H256,
@ -9,6 +9,19 @@ use reth_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrap
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(any(test, feature = "arbitrary"))]
use proptest::{
arbitrary::{any as proptest_any, ParamsFor},
collection::vec as proptest_vec,
strategy::{BoxedStrategy, Strategy},
};
#[cfg(any(test, feature = "arbitrary"))]
use reth_primitives::{
constants::eip4844::{FIELD_ELEMENTS_PER_BLOB, KZG_TRUSTED_SETUP},
kzg::{KzgCommitment, BYTES_PER_BLOB, BYTES_PER_FIELD_ELEMENT},
};
/// A list of transaction hashes that the peer would like transaction bodies for.
#[derive_arbitrary(rlp)]
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper, Default)]
@ -59,7 +72,7 @@ impl From<PooledTransactions> for Vec<TransactionSigned> {
///
/// This is defined in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#networking) as an element
/// of a [PooledTransactions] response.
// TODO: derive_arbitrary
#[add_arbitrary_tests(rlp, 20)]
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default)]
pub struct BlobTransaction {
/// The transaction payload.
@ -94,6 +107,81 @@ impl BlobTransaction {
}
}
#[cfg(any(test, feature = "arbitrary"))]
impl<'a> arbitrary::Arbitrary<'a> for BlobTransaction {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let mut arr = [0u8; BYTES_PER_BLOB];
let blobs: Vec<Blob> = (0..u.int_in_range(1..=16)?)
.map(|_| {
arr = arbitrary::Arbitrary::arbitrary(u).unwrap();
// Ensure that the blob is canonical by ensuring that
// each field element contained in the blob is < BLS_MODULUS
for i in 0..(FIELD_ELEMENTS_PER_BLOB as usize) {
arr[i * BYTES_PER_FIELD_ELEMENT] = 0;
}
Blob::from(arr)
})
.collect();
Ok(generate_blob_transaction(blobs, TransactionSigned::arbitrary(u)?))
}
}
#[cfg(any(test, feature = "arbitrary"))]
impl proptest::arbitrary::Arbitrary for BlobTransaction {
type Parameters = ParamsFor<String>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
proptest_vec(proptest_vec(proptest_any::<u8>(), BYTES_PER_BLOB), 1..=5),
proptest_any::<TransactionSigned>(),
)
.prop_map(move |(blobs, tx)| {
let blobs = blobs
.into_iter()
.map(|mut blob| {
let mut arr = [0u8; BYTES_PER_BLOB];
// Ensure that the blob is canonical by ensuring that
// each field element contained in the blob is < BLS_MODULUS
for i in 0..(FIELD_ELEMENTS_PER_BLOB as usize) {
blob[i * BYTES_PER_FIELD_ELEMENT] = 0;
}
arr.copy_from_slice(blob.as_slice());
arr.into()
})
.collect();
generate_blob_transaction(blobs, tx)
})
.boxed()
}
type Strategy = BoxedStrategy<BlobTransaction>;
}
#[cfg(any(test, feature = "arbitrary"))]
fn generate_blob_transaction(blobs: Vec<Blob>, transaction: TransactionSigned) -> BlobTransaction {
let kzg_settings = KZG_TRUSTED_SETUP.clone();
let commitments: Vec<Bytes48> = blobs
.iter()
.map(|blob| KzgCommitment::blob_to_kzg_commitment(blob.clone(), &kzg_settings).unwrap())
.map(|commitment| commitment.to_bytes())
.collect();
let proofs: Vec<Bytes48> = blobs
.iter()
.zip(commitments.iter())
.map(|(blob, commitment)| {
KzgProof::compute_blob_kzg_proof(blob.clone(), *commitment, &kzg_settings).unwrap()
})
.map(|proof| proof.to_bytes())
.collect();
BlobTransaction { transaction, blobs, commitments, proofs }
}
#[cfg(test)]
mod test {
use crate::{message::RequestPair, GetPooledTransactions, PooledTransactions};