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

1
Cargo.lock generated
View File

@@ -5831,6 +5831,7 @@ dependencies = [
"serde_with",
"strum 0.25.0",
"sucds",
"tempfile",
"test-fuzz",
"thiserror",
"tiny-keccak",

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};

View File

@@ -60,6 +60,7 @@ impl-serde = "0.4.0"
once_cell = "1.17.0"
zstd = { version = "0.12", features = ["experimental"] }
paste = "1.0"
tempfile = "3.3"
# proof related
triehash = "0.8"

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,9 @@
//! [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#parameters) protocol constants for shard Blob Transactions.
use crate::kzg::KzgSettings;
use once_cell::sync::Lazy;
use std::{io::Write, sync::Arc};
/// Size a single field element in bytes.
pub const FIELD_ELEMENT_BYTES: u64 = 32;
@@ -23,3 +27,13 @@ pub const TARGET_BLOBS_PER_BLOCK: u64 = TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER
/// Used to determine the price for next data blob
pub const BLOB_GASPRICE_UPDATE_FRACTION: u64 = 3_338_477u64; // 3338477
/// KZG Trusted setup raw
const TRUSTED_SETUP_RAW: &str = include_str!("../../res/eip4844/trusted_setup.txt");
/// KZG trusted setup
pub static KZG_TRUSTED_SETUP: Lazy<Arc<KzgSettings>> = Lazy::new(|| {
let mut file = tempfile::NamedTempFile::new().unwrap();
file.write_all(TRUSTED_SETUP_RAW.as_bytes()).unwrap();
Arc::new(KzgSettings::load_trusted_setup_file(file.path().into()).unwrap())
});