mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
add test_discard_blobs_on_blob_tx_eviction unit test (#6445)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -6970,6 +6970,7 @@ dependencies = [
|
|||||||
"revm",
|
"revm",
|
||||||
"schnellru",
|
"schnellru",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|||||||
@ -23,8 +23,11 @@ pub use legacy::TxLegacy;
|
|||||||
pub use meta::TransactionMeta;
|
pub use meta::TransactionMeta;
|
||||||
#[cfg(feature = "c-kzg")]
|
#[cfg(feature = "c-kzg")]
|
||||||
pub use pooled::{PooledTransactionsElement, PooledTransactionsElementEcRecovered};
|
pub use pooled::{PooledTransactionsElement, PooledTransactionsElementEcRecovered};
|
||||||
|
#[cfg(all(feature = "c-kzg", feature = "arbitrary"))]
|
||||||
|
pub use sidecar::generate_blob_sidecar;
|
||||||
#[cfg(feature = "c-kzg")]
|
#[cfg(feature = "c-kzg")]
|
||||||
pub use sidecar::{BlobTransaction, BlobTransactionSidecar, BlobTransactionValidationError};
|
pub use sidecar::{BlobTransaction, BlobTransactionSidecar, BlobTransactionValidationError};
|
||||||
|
|
||||||
pub use signature::Signature;
|
pub use signature::Signature;
|
||||||
pub use tx_type::{
|
pub use tx_type::{
|
||||||
TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID,
|
TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID,
|
||||||
|
|||||||
@ -482,8 +482,9 @@ impl proptest::arbitrary::Arbitrary for BlobTransactionSidecar {
|
|||||||
type Strategy = BoxedStrategy<BlobTransactionSidecar>;
|
type Strategy = BoxedStrategy<BlobTransactionSidecar>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates a [`BlobTransactionSidecar`] structure containing blobs, commitments, and proofs.
|
||||||
#[cfg(any(test, feature = "arbitrary"))]
|
#[cfg(any(test, feature = "arbitrary"))]
|
||||||
fn generate_blob_sidecar(blobs: Vec<Blob>) -> BlobTransactionSidecar {
|
pub fn generate_blob_sidecar(blobs: Vec<Blob>) -> BlobTransactionSidecar {
|
||||||
let kzg_settings = MAINNET_KZG_TRUSTED_SETUP.clone();
|
let kzg_settings = MAINNET_KZG_TRUSTED_SETUP.clone();
|
||||||
|
|
||||||
let commitments: Vec<Bytes48> = blobs
|
let commitments: Vec<Bytes48> = blobs
|
||||||
|
|||||||
@ -64,6 +64,7 @@ proptest.workspace = true
|
|||||||
criterion.workspace = true
|
criterion.workspace = true
|
||||||
assert_matches.workspace = true
|
assert_matches.workspace = true
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["serde"]
|
default = ["serde"]
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use reth_primitives::B256;
|
|||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
/// An in-memory blob store.
|
/// An in-memory blob store.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
pub struct InMemoryBlobStore {
|
pub struct InMemoryBlobStore {
|
||||||
inner: Arc<InMemoryBlobStoreInner>,
|
inner: Arc<InMemoryBlobStoreInner>,
|
||||||
}
|
}
|
||||||
@ -16,6 +16,12 @@ struct InMemoryBlobStoreInner {
|
|||||||
size_tracker: BlobStoreSize,
|
size_tracker: BlobStoreSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for InMemoryBlobStoreInner {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.store.read().eq(&other.store.read())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BlobStore for InMemoryBlobStore {
|
impl BlobStore for InMemoryBlobStore {
|
||||||
fn insert(&self, tx: B256, data: BlobTransactionSidecar) -> Result<(), BlobStoreError> {
|
fn insert(&self, tx: B256, data: BlobTransactionSidecar) -> Result<(), BlobStoreError> {
|
||||||
let mut store = self.inner.store.write();
|
let mut store = self.inner.store.write();
|
||||||
|
|||||||
@ -4,7 +4,10 @@ pub use disk::{DiskFileBlobStore, DiskFileBlobStoreConfig, OpenDiskFileBlobStore
|
|||||||
pub use mem::InMemoryBlobStore;
|
pub use mem::InMemoryBlobStore;
|
||||||
pub use noop::NoopBlobStore;
|
pub use noop::NoopBlobStore;
|
||||||
use reth_primitives::{BlobTransactionSidecar, B256};
|
use reth_primitives::{BlobTransactionSidecar, B256};
|
||||||
use std::{fmt, sync::atomic::AtomicUsize};
|
use std::{
|
||||||
|
fmt,
|
||||||
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
|
};
|
||||||
pub use tracker::{BlobStoreCanonTracker, BlobStoreUpdates};
|
pub use tracker::{BlobStoreCanonTracker, BlobStoreUpdates};
|
||||||
|
|
||||||
pub mod disk;
|
pub mod disk;
|
||||||
@ -85,32 +88,39 @@ pub(crate) struct BlobStoreSize {
|
|||||||
impl BlobStoreSize {
|
impl BlobStoreSize {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn add_size(&self, add: usize) {
|
pub(crate) fn add_size(&self, add: usize) {
|
||||||
self.data_size.fetch_add(add, std::sync::atomic::Ordering::Relaxed);
|
self.data_size.fetch_add(add, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn sub_size(&self, sub: usize) {
|
pub(crate) fn sub_size(&self, sub: usize) {
|
||||||
self.data_size.fetch_sub(sub, std::sync::atomic::Ordering::Relaxed);
|
self.data_size.fetch_sub(sub, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn update_len(&self, len: usize) {
|
pub(crate) fn update_len(&self, len: usize) {
|
||||||
self.num_blobs.store(len, std::sync::atomic::Ordering::Relaxed);
|
self.num_blobs.store(len, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn inc_len(&self, add: usize) {
|
pub(crate) fn inc_len(&self, add: usize) {
|
||||||
self.num_blobs.fetch_add(add, std::sync::atomic::Ordering::Relaxed);
|
self.num_blobs.fetch_add(add, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn data_size(&self) -> usize {
|
pub(crate) fn data_size(&self) -> usize {
|
||||||
self.data_size.load(std::sync::atomic::Ordering::Relaxed)
|
self.data_size.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn blobs_len(&self) -> usize {
|
pub(crate) fn blobs_len(&self) -> usize {
|
||||||
self.num_blobs.load(std::sync::atomic::Ordering::Relaxed)
|
self.num_blobs.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for BlobStoreSize {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.data_size.load(Ordering::Relaxed) == other.data_size.load(Ordering::Relaxed) &&
|
||||||
|
self.num_blobs.load(Ordering::Relaxed) == other.num_blobs.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1103,3 +1103,95 @@ impl<T: PoolTransaction> OnNewCanonicalStateOutcome<T> {
|
|||||||
FullPendingTransactionIter { kind, iter }
|
FullPendingTransactionIter { kind, iter }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
blobstore::{BlobStore, InMemoryBlobStore},
|
||||||
|
test_utils::{MockTransaction, TestPoolBuilder},
|
||||||
|
validate::ValidTransaction,
|
||||||
|
BlockInfo, PoolConfig, SubPoolLimit, TransactionOrigin, TransactionValidationOutcome, U256,
|
||||||
|
};
|
||||||
|
use reth_primitives::{kzg::Blob, transaction::generate_blob_sidecar};
|
||||||
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_discard_blobs_on_blob_tx_eviction() {
|
||||||
|
// Define the maximum limit for blobs in the sub-pool.
|
||||||
|
let blob_limit = SubPoolLimit::new(1000, usize::MAX);
|
||||||
|
|
||||||
|
// Create a test pool with default configuration and the specified blob limit.
|
||||||
|
let test_pool = &TestPoolBuilder::default()
|
||||||
|
.with_config(PoolConfig { blob_limit, ..Default::default() })
|
||||||
|
.pool;
|
||||||
|
|
||||||
|
// Set the block info for the pool, including a pending blob fee.
|
||||||
|
test_pool
|
||||||
|
.set_block_info(BlockInfo { pending_blob_fee: Some(10_000_000), ..Default::default() });
|
||||||
|
|
||||||
|
// Read the contents of the JSON file into a string.
|
||||||
|
let json_content = fs::read_to_string(
|
||||||
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test_data/blob1.json"),
|
||||||
|
)
|
||||||
|
.expect("Failed to read the blob data file");
|
||||||
|
|
||||||
|
// Parse the JSON contents into a serde_json::Value.
|
||||||
|
let json_value: serde_json::Value =
|
||||||
|
serde_json::from_str(&json_content).expect("Failed to deserialize JSON");
|
||||||
|
|
||||||
|
// Extract blob data from JSON and convert it to Blob.
|
||||||
|
let blobs: Vec<Blob> = vec![Blob::from_hex(
|
||||||
|
// Extract the "data" field from the JSON and parse it as a string.
|
||||||
|
json_value.get("data").unwrap().as_str().expect("Data is not a valid string"),
|
||||||
|
)
|
||||||
|
.unwrap()];
|
||||||
|
|
||||||
|
// Generate a BlobTransactionSidecar from the blobs.
|
||||||
|
let sidecar = generate_blob_sidecar(blobs.clone());
|
||||||
|
|
||||||
|
// Create an in-memory blob store.
|
||||||
|
let blob_store = InMemoryBlobStore::default();
|
||||||
|
|
||||||
|
// Loop to add transactions to the pool and test blob eviction.
|
||||||
|
for n in 0..blob_limit.max_txs + 10 {
|
||||||
|
// Create a mock transaction with the generated blob sidecar.
|
||||||
|
let mut tx = MockTransaction::eip4844_with_sidecar(sidecar.clone());
|
||||||
|
|
||||||
|
// Set non zero size
|
||||||
|
tx.set_size(1844674407370951);
|
||||||
|
|
||||||
|
// Insert the sidecar into the blob store if the current index is within the blob limit.
|
||||||
|
if n < blob_limit.max_txs {
|
||||||
|
blob_store.insert(tx.get_hash(), sidecar.clone()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the transaction to the pool with external origin and valid outcome.
|
||||||
|
test_pool
|
||||||
|
.add_transaction(
|
||||||
|
TransactionOrigin::External,
|
||||||
|
TransactionValidationOutcome::Valid {
|
||||||
|
balance: U256::from(1_000),
|
||||||
|
state_nonce: 0,
|
||||||
|
transaction: ValidTransaction::ValidWithSidecar {
|
||||||
|
transaction: tx,
|
||||||
|
sidecar: sidecar.clone(),
|
||||||
|
},
|
||||||
|
propagate: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Evict the worst transactions from the pool.
|
||||||
|
test_pool.discard_worst();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert that the size of the pool's blob component is equal to the maximum blob limit.
|
||||||
|
assert_eq!(test_pool.size().blob, blob_limit.max_txs);
|
||||||
|
|
||||||
|
// Assert that the size of the pool's blob_size component matches the expected value.
|
||||||
|
assert_eq!(test_pool.size().blob_size, 1844674407370951000);
|
||||||
|
|
||||||
|
// Assert that the pool's blob store matches the expected blob store.
|
||||||
|
assert_eq!(*test_pool.blob_store(), blob_store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -310,6 +310,16 @@ impl MockTransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a new EIP4844 transaction with a provided sidecar
|
||||||
|
pub fn eip4844_with_sidecar(sidecar: BlobTransactionSidecar) -> Self {
|
||||||
|
let mut transaction = Self::eip4844();
|
||||||
|
if let MockTransaction::Eip4844 { sidecar: ref mut existing_sidecar, .. } = &mut transaction
|
||||||
|
{
|
||||||
|
*existing_sidecar = sidecar;
|
||||||
|
}
|
||||||
|
transaction
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a new EIP2930 transaction with random address and hash and empty values
|
/// Returns a new EIP2930 transaction with random address and hash and empty values
|
||||||
pub fn eip2930() -> Self {
|
pub fn eip2930() -> Self {
|
||||||
MockTransaction::Eip2930 {
|
MockTransaction::Eip2930 {
|
||||||
|
|||||||
@ -1140,7 +1140,7 @@ impl PoolSize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the current status of the pool.
|
/// Represents the current status of the pool.
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
pub struct BlockInfo {
|
pub struct BlockInfo {
|
||||||
/// Hash for the currently tracked block.
|
/// Hash for the currently tracked block.
|
||||||
pub last_seen_block_hash: B256,
|
pub last_seen_block_hash: B256,
|
||||||
|
|||||||
4
crates/transaction-pool/test_data/blob1.json
Normal file
4
crates/transaction-pool/test_data/blob1.json
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user