Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Perf/faster block load for receipt #5708

Merged
merged 24 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Nethermind/Ethereum.Basic.Test/TransactionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void Test(TransactionTest test)
Assert.That(decodedUnsigned.Value, Is.EqualTo(test.Value), "value");
Assert.That(decodedUnsigned.GasPrice, Is.EqualTo(test.GasPrice), "gasPrice");
Assert.That(decodedUnsigned.GasLimit, Is.EqualTo(test.StartGas), "gasLimit");
Assert.That(decodedUnsigned.Data, Is.EqualTo(test.Data), "data");
Assert.That(decodedUnsigned.Data.AsArray(), Is.EqualTo(test.Data), "data");
Assert.That(decodedUnsigned.To, Is.EqualTo(test.To), "to");
Assert.That(decodedUnsigned.Nonce, Is.EqualTo(test.Nonce), "nonce");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ private void RunTest(TransactionTest test, IReleaseSpec spec)
if (validTest != null)
{
Assert.That(transaction.Value, Is.EqualTo(validTest.Value), "value");
Assert.That(transaction.Data, Is.EqualTo(validTest.Data), "data");
Assert.That(transaction.Data.AsArray(), Is.EqualTo(validTest.Data), "data");
Assert.That(transaction.GasLimit, Is.EqualTo(validTest.GasLimit.ToInt64(null)), "gasLimit");
Assert.That(transaction.GasPrice, Is.EqualTo(validTest.GasPrice), "gasPrice");
Assert.That(transaction.Nonce, Is.EqualTo(validTest.Nonce), "nonce");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ public void Should_generate_malicious_transaction()
{
ReportingValidatorContract contract = new(AbiEncoder.Instance, new Address("0x1000000000000000000000000000000000000001"), Substitute.For<ISigner>());
Transaction transaction = contract.ReportMalicious(new Address("0x75df42383afe6bf5194aa8fa0e9b3d5f9e869441"), 10, new byte[0]);
transaction.Data.ToHexString().Should().Be("c476dd4000000000000000000000000075df42383afe6bf5194aa8fa0e9b3d5f9e869441000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000");
transaction.Data.AsArray().ToHexString().Should().Be("c476dd4000000000000000000000000075df42383afe6bf5194aa8fa0e9b3d5f9e869441000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000");
}

[Test]
public void Should_generate_benign_transaction()
{
ReportingValidatorContract contract = new(AbiEncoder.Instance, new Address("0x1000000000000000000000000000000000000001"), Substitute.For<ISigner>());
Transaction transaction = contract.ReportBenign(new Address("0x75df42383afe6bf5194aa8fa0e9b3d5f9e869441"), 10);
transaction.Data.ToHexString().Should().Be("d69f13bb00000000000000000000000075df42383afe6bf5194aa8fa0e9b3d5f9e869441000000000000000000000000000000000000000000000000000000000000000a");
transaction.Data.AsArray().ToHexString().Should().Be("d69f13bb00000000000000000000000075df42383afe6bf5194aa8fa0e9b3d5f9e869441000000000000000000000000000000000000000000000000000000000000000a");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Nethermind.Consensus.AuRa.Contracts;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Test;
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
using Nethermind.Evm;
Expand Down Expand Up @@ -84,11 +85,11 @@ public void finalize_change_should_call_correct_transaction()
Arg.Is<Transaction>(t => IsEquivalentTo(expectation, t)), _block.Header, Arg.Any<ITxTracer>());
}

private static bool IsEquivalentTo(object expected, object item)
private static bool IsEquivalentTo(Transaction expected, Transaction item)
{
try
{
item.Should().BeEquivalentTo(expected);
item.EqualToTransaction(expected);
return true;
}
catch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Nethermind.Consensus.AuRa.Rewards;
using Nethermind.Consensus.Rewards;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Core.Test;
using Nethermind.Specs.ChainSpecStyle;
using Nethermind.Core.Test.Builders;
Expand Down Expand Up @@ -213,7 +214,7 @@ private void SetupBlockRewards(IDictionary<Address, BlockReward[]> rewards)
private bool CheckTransaction(Transaction t, ICollection<Address> addresses, byte[] transactionData) =>
t.SenderAddress == Address.SystemUser
&& (t.To == _auraParameters.BlockRewardContractAddress || addresses.Contains(t.To))
&& t.Data == transactionData;
&& t.Data.AsArray() == transactionData;

private byte[] SetupAbiAddresses(params BlockReward[] rewards)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ private byte[] SetupAbiAddresses(Address[] addresses)

private bool CheckTransaction(Transaction t, (Address Sender, byte[] TransactionData) transactionInfo)
{
return t.SenderAddress == transactionInfo.Sender && t.To == _contractAddress && t.Data == transactionInfo.TransactionData;
return t.SenderAddress == transactionInfo.Sender && t.To == _contractAddress && t.Data.AsArray() == transactionInfo.TransactionData;
}

public class ConsecutiveInitiateChangeTestParameters
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Runtime.InteropServices.JavaScript;
using FluentAssertions;
using Nethermind.Blockchain.Blocks;
using Nethermind.Core;
using Nethermind.Core.Test;
using Nethermind.Core.Test.Builders;
using Nethermind.Serialization.Rlp;
using Nethermind.Specs;
using NUnit.Framework;

namespace Nethermind.Blockchain.Test.Blocks;
Expand Down Expand Up @@ -60,4 +64,29 @@ public void Test_when_cached_does_not_touch_db_on_next_get()
retrieved = store.Get(block.Hash, true);
retrieved.Should().BeEquivalentTo(block);
}

[Test]
public void Test_getReceiptRecoveryBlock_produce_same_transaction_as_normal_get()
{
TestMemDb db = new TestMemDb();
BlockStore store = new BlockStore(db);

Block block = Build.A.Block.WithNumber(1)
.WithTransactions(3, MainnetSpecProvider.Instance)
.TestObject;

store.Insert(block);

ReceiptRecoveryBlock retrieved = store.GetReceiptRecoveryBlock(block.Hash).Value;
retrieved.Should().NotBeNull();

retrieved.Header.Should().BeEquivalentTo(block.Header);
retrieved.TransactionCount.Should().Be(block.Transactions.Length);

for (int i = 0; i < retrieved.TransactionCount; i++)
{
block.Transactions[i].Data = Array.Empty<byte>();
retrieved.GetNextTransaction().Should().BeEquivalentTo(block.Transactions[i]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using System.Threading;
using FluentAssertions;
using Nethermind.Blockchain.Blocks;
using Nethermind.Blockchain.Receipts;
using Nethermind.Core;
using Nethermind.Core.Crypto;
Expand All @@ -29,6 +30,7 @@ public class PersistentReceiptStorageTests
private TestMemColumnsDb<ReceiptsColumns> _receiptsDb = null!;
private ReceiptsRecovery _receiptsRecovery;
private IBlockTree _blockTree;
private IBlockStore _blockStore;
private readonly bool _useCompactReceipts;
private ReceiptConfig _receiptConfig;
private PersistentReceiptStorage _storage;
Expand All @@ -49,6 +51,7 @@ public void SetUp()
_receiptsDb = new TestMemColumnsDb<ReceiptsColumns>();
_receiptsDb.GetColumnDb(ReceiptsColumns.Blocks).Set(Keccak.Zero, Array.Empty<byte>());
_blockTree = Substitute.For<IBlockTree>();
_blockStore = Substitute.For<IBlockStore>();
CreateStorage();
}

Expand All @@ -60,6 +63,7 @@ private void CreateStorage()
MainnetSpecProvider.Instance,
_receiptsRecovery,
_blockTree,
_blockStore,
_receiptConfig,
_decoder
)
Expand Down Expand Up @@ -393,7 +397,7 @@ public void When_NewHeadBlock_ClearOldTxIndex()
{
(block, TxReceipt[] receipts) = PrepareBlock(block, isFinalized, headNumber);
_storage.Insert(block, receipts);
_receiptsRecovery.TryRecover(block, receipts);
_receiptsRecovery.TryRecover(new ReceiptRecoveryBlock(block), receipts);

return (block, receipts);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ private ReceiptsIterator CreateIterator(TxReceipt[] receipts, Block block)
false
);

ReceiptsIterator iterator = new ReceiptsIterator(span, blockDb, () => recovery.CreateRecoveryContext(block), _decoder.GetRefDecoder(span));
ReceiptsIterator iterator = new ReceiptsIterator(span, blockDb, () => recovery.CreateRecoveryContext(new ReceiptRecoveryBlock(block)), _decoder.GetRefDecoder(span));
return iterator;
}
}
23 changes: 19 additions & 4 deletions src/Nethermind/Nethermind.Blockchain/BlockTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public BlockTree(
ISpecProvider? specProvider,
IBloomStorage? bloomStorage,
ILogManager? logManager)
: this(dbProvider?.BlocksDb, dbProvider?.HeadersDb, dbProvider?.BlockInfosDb, dbProvider?.MetadataDb,
: this(new BlockStore(dbProvider?.BlocksDb), dbProvider?.HeadersDb, dbProvider?.BlockInfosDb, dbProvider?.MetadataDb,
chainLevelInfoRepository, specProvider, bloomStorage, new SyncConfig(), logManager)
{
}
Expand All @@ -132,7 +132,7 @@ public BlockTree(
IBloomStorage? bloomStorage,
ISyncConfig? syncConfig,
ILogManager? logManager)
: this(dbProvider?.BlocksDb, dbProvider?.HeadersDb, dbProvider?.BlockInfosDb, dbProvider?.MetadataDb,
: this(new BlockStore(dbProvider?.BlocksDb), dbProvider?.HeadersDb, dbProvider?.BlockInfosDb, dbProvider?.MetadataDb,
chainLevelInfoRepository, specProvider, bloomStorage, syncConfig, logManager)
{
}
Expand All @@ -145,7 +145,7 @@ public BlockTree(
ISpecProvider? specProvider,
IBloomStorage? bloomStorage,
ILogManager? logManager)
: this(blockDb, headerDb, blockInfoDb, new MemDb(), chainLevelInfoRepository, specProvider, bloomStorage,
: this(new BlockStore(blockDb), headerDb, blockInfoDb, new MemDb(), chainLevelInfoRepository, specProvider, bloomStorage,
new SyncConfig(), logManager)
{
}
Expand All @@ -160,9 +160,24 @@ public BlockTree(
IBloomStorage? bloomStorage,
ISyncConfig? syncConfig,
ILogManager? logManager)
: this(new BlockStore(blockDb), headerDb, blockInfoDb, metadataDb, chainLevelInfoRepository, specProvider, bloomStorage,
syncConfig, logManager)
{
}

public BlockTree(
IBlockStore? blockStore,
IDb? headerDb,
IDb? blockInfoDb,
IDb? metadataDb,
IChainLevelInfoRepository? chainLevelInfoRepository,
ISpecProvider? specProvider,
IBloomStorage? bloomStorage,
ISyncConfig? syncConfig,
ILogManager? logManager)
{
_logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
_blockStore = new BlockStore(blockDb ?? throw new ArgumentNullException(nameof(blockDb)));
_blockStore = blockStore ?? throw new ArgumentNullException(nameof(blockStore));
_headerDb = headerDb ?? throw new ArgumentNullException(nameof(headerDb));
_blockInfoDb = blockInfoDb ?? throw new ArgumentNullException(nameof(blockInfoDb));
_metadataDb = metadataDb ?? throw new ArgumentNullException(nameof(metadataDb));
Expand Down
26 changes: 26 additions & 0 deletions src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Buffers;
using System.Runtime.InteropServices;
using Nethermind.Core;
using Nethermind.Core.Caching;
using Nethermind.Core.Crypto;
Expand All @@ -13,6 +15,7 @@ namespace Nethermind.Blockchain.Blocks;
public class BlockStore : IBlockStore
{
private readonly IDb _blockDb;
private readonly IDbWithSpan? _blockDbAsSpan;
private readonly BlockDecoder _blockDecoder = new();
private const int CacheSize = 64;

Expand All @@ -22,6 +25,11 @@ private readonly LruCache<KeccakKey, Block>
public BlockStore(IDb blockDb)
{
_blockDb = blockDb;

if (blockDb is IDbWithSpan blockDbAsSpan)
_blockDbAsSpan = blockDbAsSpan;
else
_blockDbAsSpan = null;
}

public void SetMetadata(byte[] key, byte[] value)
Expand Down Expand Up @@ -55,9 +63,27 @@ public void Delete(Keccak blockHash)

public Block? Get(Keccak blockHash, bool shouldCache)
{

return _blockDb.Get(blockHash, _blockDecoder, _blockCache, shouldCache);
}

public ReceiptRecoveryBlock? GetReceiptRecoveryBlock(Keccak blockHash)
{
MemoryManager<byte>? memoryOwner = null;
Memory<byte> memory;
if (_blockDbAsSpan != null)
{
memoryOwner = _blockDbAsSpan.GetOwnedMemory(blockHash.Bytes);
memory = memoryOwner.Memory;
}
else
{
memory = _blockDb.Get(blockHash.Bytes);
}

return _blockDecoder.DecodeToReceiptRecoveryBlock(memoryOwner, memory, RlpBehaviors.None);
}

public void Cache(Block block)
{
_blockCache.Set(block.Hash, block);
Expand Down
2 changes: 2 additions & 0 deletions src/Nethermind/Nethermind.Blockchain/Blocks/IBlockStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Serialization.Rlp;

namespace Nethermind.Blockchain.Blocks;

Expand All @@ -15,6 +16,7 @@ public interface IBlockStore
void Insert(Block block);
void Delete(Keccak blockHash);
Block Get(Keccak blockHash, bool shouldCache = true);
ReceiptRecoveryBlock? GetReceiptRecoveryBlock(Keccak blockHash);
void Cache(Block block);


Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using Nethermind.Core;
using Nethermind.Serialization.Rlp;

namespace Nethermind.Blockchain.Receipts
{
public interface IReceiptsRecovery
{
ReceiptsRecoveryResult TryRecover(Block block, TxReceipt[] receipts, bool forceRecoverSender = true);
ReceiptsRecoveryResult TryRecover(ReceiptRecoveryBlock block, TxReceipt[] receipts, bool forceRecoverSender = true);

ReceiptsRecoveryResult TryRecover(Block block, TxReceipt[] receipts, bool forceRecoverSender = true) =>
TryRecover(new ReceiptRecoveryBlock(block), receipts, forceRecoverSender);

bool NeedRecover(TxReceipt[] receipts, bool forceRecoverSender = true, bool recoverSenderOnly = false);

IRecoveryContext CreateRecoveryContext(Block block, bool forceRecoverSender = false);
IRecoveryContext CreateRecoveryContext(ReceiptRecoveryBlock block, bool forceRecoverSender = false);

public interface IRecoveryContext
public interface IRecoveryContext : IDisposable
{
void RecoverReceiptData(TxReceipt receipt);
void RecoverReceiptData(ref TxReceiptStructRef receipt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Nethermind.Blockchain.Blocks;
using Nethermind.Core;
using Nethermind.Core.Caching;
using Nethermind.Core.Crypto;
Expand All @@ -29,6 +30,7 @@ public class PersistentReceiptStorage : IReceiptStorage
private long _migratedBlockNumber;
private readonly ReceiptArrayStorageDecoder _storageDecoder = ReceiptArrayStorageDecoder.Instance;
private readonly IBlockTree _blockTree;
private readonly IBlockStore _blockStore;
private readonly IReceiptConfig _receiptConfig;
private readonly bool _legacyHashKey;

Expand All @@ -40,6 +42,7 @@ public PersistentReceiptStorage(
ISpecProvider specProvider,
IReceiptsRecovery receiptsRecovery,
IBlockTree blockTree,
IBlockStore blockStore,
IReceiptConfig receiptConfig,
ReceiptArrayStorageDecoder? storageDecoder = null
)
Expand All @@ -52,6 +55,7 @@ public PersistentReceiptStorage(
_blocksDb = _database.GetColumnDb(ReceiptsColumns.Blocks);
_transactionDb = _database.GetColumnDb(ReceiptsColumns.Transactions);
_blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree));
_blockStore = blockStore ?? throw new ArgumentNullException(nameof(blockStore));
_storageDecoder = storageDecoder ?? ReceiptArrayStorageDecoder.Instance;
_receiptConfig = receiptConfig ?? throw new ArgumentNullException(nameof(receiptConfig));

Expand Down Expand Up @@ -237,8 +241,14 @@ public bool TryGetReceiptsIterator(long blockNumber, Keccak blockHash, out Recei
{
recoveryContextFactory = () =>
{
Block block = _blockTree.FindBlock(blockHash);
return _receiptsRecovery.CreateRecoveryContext(block!);
ReceiptRecoveryBlock? block = _blockStore.GetReceiptRecoveryBlock(blockHash);

if (!block.HasValue)
{
throw new InvalidOperationException($"Unable to recover receipts for block {blockHash} because of missing block data.");
}

return _receiptsRecovery.CreateRecoveryContext(block.Value);
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public void Dispose()
{
_blocksDb?.DangerousReleaseMemory(_decoderContext.Data);
}
_recoveryContext?.Dispose();
}

public LogEntriesIterator IterateLogs(TxReceiptStructRef receipt)
Expand Down
Loading