Skip to content

Commit

Permalink
Add test for engine_getBlobsV1 concurrency (#7581)
Browse files Browse the repository at this point in the history
Co-authored-by: Lukasz Rozmej <lukasz.rozmej@gmail.com>
  • Loading branch information
2 people authored and rjnrohit committed Oct 10, 2024
1 parent 2d9aa6a commit 3011df5
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 5 deletions.
60 changes: 60 additions & 0 deletions src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.Blobs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
using Nethermind.Evm;
using Nethermind.Evm.Tracing.GethStyle.Custom.JavaScript;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.TxPool.Collections;
Expand Down Expand Up @@ -679,6 +680,65 @@ public void should_index_blobs_when_adding_txs([Values(true, false)] bool isPers
}
}

[Test]
[Repeat(3)]
public void should_handle_indexing_blobs_when_adding_txs_in_parallel([Values(true, false)] bool isPersistentStorage)
{
const int txsPerSender = 10;
int poolSize = TestItem.PrivateKeys.Length * txsPerSender;
TxPoolConfig txPoolConfig = new()
{
BlobsSupport = isPersistentStorage ? BlobsSupportMode.Storage : BlobsSupportMode.InMemory,
PersistentBlobStorageSize = isPersistentStorage ? poolSize : 0,
InMemoryBlobPoolSize = isPersistentStorage ? 0 : poolSize
};

IComparer<Transaction> comparer = new TransactionComparerProvider(_specProvider, _blockTree).GetDefaultComparer();

BlobTxDistinctSortedPool blobPool = isPersistentStorage
? new PersistentBlobTxDistinctSortedPool(new BlobTxStorage(), txPoolConfig, comparer, LimboLogs.Instance)
: new BlobTxDistinctSortedPool(txPoolConfig.InMemoryBlobPoolSize, comparer, LimboLogs.Instance);

byte[] expectedBlobVersionedHash = null;

foreach (PrivateKey privateKey in TestItem.PrivateKeys)
{
EnsureSenderBalance(privateKey.Address, UInt256.MaxValue);
}

// adding, getting and removing txs in parallel
Parallel.ForEach(TestItem.PrivateKeys, privateKey =>
{
for (int i = 0; i < txsPerSender; i++)
{
Transaction tx = Build.A.Transaction
.WithNonce((UInt256)i)
.WithShardBlobTxTypeAndFields()
.WithMaxFeePerGas(1.GWei())
.WithMaxPriorityFeePerGas(1.GWei())
.WithMaxFeePerBlobGas(1000.Wei())
.SignedAndResolved(_ethereumEcdsa, privateKey).TestObject;

expectedBlobVersionedHash ??= tx.BlobVersionedHashes[0]!;

blobPool.TryInsert(tx.Hash, tx, out _).Should().BeTrue();

for (int j = 0; j < 100; j++)
{
blobPool.TryGetBlobAndProof(expectedBlobVersionedHash.ToBytes(), out _, out _).Should().BeTrue();
}

// removing 50% of txs
if (i % 2 == 0) blobPool.TryRemove(tx.Hash, out _).Should().BeTrue();
}
});

// we expect index to have 1 key with poolSize/2 values (50% of txs were removed)
blobPool.BlobIndex.Count.Should().Be(1);
blobPool.BlobIndex.TryGetValue(expectedBlobVersionedHash, out List<Hash256> values).Should().BeTrue();
values.Count.Should().Be(poolSize / 2);
}

private Transaction GetTx(PrivateKey sender)
{
return Build.A.Transaction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,5 @@ private void RemoveFromBlobIndex(Transaction blobTx)
/// For tests only - to test sorting
/// </summary>
internal void TryGetBlobTxSortingEquivalent(Hash256 hash, out Transaction? lightBlobTx)
=> base.TryGetValue(hash, out lightBlobTx);
=> base.TryGetValueNonLocked(hash, out lightBlobTx);
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ protected override bool InsertCore(ValueHash256 hash, Transaction fullBlobTx, Ad
return false;
}

public override bool TryGetValue(ValueHash256 hash, [NotNullWhen(true)] out Transaction? fullBlobTx)
protected override bool TryGetValueNonLocked(ValueHash256 hash, [NotNullWhen(true)] out Transaction? fullBlobTx)
{
// Firstly check if tx is present in in-memory collection of light blob txs (without actual blobs).
// If not, just return false
if (base.TryGetValue(hash, out Transaction? lightTx))
if (base.TryGetValueNonLocked(hash, out Transaction? lightTx))
{
// tx is present in light collection. Try to get full blob tx from cache
if (_blobTxCache.TryGet(hash, out fullBlobTx))
Expand Down
4 changes: 2 additions & 2 deletions src/Nethermind/Nethermind.TxPool/Collections/SortedPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,14 +336,14 @@ public bool ContainsKey(TKey key)
/// <param name="key">Key to be returned.</param>
/// <param name="value">Returned element or null.</param>
/// <returns>If element retrieval succeeded. True if element was present in pool.</returns>
public virtual bool TryGetValue(TKey key, [NotNullWhen(true)] out TValue? value)
public bool TryGetValue(TKey key, [NotNullWhen(true)] out TValue? value)
{
using var lockRelease = Lock.Acquire();

return TryGetValueNonLocked(key, out value);
}

protected bool TryGetValueNonLocked(TKey key, [NotNullWhen(true)] out TValue? value) => _cacheMap.TryGetValue(key, out value) && value is not null;
protected virtual bool TryGetValueNonLocked(TKey key, [NotNullWhen(true)] out TValue? value) => _cacheMap.TryGetValue(key, out value) && value is not null;

/// <summary>
/// Tries to insert element.
Expand Down

0 comments on commit 3011df5

Please sign in to comment.