From 9070ca2132d4ae25e0b5126d7e96baf6703a4919 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Mon, 11 Aug 2025 17:43:54 +0100
Subject: [PATCH 001/215] add to release spec
---
src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs | 5 +++++
src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs | 1 +
.../Nethermind.Specs.Test/OverridableReleaseSpec.cs | 1 +
.../Nethermind.Specs/ChainSpecStyle/ChainParameters.cs | 1 +
.../Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs | 2 ++
.../ChainSpecStyle/Json/ChainSpecParamsJson.cs | 1 +
src/Nethermind/Nethermind.Specs/ReleaseSpec.cs | 2 ++
7 files changed, 13 insertions(+)
diff --git a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
index 85cc83f6033..b97d43e548c 100644
--- a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
+++ b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
@@ -513,5 +513,10 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec
/// RIP-7728: L1SLOAD precompile for reading L1 storage from L2
///
public bool IsRip7728Enabled { get; }
+
+ ///
+ /// EIP-7928: Block-Level Access Lists
+ ///
+ public bool IsEip7928Enabled { get; }
}
}
diff --git a/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs b/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs
index 3d7759d6824..2434ba4862c 100644
--- a/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs
+++ b/src/Nethermind/Nethermind.Core/Specs/ReleaseSpecDecorator.cs
@@ -152,4 +152,5 @@ public class ReleaseSpecDecorator(IReleaseSpec spec) : IReleaseSpec
public bool IsEip7939Enabled => spec.IsEip7939Enabled;
public bool IsEip7907Enabled => spec.IsEip7907Enabled;
public bool IsRip7728Enabled => spec.IsRip7728Enabled;
+ public bool IsEip7928Enabled => spec.IsEip7928Enabled;
}
diff --git a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs
index 2768d4c3e8e..c354ab068a3 100644
--- a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs
+++ b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs
@@ -196,5 +196,6 @@ public ulong Eip4844TransitionTimestamp
public bool IsEip7939Enabled => spec.IsEip7939Enabled;
public bool IsEip7907Enabled => spec.IsEip7907Enabled;
public bool IsRip7728Enabled => spec.IsRip7728Enabled;
+ public bool IsEip7928Enabled => spec.IsEip7928Enabled;
}
}
diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs
index ac09082a725..4cb47fe691e 100644
--- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs
+++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainParameters.cs
@@ -172,4 +172,5 @@ public class ChainParameters
#endregion
public ulong? Rip7728TransitionTimestamp { get; set; }
+ public ulong? Eip7928TransitionTimestamp { get; set; }
}
diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs
index 617c92ff9bc..f63fa545d95 100644
--- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs
+++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs
@@ -195,6 +195,8 @@ bool GetForInnerPathExistence(KeyValuePair o) =>
Eip7934MaxRlpBlockSize = chainSpecJson.Params.Eip7934MaxRlpBlockSize ?? Eip7934Constants.DefaultMaxRlpBlockSize,
Rip7728TransitionTimestamp = chainSpecJson.Params.Rip7728TransitionTimestamp,
+
+ Eip7928TransitionTimestamp = chainSpecJson.Params.Eip7928TransitionTimestamp,
};
chainSpec.Parameters.Eip152Transition ??= GetTransitionForExpectedPricing("blake2_f", "price.blake2_f.gas_per_round", 1);
diff --git a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs
index 2b11d0e01d4..ed186bd7aa5 100644
--- a/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs
+++ b/src/Nethermind/Nethermind.Specs/ChainSpecStyle/Json/ChainSpecParamsJson.cs
@@ -175,4 +175,5 @@ public class ChainSpecParamsJson
public ulong? Eip7594TransitionTimestamp { get; set; }
public ulong? Eip7939TransitionTimestamp { get; set; }
public ulong? Rip7728TransitionTimestamp { get; set; }
+ public ulong? Eip7928TransitionTimestamp { get; set; }
}
diff --git a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs
index 4b6dacdcf64..9a18167a7a3 100644
--- a/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs
+++ b/src/Nethermind/Nethermind.Specs/ReleaseSpec.cs
@@ -159,5 +159,7 @@ public Address Eip2935ContractAddress
Array? IReleaseSpec.EvmInstructionsTraced { get; set; }
public bool IsEip7939Enabled { get; set; }
public bool IsRip7728Enabled { get; set; }
+
+ public bool IsEip7928Enabled { get; set; }
}
}
From ea3f4d233d0654245dd6a4fc5fb7359f2d1890d6 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Mon, 11 Aug 2025 17:46:07 +0100
Subject: [PATCH 002/215] add hash to header
---
src/Nethermind/Nethermind.Core/BlockHeader.cs | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/Nethermind/Nethermind.Core/BlockHeader.cs b/src/Nethermind/Nethermind.Core/BlockHeader.cs
index 8948f3791c6..5a74fec72a2 100644
--- a/src/Nethermind/Nethermind.Core/BlockHeader.cs
+++ b/src/Nethermind/Nethermind.Core/BlockHeader.cs
@@ -73,13 +73,14 @@ public BlockHeader(
public Hash256? WithdrawalsRoot { get; set; }
public Hash256? ParentBeaconBlockRoot { get; set; }
public Hash256? RequestsHash { get; set; }
+ public Hash256? BlockAccessListHash { get; set; }
public ulong? BlobGasUsed { get; set; }
public ulong? ExcessBlobGas { get; set; }
public bool HasBody => (TxRoot is not null && TxRoot != Keccak.EmptyTreeHash)
|| (UnclesHash is not null && UnclesHash != Keccak.OfAnEmptySequenceRlp)
|| (WithdrawalsRoot is not null && WithdrawalsRoot != Keccak.EmptyTreeHash);
- public bool HasTransactions => (TxRoot is not null && TxRoot != Keccak.EmptyTreeHash);
+ public bool HasTransactions => TxRoot is not null && TxRoot != Keccak.EmptyTreeHash;
public string SealEngineType { get; set; } = Core.SealEngineType.Ethash;
public bool IsPostMerge { get; set; }
@@ -122,6 +123,10 @@ public string ToString(string indent)
{
builder.AppendLine($"{indent}RequestsHash: {RequestsHash}");
}
+ if (BlockAccessListHash is not null)
+ {
+ builder.AppendLine($"{indent}BlockAccessListHash: {BlockAccessListHash}");
+ }
return builder.ToString();
}
From 5fae29d0ac81be363db39fccb0ead736acb89524 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Mon, 11 Aug 2025 17:51:15 +0100
Subject: [PATCH 003/215] add to block body
---
src/Nethermind/Nethermind.Core/Block.cs | 1 +
src/Nethermind/Nethermind.Core/BlockBody.cs | 18 ++++++------------
2 files changed, 7 insertions(+), 12 deletions(-)
diff --git a/src/Nethermind/Nethermind.Core/Block.cs b/src/Nethermind/Nethermind.Core/Block.cs
index aae9fdbbb6f..6c25efae61d 100644
--- a/src/Nethermind/Nethermind.Core/Block.cs
+++ b/src/Nethermind/Nethermind.Core/Block.cs
@@ -116,6 +116,7 @@ public Transaction[] Transactions
public Hash256? ParentBeaconBlockRoot => Header.ParentBeaconBlockRoot; // do not add setter here
public Hash256? RequestsHash => Header.RequestsHash; // do not add setter here
+ public byte[]? BlockAccessList => Body.BlockAccessList; // do not add setter here
[JsonIgnore]
public byte[][]? ExecutionRequests { get; set; }
diff --git a/src/Nethermind/Nethermind.Core/BlockBody.cs b/src/Nethermind/Nethermind.Core/BlockBody.cs
index 619a0edd8ac..6104ca6f206 100644
--- a/src/Nethermind/Nethermind.Core/BlockBody.cs
+++ b/src/Nethermind/Nethermind.Core/BlockBody.cs
@@ -3,15 +3,8 @@
namespace Nethermind.Core
{
- public class BlockBody
+ public class BlockBody(Transaction[]? transactions, BlockHeader[]? uncles, Withdrawal[]? withdrawals = null)
{
- public BlockBody(Transaction[]? transactions, BlockHeader[]? uncles, Withdrawal[]? withdrawals = null)
- {
- Transactions = transactions ?? [];
- Uncles = uncles ?? [];
- Withdrawals = withdrawals;
- }
-
public BlockBody() : this(null, null, null) { }
public BlockBody WithChangedTransactions(Transaction[] transactions) => new(transactions, Uncles, Withdrawals);
@@ -20,13 +13,14 @@ public BlockBody() : this(null, null, null) { }
public BlockBody WithChangedWithdrawals(Withdrawal[]? withdrawals) => new(Transactions, Uncles, withdrawals);
- public static BlockBody WithOneTransactionOnly(Transaction tx) => new(new[] { tx }, null, null);
+ public static BlockBody WithOneTransactionOnly(Transaction tx) => new([tx], null, null);
- public Transaction[] Transactions { get; internal set; }
+ public Transaction[] Transactions { get; internal set; } = transactions ?? [];
- public BlockHeader[] Uncles { get; }
+ public BlockHeader[] Uncles { get; } = uncles ?? [];
- public Withdrawal[]? Withdrawals { get; }
+ public Withdrawal[]? Withdrawals { get; } = withdrawals;
+ public byte[]? BlockAccessList { get; }
public bool IsEmpty => Transactions.Length == 0 && Uncles.Length == 0 && (Withdrawals?.Length ?? 0) == 0;
}
From 273905e03aedd6164b81090af8ebb3a2b0ca42e0 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Mon, 11 Aug 2025 18:21:07 +0100
Subject: [PATCH 004/215] BAL validation
---
.../Messages/BlockErrorMessages.cs | 6 +++
.../Processing/BranchProcessor.cs | 6 ---
.../Validators/BlockValidator.cs | 49 +++++++++++++++++++
.../Nethermind.Core/Specs/IReleaseSpec.cs | 2 +
4 files changed, 57 insertions(+), 6 deletions(-)
diff --git a/src/Nethermind/Nethermind.Consensus/Messages/BlockErrorMessages.cs b/src/Nethermind/Nethermind.Consensus/Messages/BlockErrorMessages.cs
index 8bcca457d05..ec1db39e983 100644
--- a/src/Nethermind/Nethermind.Consensus/Messages/BlockErrorMessages.cs
+++ b/src/Nethermind/Nethermind.Consensus/Messages/BlockErrorMessages.cs
@@ -150,4 +150,10 @@ public static string InvalidDepositEventLayout(string error) =>
public static string ExceededBlockSizeLimit(int limit) =>
$"ExceededBlockSizeLimit: Exceeded block size limit of {limit} bytes.";
+
+ public const string MissingBlockLevelAccessList = "MissingBlockLevelAccessList: Must be present in block body.";
+
+ public static string InvalidBlockLevelAccessListRoot(Hash256 expected, Hash256 actual) =>
+ $"InvalidBlockLevelAccessListRoot: expected {expected}, got {actual}";
+
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BranchProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BranchProcessor.cs
index 7dd0351fa37..2a0cad1c5e0 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BranchProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BranchProcessor.cs
@@ -6,12 +6,6 @@
using System.Threading;
using System.Threading.Tasks;
using Nethermind.Blockchain.BeaconBlockRoot;
-using Nethermind.Blockchain.Blocks;
-using Nethermind.Blockchain.Receipts;
-using Nethermind.Consensus.ExecutionRequests;
-using Nethermind.Consensus.Rewards;
-using Nethermind.Consensus.Validators;
-using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
diff --git a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
index 0f8e98ac4f5..35384b53474 100644
--- a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
+++ b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
@@ -391,6 +391,43 @@ public virtual bool ValidateBodyAgainstHeader(BlockHeader header, BlockBody toBe
return true;
}
+ public virtual bool ValidateBlockLevelAccessList(Block block, IReleaseSpec spec, out string? error)
+ {
+ if (spec.BlockLevelAccessListsEnabled && block.BlockAccessList is null)
+ {
+ error = BlockErrorMessages.MissingBlockLevelAccessList;
+
+ if (_logger.IsWarn) _logger.Warn($"Block level access list cannot be null in block {block.Hash} when EIP-7928 activated.");
+
+ return false;
+ }
+
+ if (!spec.BlockLevelAccessListsEnabled && block.BlockAccessList is not null)
+ {
+ error = BlockErrorMessages.WithdrawalsNotEnabled;
+
+ if (_logger.IsWarn) _logger.Warn($"Block level access list must be null in block {block.Hash} when EIP-7928 not activated.");
+
+ return false;
+ }
+
+ if (block.BlockAccessList is not null)
+ {
+ if (!ValidateBlockLevelAccessListHashMatces(block.Header, block.Body, out Hash256 blockLevelAccessListRoot))
+ {
+ error = BlockErrorMessages.InvalidBlockLevelAccessListRoot(block.Header.BlockAccessListHash, blockLevelAccessListRoot);
+ if (_logger.IsWarn) _logger.Warn($"Block level access list root hash mismatch in block {block.ToString(Block.Format.FullHashAndNumber)}: expected {block.Header.BlockAccessListHash}, got {blockLevelAccessListRoot}");
+
+ return false;
+ }
+ }
+
+ error = null;
+
+ return true;
+
+ }
+
public static bool ValidateTxRootMatchesTxs(Block block, out Hash256 txRoot) =>
ValidateTxRootMatchesTxs(block.Header, block.Body, out txRoot);
@@ -417,6 +454,18 @@ public static bool ValidateWithdrawalsHashMatches(BlockHeader header, BlockBody
return (withdrawalsRoot = new WithdrawalTrie(body.Withdrawals).RootHash) == header.WithdrawalsRoot;
}
+ public static bool ValidateBlockLevelAccessListHashMatces(BlockHeader header, BlockBody body, out Hash256? blockLevelAccessListRoot)
+ {
+ if (body.BlockAccessList is null)
+ {
+ blockLevelAccessListRoot = null;
+ return header.BlockAccessListHash is null;
+ }
+
+ // todo: SSZ encode here
+ return (blockLevelAccessListRoot = Hash256.Zero) == header.BlockAccessListHash;
+ }
+
private static string Invalid(Block block) =>
$"Invalid block {block.ToString(Block.Format.FullHashAndNumber)}:";
}
diff --git a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
index b97d43e548c..2587533f7bb 100644
--- a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
+++ b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
@@ -466,6 +466,8 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec
public bool RequestsEnabled => ConsolidationRequestsEnabled || WithdrawalRequestsEnabled || DepositsEnabled;
+ bool BlockLevelAccessListsEnabled => IsEip7928Enabled;
+
public bool IsEip7594Enabled { get; }
///
From 0246d856cdcacfe2ffe96adbb70b579c469c379f Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Mon, 11 Aug 2025 18:24:21 +0100
Subject: [PATCH 005/215] add to constuctor
---
src/Nethermind/Nethermind.Core/BlockBody.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Nethermind/Nethermind.Core/BlockBody.cs b/src/Nethermind/Nethermind.Core/BlockBody.cs
index 6104ca6f206..a443e1d24f5 100644
--- a/src/Nethermind/Nethermind.Core/BlockBody.cs
+++ b/src/Nethermind/Nethermind.Core/BlockBody.cs
@@ -3,7 +3,7 @@
namespace Nethermind.Core
{
- public class BlockBody(Transaction[]? transactions, BlockHeader[]? uncles, Withdrawal[]? withdrawals = null)
+ public class BlockBody(Transaction[]? transactions, BlockHeader[]? uncles, Withdrawal[]? withdrawals = null, byte[]? blockLevelAccessList = null)
{
public BlockBody() : this(null, null, null) { }
@@ -20,7 +20,7 @@ public BlockBody() : this(null, null, null) { }
public BlockHeader[] Uncles { get; } = uncles ?? [];
public Withdrawal[]? Withdrawals { get; } = withdrawals;
- public byte[]? BlockAccessList { get; }
+ public byte[]? BlockAccessList { get; } = blockLevelAccessList ?? [];
public bool IsEmpty => Transactions.Length == 0 && Uncles.Length == 0 && (Withdrawals?.Length ?? 0) == 0;
}
From db756e64e28c7fd58f997cb1b92c967f0a8ee111 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 12 Aug 2025 16:16:13 +0100
Subject: [PATCH 006/215] set BAL at end of processing
---
.../Nethermind.Consensus/Processing/BlockProcessor.cs | 9 +++------
src/Nethermind/Nethermind.Core/BlockBody.cs | 2 +-
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index 72f350bffab..6f670dbcd63 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -2,11 +2,9 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
-using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading;
-using System.Threading.Tasks;
using Nethermind.Blockchain;
using Nethermind.Blockchain.BeaconBlockRoot;
using Nethermind.Blockchain.Blocks;
@@ -17,8 +15,6 @@
using Nethermind.Consensus.Validators;
using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
-using Nethermind.Core.Crypto;
-using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Core.Threading;
using Nethermind.Crypto;
@@ -31,8 +27,6 @@
using Nethermind.State;
using static Nethermind.Consensus.Processing.IBlockProcessor;
-using Metrics = Nethermind.Blockchain.Metrics;
-
namespace Nethermind.Consensus.Processing;
public partial class BlockProcessor(
@@ -104,6 +98,7 @@ protected virtual TxReceipt[] ProcessBlock(
IReleaseSpec spec,
CancellationToken token)
{
+ BlockBody body = block.Body;
BlockHeader header = block.Header;
ReceiptsTracer.SetOtherTracer(blockTracer);
@@ -154,6 +149,8 @@ protected virtual TxReceipt[] ProcessBlock(
}
header.Hash = header.CalculateHash();
+ // create from block.AccountChanges and encode
+ body.BlockAccessList = [];
return receipts;
}
diff --git a/src/Nethermind/Nethermind.Core/BlockBody.cs b/src/Nethermind/Nethermind.Core/BlockBody.cs
index a443e1d24f5..0485b8f51dd 100644
--- a/src/Nethermind/Nethermind.Core/BlockBody.cs
+++ b/src/Nethermind/Nethermind.Core/BlockBody.cs
@@ -20,7 +20,7 @@ public BlockBody() : this(null, null, null) { }
public BlockHeader[] Uncles { get; } = uncles ?? [];
public Withdrawal[]? Withdrawals { get; } = withdrawals;
- public byte[]? BlockAccessList { get; } = blockLevelAccessList ?? [];
+ public byte[]? BlockAccessList { get; internal set; } = blockLevelAccessList ?? [];
public bool IsEmpty => Transactions.Length == 0 && Uncles.Length == 0 && (Withdrawals?.Length ?? 0) == 0;
}
From 8c6f4e2304b0b7882b9dad14ba87bb90cb005ba8 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 12 Aug 2025 17:28:25 +0100
Subject: [PATCH 007/215] constants, ssz containers
---
...sor.BlockValidationTransactionsExecutor.cs | 2 -
.../Nethermind.Core/Eip7928Constants.cs | 13 +++
.../BlockAccessLists/BlockAccessLists.cs | 95 +++++++++++++++++++
3 files changed, 108 insertions(+), 2 deletions(-)
create mode 100644 src/Nethermind/Nethermind.Core/Eip7928Constants.cs
create mode 100644 src/Nethermind/Nethermind.Serialization.Ssz/BlockAccessLists/BlockAccessLists.cs
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
index bff0bd56ef7..7293bb5240b 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
@@ -9,10 +9,8 @@
using Nethermind.Blockchain;
using Nethermind.Blockchain.Tracing;
using Nethermind.Core;
-using Nethermind.Core.Specs;
using Nethermind.Evm;
using Nethermind.Evm.State;
-using Nethermind.Evm.Tracing;
using Nethermind.Evm.TransactionProcessing;
using Metrics = Nethermind.Evm.Metrics;
diff --git a/src/Nethermind/Nethermind.Core/Eip7928Constants.cs b/src/Nethermind/Nethermind.Core/Eip7928Constants.cs
new file mode 100644
index 00000000000..cafa85007c4
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Eip7928Constants.cs
@@ -0,0 +1,13 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+namespace Nethermind.Core;
+
+public static class Eip7928Constants
+{
+ public const int MaxTxs = 30_000;
+ public const int MaxSlots = 300_000;
+ public const int MaxAccounts = 300_000;
+ public const int MaxCodeSize = 24_576;
+ public const int MaxCodeChanges = 1;
+}
diff --git a/src/Nethermind/Nethermind.Serialization.Ssz/BlockAccessLists/BlockAccessLists.cs b/src/Nethermind/Nethermind.Serialization.Ssz/BlockAccessLists/BlockAccessLists.cs
new file mode 100644
index 00000000000..f385d2ee262
--- /dev/null
+++ b/src/Nethermind/Nethermind.Serialization.Ssz/BlockAccessLists/BlockAccessLists.cs
@@ -0,0 +1,95 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using Nethermind.Core;
+
+// move somewhere
+namespace Nethermind.Serialization.Ssz;
+
+// Single storage write: tx_index -> new_value
+[SszSerializable]
+public struct StorageChange
+{
+ public ushort TxIndex { get; set; }
+ [SszVector(32)]
+ public byte[] NewValue { get; set; }
+}
+
+// Single balance change: tx_index -> post_balance
+[SszSerializable]
+public struct BalanceChange
+{
+ public ushort TxIndex { get; set; }
+ public UInt128 PostBalance { get; set; }
+}
+
+// Single nonce change: tx_index -> new_nonce
+[SszSerializable]
+public struct NonceChange
+{
+ public ushort TxIndex { get; set; }
+ public ulong NewNonce { get; set; }
+}
+
+// Single code change: tx_index -> new_code
+[SszSerializable]
+public struct CodeChange
+{
+ public ushort TxIndex { get; set; }
+
+ [SszList(Eip7928Constants.MaxCodeSize)]
+ public byte[] NewCode { get; set; }
+}
+
+[SszSerializable]
+public struct SlotChanges
+{
+ [SszVector(32)]
+ public byte[] Slot { get; set; }
+
+ [SszList(Eip7928Constants.MaxTxs)]
+ public ulong Changes { get; set; }
+}
+
+[SszSerializable]
+public struct StorageKey
+{
+ [SszVector(32)]
+ public byte[] Key { get; set; }
+}
+
+[SszSerializable]
+public struct AccoutChanges
+{
+ [SszVector(20)]
+ public byte[] Address { get; set; }
+
+ // Storage changes (slot -> [tx_index -> new_value])
+ [SszList(Eip7928Constants.MaxSlots)]
+ public List StorageChanges { get; set; }
+
+ // Read-only storage keys
+ [SszList(Eip7928Constants.MaxSlots)]
+ public List StorageReads { get; set; }
+
+ // Balance changes ([tx_index -> post_balance])
+ [SszList(Eip7928Constants.MaxTxs)]
+ public List BalanceChanges { get; set; }
+
+ // Nonce changes ([tx_index -> new_nonce])
+ [SszList(Eip7928Constants.MaxTxs)]
+ public List NonceChanges { get; set; }
+
+ // Code changes ([tx_index -> new_code])
+ [SszList(Eip7928Constants.MaxCodeChanges)]
+ public List CodeChanges { get; set; }
+}
+
+[SszSerializable]
+public struct BlockAccessList
+{
+ [SszList(Eip7928Constants.MaxAccounts)]
+ public List AccountChanges { get; set; }
+}
From dbed6d22fbcd76ba1d7ac7d2bdba63a6e3986fe8 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 15 Aug 2025 12:39:10 +0100
Subject: [PATCH 008/215] add block access tracer
---
.../Tracing/BlockAccessTracer.cs | 238 ++++++++++++++++++
.../Processing/BlockProcessor.cs | 7 +-
2 files changed, 244 insertions(+), 1 deletion(-)
create mode 100644 src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
new file mode 100644
index 00000000000..00d3247be31
--- /dev/null
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
@@ -0,0 +1,238 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Evm;
+using Nethermind.Evm.Tracing;
+using Nethermind.Evm.TransactionProcessing;
+using Nethermind.Int256;
+
+namespace Nethermind.Blockchain.Tracing;
+
+public struct Access
+{
+
+}
+
+public class BlockAccessTracer : IBlockTracer, ITxTracer, IJournal
+{
+ // private IBlockTracer _otherTracer = NullBlockTracer.Instance;
+ protected Block Block = null!;
+ public bool IsTracingReceipt => false;
+ public bool IsTracingActions => false;
+ public bool IsTracingOpLevelStorage => false;
+ public bool IsTracingMemory => false;
+ public bool IsTracingInstructions => false;
+ public bool IsTracingRefunds => false;
+ public bool IsTracingCode => false;
+ public bool IsTracingStack => false;
+ public bool IsTracingState => true;
+ public bool IsTracingStorage => true;
+
+ public bool IsTracingBlockHash => false;
+ public bool IsTracingAccess => true;
+ public bool IsTracingFees => false;
+ public bool IsTracingLogs => false;
+
+ public void MarkAsSuccess(Address recipient, GasConsumed gasSpent, byte[] output, LogEntry[] logs, Hash256? stateRoot = null)
+ {
+ // _txReceipts.Add(BuildReceipt(recipient, gasSpent.SpentGas, StatusCode.Success, logs, stateRoot));
+ }
+
+ public void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output, string? error, Hash256? stateRoot = null)
+ {
+ // _txReceipts.Add(BuildFailedReceipt(recipient, gasSpent.SpentGas, error, stateRoot));
+
+ }
+
+ protected TxReceipt BuildFailedReceipt(Address recipient, long gasSpent, string error, Hash256? stateRoot)
+ {
+ TxReceipt receipt = BuildReceipt(recipient, gasSpent, StatusCode.Failure, [], stateRoot);
+ receipt.Error = error;
+ return receipt;
+ }
+
+ protected virtual TxReceipt BuildReceipt(Address recipient, long spentGas, byte statusCode, LogEntry[] logEntries, Hash256? stateRoot)
+ {
+ Transaction transaction = CurrentTx!;
+ TxReceipt txReceipt = new()
+ {
+ Logs = logEntries,
+ TxType = transaction.Type,
+ // Bloom calculated in parallel with other receipts
+ GasUsedTotal = Block.GasUsed,
+ StatusCode = statusCode,
+ Recipient = transaction.IsContractCreation ? null : recipient,
+ BlockHash = Block.Hash,
+ BlockNumber = Block.Number,
+ Index = _currentIndex,
+ GasUsed = spentGas,
+ Sender = transaction.SenderAddress,
+ ContractAddress = transaction.IsContractCreation ? recipient : null,
+ TxHash = transaction.Hash,
+ PostTransactionState = stateRoot
+ };
+
+ return txReceipt;
+ }
+
+ public void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env, int codeSection = 0, int functionDepth = 0) {}
+
+ public void ReportOperationError(EvmExceptionType error) {}
+
+
+ public void ReportOperationRemainingGas(long gas) {}
+
+ public void ReportLog(LogEntry log) {}
+
+ public void SetOperationMemorySize(ulong newSize) {}
+
+ public void ReportMemoryChange(long offset, in ReadOnlySpan data) {}
+
+ public void ReportStorageChange(in ReadOnlySpan key, in ReadOnlySpan value)
+ {
+ _accesses.Add(new());
+ }
+
+ public void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue) {}
+
+ public void LoadOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan value) {}
+
+ public void ReportSelfDestruct(Address address, UInt256 balance, Address refundAddress) {}
+
+ public void ReportBalanceChange(Address address, UInt256? before, UInt256? after)
+ {
+ _accesses.Add(new());
+ }
+
+ public void ReportCodeChange(Address address, byte[] before, byte[] after)
+ {
+ _accesses.Add(new());
+ }
+
+ public void ReportNonceChange(Address address, UInt256? before, UInt256? after)
+ {
+ _accesses.Add(new());
+ }
+
+ public void ReportAccountRead(Address address)
+ {
+ _accesses.Add(new());
+ }
+
+ public void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[] after)
+ {
+ _accesses.Add(new());
+ }
+
+ public void ReportStorageRead(in StorageCell storageCell)
+ {
+ _accesses.Add(new());
+ }
+
+ public void ReportAction(long gas, UInt256 value, Address from, Address to, ReadOnlyMemory input, ExecutionType callType, bool isPrecompileCall = false) {}
+
+ public void ReportActionEnd(long gas, ReadOnlyMemory output) {}
+
+ public void ReportActionError(EvmExceptionType exceptionType) {}
+
+ public void ReportActionRevert(long gasLeft, ReadOnlyMemory output) {}
+
+ public void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory deployedCode) {}
+
+ public void ReportByteCode(ReadOnlyMemory byteCode) {}
+
+ public void ReportGasUpdateForVmTrace(long refund, long gasAvailable) {}
+
+ public void ReportRefund(long refund) {}
+
+ public void ReportExtraGasPressure(long extraGasPressure) {}
+
+ public void ReportAccess(IReadOnlyCollection accessedAddresses, IReadOnlyCollection accessedStorageCells)
+ {
+ _accesses.Add(new());
+ }
+
+ public void SetOperationStack(TraceStack stack) {}
+
+ public void ReportStackPush(in ReadOnlySpan stackItem) {}
+
+ public void ReportBlockHash(Hash256 blockHash) {}
+
+ public void SetOperationMemory(TraceMemory memoryTrace) {}
+
+ public void ReportFees(UInt256 fees, UInt256 burntFees) {}
+
+ // private ITxTracer _currentTxTracer = NullTxTracer.Instance;
+ protected int _currentIndex { get; private set; }
+ // private readonly List _txReceipts = new();
+ private readonly List _accesses = [];
+ protected Transaction? CurrentTx;
+ public IReadOnlyList Accesses => _accesses;
+ // public IReadOnlyList TxReceipts => _txReceipts;
+ // public TxReceipt LastReceipt => _txReceipts[^1];
+ public bool IsTracingRewards => false;
+
+ // public ITxTracer InnerTracer => _currentTxTracer;
+
+ public int TakeSnapshot() => _accesses.Count;
+
+ public void Restore(int snapshot)
+ {
+ // int numToRemove = _txReceipts.Count - snapshot;
+
+ // for (int i = 0; i < numToRemove; i++)
+ // {
+ // _txReceipts.RemoveAt(_txReceipts.Count - 1);
+ // }
+
+ // Block.Header.GasUsed = _txReceipts.Count > 0 ? _txReceipts.Last().GasUsedTotal : 0;
+ }
+
+ public void ReportReward(Address author, string rewardType, UInt256 rewardValue) {}
+
+ public void StartNewBlockTrace(Block block)
+ {
+ Block = block;
+ _currentIndex = 0;
+ _accesses.Clear();
+ }
+
+ public ITxTracer StartNewTxTrace(Transaction? tx)
+ {
+ return this;
+ }
+
+ public void EndTxTrace()
+ {
+ _currentIndex++;
+ }
+
+ public void EndBlockTrace()
+ {
+ // _otherTracer.EndBlockTrace();
+ // if (_txReceipts.Count > 0)
+ // {
+ // Bloom blockBloom = new();
+ // Block.Header.Bloom = blockBloom;
+ // for (int index = 0; index < _txReceipts.Count; index++)
+ // {
+ // TxReceipt? receipt = _txReceipts[index];
+ // blockBloom.Accumulate(receipt.Bloom!);
+ // }
+ // }
+ }
+
+ // public void SetOtherTracer(IBlockTracer blockTracer)
+ // {
+ // _otherTracer = blockTracer;
+ // }
+
+ public void Dispose()
+ {
+ // _currentTxTracer.Dispose();
+ }
+}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index 6f670dbcd63..a6e14d4907c 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -52,6 +52,7 @@ public partial class BlockProcessor(
/// to any block-specific tracers.
///
protected BlockReceiptsTracer ReceiptsTracer { get; set; } = new();
+ protected BlockAccessTracer BlockAccessTracer { get; set; } = new();
public event EventHandler TransactionProcessed
{
@@ -101,7 +102,10 @@ protected virtual TxReceipt[] ProcessBlock(
BlockBody body = block.Body;
BlockHeader header = block.Header;
- ReceiptsTracer.SetOtherTracer(blockTracer);
+ CompositeBlockTracer compositeBlockTracer = new();
+ compositeBlockTracer.Add(blockTracer);
+ compositeBlockTracer.Add(BlockAccessTracer);
+ ReceiptsTracer.SetOtherTracer(compositeBlockTracer);
ReceiptsTracer.StartNewBlockTrace(block);
blockTransactionsExecutor.SetBlockExecutionContext(new BlockExecutionContext(block.Header, spec));
@@ -150,6 +154,7 @@ protected virtual TxReceipt[] ProcessBlock(
header.Hash = header.CalculateHash();
// create from block.AccountChanges and encode
+ System.Collections.Generic.IReadOnlyList accesses = ReceiptsTracer.GetTracer().Accesses;
body.BlockAccessList = [];
return receipts;
From 7d7cb298e4a243b648f283c6a792eaf064597226 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 15 Aug 2025 13:09:27 +0100
Subject: [PATCH 009/215] construct BAL in tracer
---
.../Tracing}/BlockAccessLists.cs | 39 ++++----
.../Tracing/BlockAccessTracer.cs | 90 +++++++++----------
.../Processing/BlockProcessor.cs | 5 +-
3 files changed, 59 insertions(+), 75 deletions(-)
rename src/Nethermind/{Nethermind.Serialization.Ssz/BlockAccessLists => Nethermind.Blockchain/Tracing}/BlockAccessLists.cs (69%)
diff --git a/src/Nethermind/Nethermind.Serialization.Ssz/BlockAccessLists/BlockAccessLists.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessLists.cs
similarity index 69%
rename from src/Nethermind/Nethermind.Serialization.Ssz/BlockAccessLists/BlockAccessLists.cs
rename to src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessLists.cs
index f385d2ee262..cd9157c396e 100644
--- a/src/Nethermind/Nethermind.Serialization.Ssz/BlockAccessLists/BlockAccessLists.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessLists.cs
@@ -5,20 +5,17 @@
using System.Collections.Generic;
using Nethermind.Core;
-// move somewhere
-namespace Nethermind.Serialization.Ssz;
+namespace Nethermind.Blockchain.Tracing;
// Single storage write: tx_index -> new_value
-[SszSerializable]
public struct StorageChange
{
public ushort TxIndex { get; set; }
- [SszVector(32)]
+ // [SszVector(32)]
public byte[] NewValue { get; set; }
}
// Single balance change: tx_index -> post_balance
-[SszSerializable]
public struct BalanceChange
{
public ushort TxIndex { get; set; }
@@ -26,7 +23,6 @@ public struct BalanceChange
}
// Single nonce change: tx_index -> new_nonce
-[SszSerializable]
public struct NonceChange
{
public ushort TxIndex { get; set; }
@@ -34,62 +30,57 @@ public struct NonceChange
}
// Single code change: tx_index -> new_code
-[SszSerializable]
public struct CodeChange
{
public ushort TxIndex { get; set; }
- [SszList(Eip7928Constants.MaxCodeSize)]
+ // [SszList(Eip7928Constants.MaxCodeSize)]
public byte[] NewCode { get; set; }
}
-[SszSerializable]
public struct SlotChanges
{
- [SszVector(32)]
+ // [SszVector(32)]
public byte[] Slot { get; set; }
- [SszList(Eip7928Constants.MaxTxs)]
+ // [SszList(Eip7928Constants.MaxTxs)]
public ulong Changes { get; set; }
}
-[SszSerializable]
public struct StorageKey
{
- [SszVector(32)]
+ // [SszVector(32)]
public byte[] Key { get; set; }
}
-[SszSerializable]
-public struct AccoutChanges
+public struct AccountChanges
{
- [SszVector(20)]
+ // [SszVector(20)]
public byte[] Address { get; set; }
// Storage changes (slot -> [tx_index -> new_value])
- [SszList(Eip7928Constants.MaxSlots)]
+ // [SszList(Eip7928Constants.MaxSlots)]
public List StorageChanges { get; set; }
// Read-only storage keys
- [SszList(Eip7928Constants.MaxSlots)]
+ // [SszList(Eip7928Constants.MaxSlots)]
public List StorageReads { get; set; }
// Balance changes ([tx_index -> post_balance])
- [SszList(Eip7928Constants.MaxTxs)]
+ // [SszList(Eip7928Constants.MaxTxs)]
public List BalanceChanges { get; set; }
// Nonce changes ([tx_index -> new_nonce])
- [SszList(Eip7928Constants.MaxTxs)]
+ // [SszList(Eip7928Constants.MaxTxs)]
public List NonceChanges { get; set; }
// Code changes ([tx_index -> new_code])
- [SszList(Eip7928Constants.MaxCodeChanges)]
+ // [SszList(Eip7928Constants.MaxCodeChanges)]
public List CodeChanges { get; set; }
}
-[SszSerializable]
public struct BlockAccessList
{
- [SszList(Eip7928Constants.MaxAccounts)]
- public List AccountChanges { get; set; }
+ // [SszList(Eip7928Constants.MaxAccounts)]
+ public Dictionary AccountChanges { get; set; }
}
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
index 00d3247be31..bc841465a0a 100644
--- a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
@@ -12,11 +12,6 @@
namespace Nethermind.Blockchain.Tracing;
-public struct Access
-{
-
-}
-
public class BlockAccessTracer : IBlockTracer, ITxTracer, IJournal
{
// private IBlockTracer _otherTracer = NullBlockTracer.Instance;
@@ -48,37 +43,6 @@ public void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output,
}
- protected TxReceipt BuildFailedReceipt(Address recipient, long gasSpent, string error, Hash256? stateRoot)
- {
- TxReceipt receipt = BuildReceipt(recipient, gasSpent, StatusCode.Failure, [], stateRoot);
- receipt.Error = error;
- return receipt;
- }
-
- protected virtual TxReceipt BuildReceipt(Address recipient, long spentGas, byte statusCode, LogEntry[] logEntries, Hash256? stateRoot)
- {
- Transaction transaction = CurrentTx!;
- TxReceipt txReceipt = new()
- {
- Logs = logEntries,
- TxType = transaction.Type,
- // Bloom calculated in parallel with other receipts
- GasUsedTotal = Block.GasUsed,
- StatusCode = statusCode,
- Recipient = transaction.IsContractCreation ? null : recipient,
- BlockHash = Block.Hash,
- BlockNumber = Block.Number,
- Index = _currentIndex,
- GasUsed = spentGas,
- Sender = transaction.SenderAddress,
- ContractAddress = transaction.IsContractCreation ? recipient : null,
- TxHash = transaction.Hash,
- PostTransactionState = stateRoot
- };
-
- return txReceipt;
- }
-
public void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env, int codeSection = 0, int functionDepth = 0) {}
public void ReportOperationError(EvmExceptionType error) {}
@@ -94,7 +58,7 @@ public void ReportMemoryChange(long offset, in ReadOnlySpan data) {}
public void ReportStorageChange(in ReadOnlySpan key, in ReadOnlySpan value)
{
- _accesses.Add(new());
+ //_bal.AccountChanges[].StorageChanges()
}
public void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue) {}
@@ -105,32 +69,61 @@ public void ReportSelfDestruct(Address address, UInt256 balance, Address refundA
public void ReportBalanceChange(Address address, UInt256? before, UInt256? after)
{
- _accesses.Add(new());
+ BalanceChange balanceChange = new()
+ {
+ TxIndex = (ushort)_currentIndex,
+ PostBalance = (ulong)after // why not 256 bit?
+ };
+ _bal.AccountChanges[address].BalanceChanges.Add(balanceChange);
}
public void ReportCodeChange(Address address, byte[] before, byte[] after)
{
- _accesses.Add(new());
+ CodeChange codeChange = new()
+ {
+ TxIndex = (ushort)_currentIndex,
+ NewCode = after
+ };
+ _bal.AccountChanges[address].CodeChanges.Add(codeChange);
}
public void ReportNonceChange(Address address, UInt256? before, UInt256? after)
{
- _accesses.Add(new());
+ NonceChange nonceChange = new()
+ {
+ TxIndex = (ushort)_currentIndex,
+ NewNonce = (ulong)after
+ };
+ _bal.AccountChanges[address].NonceChanges.Add(nonceChange);
}
public void ReportAccountRead(Address address)
{
- _accesses.Add(new());
+ if (!_bal.AccountChanges.ContainsKey(address))
+ {
+ _bal.AccountChanges.Add(address, new());
+ }
}
public void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[] after)
{
- _accesses.Add(new());
+ StorageChange storageChange = new()
+ {
+ TxIndex = (ushort)_currentIndex,
+ NewValue = after
+ };
+ Address address = Address.Zero;
+ _bal.AccountChanges[address].StorageChanges.Add(storageChange);
}
public void ReportStorageRead(in StorageCell storageCell)
{
- _accesses.Add(new());
+ StorageKey storageKey = new()
+ {
+ Key = storageCell.Hash.ToByteArray()
+ };
+ Address address = Address.Zero;
+ _bal.AccountChanges[address].StorageReads.Add(storageKey);
}
public void ReportAction(long gas, UInt256 value, Address from, Address to, ReadOnlyMemory input, ExecutionType callType, bool isPrecompileCall = false) {}
@@ -153,7 +146,7 @@ public void ReportExtraGasPressure(long extraGasPressure) {}
public void ReportAccess(IReadOnlyCollection accessedAddresses, IReadOnlyCollection accessedStorageCells)
{
- _accesses.Add(new());
+ // _bal.Add(new());
}
public void SetOperationStack(TraceStack stack) {}
@@ -169,16 +162,15 @@ public void ReportFees(UInt256 fees, UInt256 burntFees) {}
// private ITxTracer _currentTxTracer = NullTxTracer.Instance;
protected int _currentIndex { get; private set; }
// private readonly List _txReceipts = new();
- private readonly List _accesses = [];
+ private BlockAccessList _bal = new();
protected Transaction? CurrentTx;
- public IReadOnlyList Accesses => _accesses;
- // public IReadOnlyList TxReceipts => _txReceipts;
+ public BlockAccessList BlockAccessList => _bal;
// public TxReceipt LastReceipt => _txReceipts[^1];
public bool IsTracingRewards => false;
// public ITxTracer InnerTracer => _currentTxTracer;
- public int TakeSnapshot() => _accesses.Count;
+ public int TakeSnapshot() => _bal.AccountChanges.Count;
public void Restore(int snapshot)
{
@@ -198,7 +190,7 @@ public void StartNewBlockTrace(Block block)
{
Block = block;
_currentIndex = 0;
- _accesses.Clear();
+ _bal = new();
}
public ITxTracer StartNewTxTrace(Transaction? tx)
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index a6e14d4907c..da71b1747bb 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -118,6 +118,8 @@ protected virtual TxReceipt[] ProcessBlock(
_stateProvider.Commit(spec, commitRoots: false);
+ BlockAccessList bal = ReceiptsTracer.GetTracer().BlockAccessList;
+
CalculateBlooms(receipts);
if (spec.IsEip4844Enabled)
@@ -153,8 +155,7 @@ protected virtual TxReceipt[] ProcessBlock(
}
header.Hash = header.CalculateHash();
- // create from block.AccountChanges and encode
- System.Collections.Generic.IReadOnlyList accesses = ReceiptsTracer.GetTracer().Accesses;
+ // RLP encode bal
body.BlockAccessList = [];
return receipts;
From ec347c17d64b33c0eac8f36f3fd2a13e63bc67c7 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 15 Aug 2025 13:15:10 +0100
Subject: [PATCH 010/215] call byte encode, move BAL to core
---
.../Nethermind.Blockchain/Tracing/BlockAccessTracer.cs | 1 +
.../Nethermind.Consensus/Processing/BlockProcessor.cs | 4 ++--
.../BlockAccessList.cs} | 6 ++++--
3 files changed, 7 insertions(+), 4 deletions(-)
rename src/Nethermind/{Nethermind.Blockchain/Tracing/BlockAccessLists.cs => Nethermind.Core/BlockAccessList.cs} (95%)
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
index bc841465a0a..a7b32afdbe8 100644
--- a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using Nethermind.Core;
+using Nethermind.Core.BlockAccessLists;
using Nethermind.Core.Crypto;
using Nethermind.Evm;
using Nethermind.Evm.Tracing;
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index da71b1747bb..f41d34de2e2 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -15,6 +15,7 @@
using Nethermind.Consensus.Validators;
using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
+using Nethermind.Core.BlockAccessLists;
using Nethermind.Core.Specs;
using Nethermind.Core.Threading;
using Nethermind.Crypto;
@@ -155,8 +156,7 @@ protected virtual TxReceipt[] ProcessBlock(
}
header.Hash = header.CalculateHash();
- // RLP encode bal
- body.BlockAccessList = [];
+ body.BlockAccessList = bal.Bytes;
return receipts;
}
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessLists.cs b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
similarity index 95%
rename from src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessLists.cs
rename to src/Nethermind/Nethermind.Core/BlockAccessList.cs
index cd9157c396e..f597fe9f8d5 100644
--- a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessLists.cs
+++ b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
@@ -3,9 +3,8 @@
using System;
using System.Collections.Generic;
-using Nethermind.Core;
-namespace Nethermind.Blockchain.Tracing;
+namespace Nethermind.Core.BlockAccessLists;
// Single storage write: tx_index -> new_value
public struct StorageChange
@@ -83,4 +82,7 @@ public struct BlockAccessList
{
// [SszList(Eip7928Constants.MaxAccounts)]
public Dictionary AccountChanges { get; set; }
+
+ // RLP encode bal
+ public byte[] Bytes => [];
}
From 675485ce18ed7cec398e1d03d9e13d2fac7b78b8 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Mon, 18 Aug 2025 14:45:27 +0100
Subject: [PATCH 011/215] block access tracer improvements & tests
---
.../BlockAccessListTests.cs | 80 +++++++++++++++++++
.../TransactionProcessorTests.cs | 10 +--
.../Tracing/BlockAccessTracer.cs | 56 +++++++++++--
.../Nethermind.Core/BlockAccessList.cs | 23 +++---
.../TransactionProcessor.cs | 1 +
5 files changed, 146 insertions(+), 24 deletions(-)
create mode 100644 src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
new file mode 100644
index 00000000000..8cd90d36997
--- /dev/null
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -0,0 +1,80 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Collections.Generic;
+using Nethermind.Blockchain.Tracing;
+using Nethermind.Core;
+using Nethermind.Core.BlockAccessLists;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Int256;
+using NUnit.Framework;
+
+//move all to correct folder
+namespace Nethermind.Evm.Test
+{
+ [TestFixture]
+ public class BlockAccessListTests() : TransactionProcessorTests(true)
+ {
+ [Test]
+ public void Empty_account_changes()
+ {
+ Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject).TestObject;
+
+ BlockAccessTracer tracer = new();
+ tracer.StartNewBlockTrace(block);
+ tracer.StartNewTxTrace(block.Transactions[0]);
+ tracer.MarkAsSuccess(TestItem.AddressA, 100, [], [], TestItem.KeccakF);
+
+ Assert.That(tracer.BlockAccessList.AccountChanges, Has.Count.EqualTo(0));
+ }
+
+ [Test]
+ public void Balance_and_nonce_changes()
+ {
+ ulong gasPrice = 2;
+ long gasLimit = 100000;
+ Transaction tx = Build.A.Transaction
+ .WithTo(TestItem.AddressB)
+ .WithSenderAddress(TestItem.AddressA)
+ .WithValue(0)
+ .WithGasPrice(gasPrice)
+ .WithGasLimit(gasLimit)
+ .TestObject;
+
+ Block block = Build.A.Block
+ .WithTransactions(tx)
+ .WithBaseFeePerGas(1)
+ .WithBeneficiary(TestItem.AddressC).TestObject;
+
+ BlockReceiptsTracer blockReceiptsTracer = new();
+ BlockAccessTracer accessTracer = new();
+ blockReceiptsTracer.SetOtherTracer(accessTracer);
+ Execute(tx, block, blockReceiptsTracer);
+
+ Dictionary accountChanges = accessTracer.BlockAccessList.AccountChanges;
+ Assert.That(accountChanges, Has.Count.EqualTo(3));
+
+ List senderBalanceChanges = accountChanges[TestItem.AddressA].BalanceChanges;
+ List senderNonceChanges = accountChanges[TestItem.AddressA].NonceChanges;
+ // refund?
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(senderBalanceChanges, Has.Count.EqualTo(2));
+ Assert.That(senderBalanceChanges[0].PostBalance, Is.EqualTo(AccountBalance - gasPrice * (ulong)gasLimit));
+ Assert.That(senderBalanceChanges[1].PostBalance, Is.EqualTo(AccountBalance - gasPrice * GasCostOf.Transaction));
+
+ Assert.That(senderNonceChanges, Has.Count.EqualTo(1));
+ Assert.That(senderNonceChanges[0].NewNonce, Is.EqualTo(1));
+
+ }
+
+ // zero balance change should not be recorded
+ List toBalanceChanges = accountChanges[TestItem.AddressB].BalanceChanges;
+ Assert.That(toBalanceChanges, Is.Empty);
+
+ List beneficiaryBalanceChanges = accountChanges[TestItem.AddressC].BalanceChanges;
+ Assert.That(beneficiaryBalanceChanges, Has.Count.EqualTo(1));
+ Assert.That(beneficiaryBalanceChanges[0].PostBalance, Is.EqualTo(new UInt256(GasCostOf.Transaction)));
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionProcessorTests.cs
index e515a2480ec..77392d405a6 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionProcessorTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionProcessorTests.cs
@@ -11,7 +11,6 @@
using Nethermind.Specs;
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
-using Nethermind.Db;
using Nethermind.Int256;
using Nethermind.Evm.Tracing;
using Nethermind.Blockchain.Tracing.GethStyle;
@@ -21,7 +20,6 @@
using Nethermind.Serialization.Json;
using Nethermind.Specs.Forks;
using Nethermind.Evm.State;
-using Nethermind.Trie.Pruning;
using NUnit.Framework;
using Nethermind.Config;
using System.Collections.Generic;
@@ -36,12 +34,12 @@ namespace Nethermind.Evm.Test;
[TestFixture(false)]
[Todo(Improve.Refactor, "Check why fixture test cases did not work")]
[Parallelizable(ParallelScope.Self)]
-public class TransactionProcessorTests
+public abstract class TransactionProcessorTests
{
private readonly bool _isEip155Enabled;
private readonly ISpecProvider _specProvider;
private IEthereumEcdsa _ethereumEcdsa;
- private ITransactionProcessor _transactionProcessor;
+ protected ITransactionProcessor _transactionProcessor;
private IWorldState _stateProvider;
public TransactionProcessorTests(bool eip155Enabled)
@@ -50,7 +48,7 @@ public TransactionProcessorTests(bool eip155Enabled)
_specProvider = MainnetSpecProvider.Instance;
}
- private static readonly UInt256 AccountBalance = 1.Ether();
+ protected static readonly UInt256 AccountBalance = 1.Ether();
[SetUp]
public void Setup()
@@ -735,7 +733,7 @@ private BlockReceiptsTracer BuildTracer(Block block, Transaction tx, bool stateD
return tracer;
}
- private TransactionResult Execute(Transaction tx, Block block, BlockReceiptsTracer? tracer = null)
+ protected TransactionResult Execute(Transaction tx, Block block, BlockReceiptsTracer? tracer = null)
{
tracer?.StartNewBlockTrace(block);
tracer?.StartNewTxTrace(tx);
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
index a7b32afdbe8..7f1174ecbc9 100644
--- a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
@@ -73,9 +73,23 @@ public void ReportBalanceChange(Address address, UInt256? before, UInt256? after
BalanceChange balanceChange = new()
{
TxIndex = (ushort)_currentIndex,
- PostBalance = (ulong)after // why not 256 bit?
+ // PostBalance = (ulong)after // why not 256 bit?
+ PostBalance = after!.Value
};
- _bal.AccountChanges[address].BalanceChanges.Add(balanceChange);
+
+ if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
+ {
+ accountChanges = new(address);
+ _bal.AccountChanges.Add(address, accountChanges);
+ }
+
+ // show should refunds be handled?
+
+ // don't add zero balance transfers, but add empty account changes
+ if ((before ?? 0) != after)
+ {
+ accountChanges.BalanceChanges.Add(balanceChange);
+ }
}
public void ReportCodeChange(Address address, byte[] before, byte[] after)
@@ -85,7 +99,14 @@ public void ReportCodeChange(Address address, byte[] before, byte[] after)
TxIndex = (ushort)_currentIndex,
NewCode = after
};
- _bal.AccountChanges[address].CodeChanges.Add(codeChange);
+
+ if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
+ {
+ accountChanges = new(address);
+ _bal.AccountChanges.Add(address, accountChanges);
+ }
+
+ accountChanges.CodeChanges.Add(codeChange);
}
public void ReportNonceChange(Address address, UInt256? before, UInt256? after)
@@ -95,14 +116,21 @@ public void ReportNonceChange(Address address, UInt256? before, UInt256? after)
TxIndex = (ushort)_currentIndex,
NewNonce = (ulong)after
};
- _bal.AccountChanges[address].NonceChanges.Add(nonceChange);
+
+ if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
+ {
+ accountChanges = new(address);
+ _bal.AccountChanges.Add(address, accountChanges);
+ }
+
+ accountChanges.NonceChanges.Add(nonceChange);
}
public void ReportAccountRead(Address address)
{
if (!_bal.AccountChanges.ContainsKey(address))
{
- _bal.AccountChanges.Add(address, new());
+ _bal.AccountChanges.Add(address, new(address));
}
}
@@ -114,7 +142,14 @@ public void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[
NewValue = after
};
Address address = Address.Zero;
- _bal.AccountChanges[address].StorageChanges.Add(storageChange);
+
+ if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
+ {
+ accountChanges = new(address);
+ _bal.AccountChanges.Add(address, accountChanges);
+ }
+
+ accountChanges.StorageChanges.Add(storageChange);
}
public void ReportStorageRead(in StorageCell storageCell)
@@ -124,7 +159,14 @@ public void ReportStorageRead(in StorageCell storageCell)
Key = storageCell.Hash.ToByteArray()
};
Address address = Address.Zero;
- _bal.AccountChanges[address].StorageReads.Add(storageKey);
+
+ if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
+ {
+ accountChanges = new(address);
+ _bal.AccountChanges.Add(address, accountChanges);
+ }
+
+ accountChanges.StorageReads.Add(storageKey);
}
public void ReportAction(long gas, UInt256 value, Address from, Address to, ReadOnlyMemory input, ExecutionType callType, bool isPrecompileCall = false) {}
diff --git a/src/Nethermind/Nethermind.Core/BlockAccessList.cs b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
index f597fe9f8d5..1db7a375963 100644
--- a/src/Nethermind/Nethermind.Core/BlockAccessList.cs
+++ b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
@@ -1,8 +1,8 @@
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
-using System;
using System.Collections.Generic;
+using Nethermind.Int256;
namespace Nethermind.Core.BlockAccessLists;
@@ -18,7 +18,8 @@ public struct StorageChange
public struct BalanceChange
{
public ushort TxIndex { get; set; }
- public UInt128 PostBalance { get; set; }
+ // actually UInt128
+ public UInt256 PostBalance { get; set; }
}
// Single nonce change: tx_index -> new_nonce
@@ -52,36 +53,36 @@ public struct StorageKey
public byte[] Key { get; set; }
}
-public struct AccountChanges
+public struct AccountChanges(Address address)
{
// [SszVector(20)]
- public byte[] Address { get; set; }
+ public byte[] Address { get; set; } = address.Bytes;
// Storage changes (slot -> [tx_index -> new_value])
// [SszList(Eip7928Constants.MaxSlots)]
- public List StorageChanges { get; set; }
+ public List StorageChanges { get; set; } = [];
// Read-only storage keys
// [SszList(Eip7928Constants.MaxSlots)]
- public List StorageReads { get; set; }
+ public List StorageReads { get; set; } = [];
// Balance changes ([tx_index -> post_balance])
// [SszList(Eip7928Constants.MaxTxs)]
- public List BalanceChanges { get; set; }
+ public List BalanceChanges { get; set; } = [];
// Nonce changes ([tx_index -> new_nonce])
// [SszList(Eip7928Constants.MaxTxs)]
- public List NonceChanges { get; set; }
+ public List NonceChanges { get; set; } = [];
// Code changes ([tx_index -> new_code])
// [SszList(Eip7928Constants.MaxCodeChanges)]
- public List CodeChanges { get; set; }
+ public List CodeChanges { get; set; } = [];
}
-public struct BlockAccessList
+public struct BlockAccessList()
{
// [SszList(Eip7928Constants.MaxAccounts)]
- public Dictionary AccountChanges { get; set; }
+ public Dictionary AccountChanges { get; set; } = [];
// RLP encode bal
public byte[] Bytes => [];
diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs
index 0e5458317f6..51e09fd8efa 100644
--- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs
+++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs
@@ -867,6 +867,7 @@ protected virtual GasConsumed Refund(Transaction tx, BlockHeader header, IReleas
spentGas = Math.Max(spentGas, floorGas);
// If noValidation we didn't charge for gas, so do not refund
+ // report to tracer??
if (!opts.HasFlag(ExecutionOptions.SkipValidation))
WorldState.AddToBalance(tx.SenderAddress!, (ulong)(tx.GasLimit - spentGas) * gasPrice, spec);
From 65bcb30501b349668595a3df495a239e70f7d315 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Mon, 18 Aug 2025 19:08:20 +0100
Subject: [PATCH 012/215] add to execution payload
---
src/Nethermind/Nethermind.Core/Block.cs | 7 +++++--
.../Nethermind.Merge.Plugin/Data/ExecutionPayload.cs | 8 +++++---
src/Nethermind/Nethermind.State/StateProvider.cs | 1 +
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/Nethermind/Nethermind.Core/Block.cs b/src/Nethermind/Nethermind.Core/Block.cs
index 6c25efae61d..a064acc71b2 100644
--- a/src/Nethermind/Nethermind.Core/Block.cs
+++ b/src/Nethermind/Nethermind.Core/Block.cs
@@ -12,6 +12,8 @@
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Int256;
+using Nethermind.Core.BlockAccessLists;
+using Nethermind.Serialization.Json;
namespace Nethermind.Core;
@@ -27,10 +29,11 @@ public Block(BlockHeader header, BlockBody body)
public Block(BlockHeader header,
IEnumerable transactions,
IEnumerable uncles,
- IEnumerable? withdrawals = null)
+ IEnumerable? withdrawals = null,
+ byte[]? blockAccessList = null)
{
Header = header ?? throw new ArgumentNullException(nameof(header));
- Body = new(transactions.ToArray(), uncles.ToArray(), withdrawals?.ToArray());
+ Body = new(transactions.ToArray(), uncles.ToArray(), withdrawals?.ToArray(), blockAccessList);
}
public Block(BlockHeader header) : this(
diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayload.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayload.cs
index 6e958ad8079..a3bbb7eb2e4 100644
--- a/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayload.cs
+++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayload.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
-using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Nethermind.Core;
using Nethermind.Core.Crypto;
@@ -12,7 +11,6 @@
using Nethermind.Serialization.Rlp;
using Nethermind.State.Proofs;
using System.Text.Json.Serialization;
-using Microsoft.AspNetCore.Server.Kestrel.Transport.Quic;
using Nethermind.Core.ExecutionRequest;
namespace Nethermind.Merge.Plugin.Data;
@@ -53,6 +51,8 @@ public class ExecutionPayload : IForkValidator, IExecutionPayloadParams, IExecut
public ulong Timestamp { get; set; }
+ public byte[] BlockAccessList { get; set; } = [];
+
protected byte[][] _encodedTransactions = [];
///
@@ -126,6 +126,7 @@ public byte[][] Transactions
Timestamp = block.Timestamp,
BaseFeePerGas = block.BaseFeePerGas,
Withdrawals = block.Withdrawals,
+ BlockAccessList = block.BlockAccessList!,
};
executionPayload.SetTransactions(block.Transactions);
return executionPayload;
@@ -168,9 +169,10 @@ public virtual BlockDecodingResult TryGetBlock(UInt256? totalDifficulty = null)
TotalDifficulty = totalDifficulty,
TxRoot = TxTrie.CalculateRoot(transactions.Transactions),
WithdrawalsRoot = BuildWithdrawalsRoot(),
+ BlockAccessListHash = new Hash256(BlockAccessList) //valuehash
};
- return new BlockDecodingResult(new Block(header, transactions.Transactions, Array.Empty(), Withdrawals));
+ return new BlockDecodingResult(new Block(header, transactions.Transactions, Array.Empty(), Withdrawals, BlockAccessList));
}
protected virtual Hash256? BuildWithdrawalsRoot()
diff --git a/src/Nethermind/Nethermind.State/StateProvider.cs b/src/Nethermind/Nethermind.State/StateProvider.cs
index 549792456cb..5167e75cbc4 100644
--- a/src/Nethermind/Nethermind.State/StateProvider.cs
+++ b/src/Nethermind/Nethermind.State/StateProvider.cs
@@ -57,6 +57,7 @@ internal class StateProvider
private readonly bool _populatePreBlockCache;
private bool _needsStateRootUpdate;
+ // get from block access list
public StateProvider(IScopedTrieStore? trieStore,
IKeyValueStoreWithBatching codeDb,
ILogManager logManager,
From 4cd315bf0a904a45ba83217a22f2e310ab54556f Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 19 Aug 2025 11:02:49 +0100
Subject: [PATCH 013/215] update structures
---
.../BlockAccessListTests.cs | 2 +-
.../Tracing/BlockAccessTracer.cs | 9 ++++----
.../Nethermind.Core/BlockAccessList.cs | 21 ++++++++++---------
3 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index 8cd90d36997..4e33f9b5f2c 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -51,7 +51,7 @@ public void Balance_and_nonce_changes()
blockReceiptsTracer.SetOtherTracer(accessTracer);
Execute(tx, block, blockReceiptsTracer);
- Dictionary accountChanges = accessTracer.BlockAccessList.AccountChanges;
+ SortedDictionary accountChanges = accessTracer.BlockAccessList.AccountChanges;
Assert.That(accountChanges, Has.Count.EqualTo(3));
List senderBalanceChanges = accountChanges[TestItem.AddressA].BalanceChanges;
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
index 7f1174ecbc9..e728f9d58fc 100644
--- a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
@@ -72,8 +72,7 @@ public void ReportBalanceChange(Address address, UInt256? before, UInt256? after
{
BalanceChange balanceChange = new()
{
- TxIndex = (ushort)_currentIndex,
- // PostBalance = (ulong)after // why not 256 bit?
+ BlockAccessIndex = (ushort)_currentIndex,
PostBalance = after!.Value
};
@@ -96,7 +95,7 @@ public void ReportCodeChange(Address address, byte[] before, byte[] after)
{
CodeChange codeChange = new()
{
- TxIndex = (ushort)_currentIndex,
+ BlockAccessIndex = (ushort)_currentIndex,
NewCode = after
};
@@ -113,7 +112,7 @@ public void ReportNonceChange(Address address, UInt256? before, UInt256? after)
{
NonceChange nonceChange = new()
{
- TxIndex = (ushort)_currentIndex,
+ BlockAccessIndex = (ushort)_currentIndex,
NewNonce = (ulong)after
};
@@ -138,7 +137,7 @@ public void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[
{
StorageChange storageChange = new()
{
- TxIndex = (ushort)_currentIndex,
+ BlockAccessIndex = (ushort)_currentIndex,
NewValue = after
};
Address address = Address.Zero;
diff --git a/src/Nethermind/Nethermind.Core/BlockAccessList.cs b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
index 1db7a375963..ff6af62b787 100644
--- a/src/Nethermind/Nethermind.Core/BlockAccessList.cs
+++ b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
@@ -6,38 +6,39 @@
namespace Nethermind.Core.BlockAccessLists;
-// Single storage write: tx_index -> new_value
+// # StorageChange: [block_access_index, new_value]
public struct StorageChange
{
- public ushort TxIndex { get; set; }
+ public ushort BlockAccessIndex { get; set; }
// [SszVector(32)]
public byte[] NewValue { get; set; }
}
-// Single balance change: tx_index -> post_balance
+// BalanceChange: [block_access_index, post_balance]
public struct BalanceChange
{
- public ushort TxIndex { get; set; }
- // actually UInt128
+ public ushort BlockAccessIndex { get; set; }
public UInt256 PostBalance { get; set; }
}
-// Single nonce change: tx_index -> new_nonce
+// NonceChange: [block_access_index, new_nonce]
public struct NonceChange
{
- public ushort TxIndex { get; set; }
+ public ushort BlockAccessIndex { get; set; }
public ulong NewNonce { get; set; }
}
-// Single code change: tx_index -> new_code
+// CodeChange: [block_access_index, new_code]
public struct CodeChange
{
- public ushort TxIndex { get; set; }
+ public ushort BlockAccessIndex { get; set; }
// [SszList(Eip7928Constants.MaxCodeSize)]
public byte[] NewCode { get; set; }
}
+// SlotChanges: [slot, [changes]]
+// All changes to a single storage slot
public struct SlotChanges
{
// [SszVector(32)]
@@ -82,7 +83,7 @@ public struct AccountChanges(Address address)
public struct BlockAccessList()
{
// [SszList(Eip7928Constants.MaxAccounts)]
- public Dictionary AccountChanges { get; set; } = [];
+ public SortedDictionary AccountChanges { get; set; } = [];
// RLP encode bal
public byte[] Bytes => [];
From 6f9aabf54c9fe41afcaf21662ae45b0957785a3d Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 19 Aug 2025 11:48:14 +0100
Subject: [PATCH 014/215] only record last change of each tx
---
.../Tracing/BlockAccessTracer.cs | 87 ++++++++++++++-----
.../Nethermind.Core/BlockAccessList.cs | 13 +--
2 files changed, 73 insertions(+), 27 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
index e728f9d58fc..ffbdbb9fd7f 100644
--- a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Nethermind.Core;
using Nethermind.Core.BlockAccessLists;
using Nethermind.Core.Crypto;
@@ -57,11 +58,6 @@ public void SetOperationMemorySize(ulong newSize) {}
public void ReportMemoryChange(long offset, in ReadOnlySpan data) {}
- public void ReportStorageChange(in ReadOnlySpan key, in ReadOnlySpan value)
- {
- //_bal.AccountChanges[].StorageChanges()
- }
-
public void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue) {}
public void LoadOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan value) {}
@@ -72,7 +68,7 @@ public void ReportBalanceChange(Address address, UInt256? before, UInt256? after
{
BalanceChange balanceChange = new()
{
- BlockAccessIndex = (ushort)_currentIndex,
+ BlockAccessIndex = _blockAccessIndex,
PostBalance = after!.Value
};
@@ -85,17 +81,24 @@ public void ReportBalanceChange(Address address, UInt256? before, UInt256? after
// show should refunds be handled?
// don't add zero balance transfers, but add empty account changes
- if ((before ?? 0) != after)
+ if ((before ?? 0) == after)
+ {
+ return;
+ }
+
+ List balanceChanges = accountChanges.BalanceChanges;
+ if (balanceChanges is not [] && balanceChanges[^1].BlockAccessIndex == _blockAccessIndex)
{
- accountChanges.BalanceChanges.Add(balanceChange);
+ balanceChanges.RemoveAt(balanceChanges.Count - 1);
}
+ balanceChanges.Add(balanceChange);
}
public void ReportCodeChange(Address address, byte[] before, byte[] after)
{
CodeChange codeChange = new()
{
- BlockAccessIndex = (ushort)_currentIndex,
+ BlockAccessIndex = _blockAccessIndex,
NewCode = after
};
@@ -105,14 +108,19 @@ public void ReportCodeChange(Address address, byte[] before, byte[] after)
_bal.AccountChanges.Add(address, accountChanges);
}
- accountChanges.CodeChanges.Add(codeChange);
+ List codeChanges = accountChanges.CodeChanges;
+ if (codeChanges is not [] && codeChanges[^1].BlockAccessIndex == _blockAccessIndex)
+ {
+ codeChanges.RemoveAt(codeChanges.Count - 1);
+ }
+ codeChanges.Add(codeChange);
}
public void ReportNonceChange(Address address, UInt256? before, UInt256? after)
{
NonceChange nonceChange = new()
{
- BlockAccessIndex = (ushort)_currentIndex,
+ BlockAccessIndex = _blockAccessIndex,
NewNonce = (ulong)after
};
@@ -122,7 +130,12 @@ public void ReportNonceChange(Address address, UInt256? before, UInt256? after)
_bal.AccountChanges.Add(address, accountChanges);
}
- accountChanges.NonceChanges.Add(nonceChange);
+ List nonceChanges = accountChanges.NonceChanges;
+ if (nonceChanges is not [] && nonceChanges[^1].BlockAccessIndex == _blockAccessIndex)
+ {
+ nonceChanges.RemoveAt(nonceChanges.Count - 1);
+ }
+ nonceChanges.Add(nonceChange);
}
public void ReportAccountRead(Address address)
@@ -133,13 +146,22 @@ public void ReportAccountRead(Address address)
}
}
- public void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[] after)
+ public void ReportStorageChange(in ReadOnlySpan key, in ReadOnlySpan value)
{
- StorageChange storageChange = new()
+ // get address?
+ Address address = Address.Zero;
+
+ if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
{
- BlockAccessIndex = (ushort)_currentIndex,
- NewValue = after
- };
+ accountChanges = new(address);
+ _bal.AccountChanges.Add(address, accountChanges);
+ }
+
+ StorageChange(accountChanges, key, value);
+ }
+
+ public void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[] after)
+ {
Address address = Address.Zero;
if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
@@ -148,7 +170,30 @@ public void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[
_bal.AccountChanges.Add(address, accountChanges);
}
- accountChanges.StorageChanges.Add(storageChange);
+ if (!Enumerable.SequenceEqual(before, after))
+ {
+ StorageChange(accountChanges, storageCell.Hash.BytesAsSpan, after.AsSpan());
+ }
+ }
+
+ private void StorageChange(AccountChanges accountChanges, in ReadOnlySpan key, in ReadOnlySpan value)
+ {
+ StorageChange storageChange = new()
+ {
+ BlockAccessIndex = _blockAccessIndex,
+ NewValue = value.ToArray()
+ };
+
+ StorageKey storageKey = new(key);
+ if (!accountChanges.StorageChanges.TryGetValue(storageKey, out SlotChanges storageChanges))
+ {
+ storageChanges = new();
+ }
+ else if (storageChanges.Changes is not [] && storageChanges.Changes[^1].BlockAccessIndex == _blockAccessIndex)
+ {
+ storageChanges.Changes.RemoveAt(storageChanges.Changes.Count - 1);
+ }
+ storageChanges.Changes.Add(storageChange);
}
public void ReportStorageRead(in StorageCell storageCell)
@@ -202,7 +247,7 @@ public void SetOperationMemory(TraceMemory memoryTrace) {}
public void ReportFees(UInt256 fees, UInt256 burntFees) {}
// private ITxTracer _currentTxTracer = NullTxTracer.Instance;
- protected int _currentIndex { get; private set; }
+ private ushort _blockAccessIndex = 1;
// private readonly List _txReceipts = new();
private BlockAccessList _bal = new();
protected Transaction? CurrentTx;
@@ -231,7 +276,7 @@ public void ReportReward(Address author, string rewardType, UInt256 rewardValue)
public void StartNewBlockTrace(Block block)
{
Block = block;
- _currentIndex = 0;
+ _blockAccessIndex = 1;
_bal = new();
}
@@ -242,7 +287,7 @@ public ITxTracer StartNewTxTrace(Transaction? tx)
public void EndTxTrace()
{
- _currentIndex++;
+ _blockAccessIndex++;
}
public void EndBlockTrace()
diff --git a/src/Nethermind/Nethermind.Core/BlockAccessList.cs b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
index ff6af62b787..0bd42a06b3d 100644
--- a/src/Nethermind/Nethermind.Core/BlockAccessList.cs
+++ b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System;
using System.Collections.Generic;
using Nethermind.Int256;
@@ -39,19 +40,19 @@ public struct CodeChange
// SlotChanges: [slot, [changes]]
// All changes to a single storage slot
-public struct SlotChanges
+public struct SlotChanges()
{
// [SszVector(32)]
- public byte[] Slot { get; set; }
+ // public byte[] Slot { get; set; }
// [SszList(Eip7928Constants.MaxTxs)]
- public ulong Changes { get; set; }
+ public List Changes { get; set; } = [];
}
-public struct StorageKey
+public struct StorageKey(ReadOnlySpan key)
{
// [SszVector(32)]
- public byte[] Key { get; set; }
+ public byte[] Key { get; set; } = key.ToArray();
}
public struct AccountChanges(Address address)
@@ -61,7 +62,7 @@ public struct AccountChanges(Address address)
// Storage changes (slot -> [tx_index -> new_value])
// [SszList(Eip7928Constants.MaxSlots)]
- public List StorageChanges { get; set; } = [];
+ public SortedDictionary StorageChanges { get; set; } = [];
// Read-only storage keys
// [SszList(Eip7928Constants.MaxSlots)]
From d884b36db1c299127a2a426fc157b0052056ac62 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 19 Aug 2025 11:54:52 +0100
Subject: [PATCH 015/215] fix test
---
.../BlockAccessListTests.cs | 22 +++++++++----------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index 4e33f9b5f2c..5a94de1ee71 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -56,25 +56,23 @@ public void Balance_and_nonce_changes()
List senderBalanceChanges = accountChanges[TestItem.AddressA].BalanceChanges;
List senderNonceChanges = accountChanges[TestItem.AddressA].NonceChanges;
- // refund?
+ List toBalanceChanges = accountChanges[TestItem.AddressB].BalanceChanges;
+ List beneficiaryBalanceChanges = accountChanges[TestItem.AddressC].BalanceChanges;
+
using (Assert.EnterMultipleScope())
{
- Assert.That(senderBalanceChanges, Has.Count.EqualTo(2));
- Assert.That(senderBalanceChanges[0].PostBalance, Is.EqualTo(AccountBalance - gasPrice * (ulong)gasLimit));
- Assert.That(senderBalanceChanges[1].PostBalance, Is.EqualTo(AccountBalance - gasPrice * GasCostOf.Transaction));
+ Assert.That(senderBalanceChanges, Has.Count.EqualTo(1));
+ Assert.That(senderBalanceChanges[0].PostBalance, Is.EqualTo(AccountBalance - gasPrice * GasCostOf.Transaction));
Assert.That(senderNonceChanges, Has.Count.EqualTo(1));
Assert.That(senderNonceChanges[0].NewNonce, Is.EqualTo(1));
- }
-
- // zero balance change should not be recorded
- List toBalanceChanges = accountChanges[TestItem.AddressB].BalanceChanges;
- Assert.That(toBalanceChanges, Is.Empty);
+ // zero balance change should not be recorded
+ Assert.That(toBalanceChanges, Is.Empty);
- List beneficiaryBalanceChanges = accountChanges[TestItem.AddressC].BalanceChanges;
- Assert.That(beneficiaryBalanceChanges, Has.Count.EqualTo(1));
- Assert.That(beneficiaryBalanceChanges[0].PostBalance, Is.EqualTo(new UInt256(GasCostOf.Transaction)));
+ Assert.That(beneficiaryBalanceChanges, Has.Count.EqualTo(1));
+ Assert.That(beneficiaryBalanceChanges[0].PostBalance, Is.EqualTo(new UInt256(GasCostOf.Transaction)));
+ }
}
}
}
From 0eb0736c1705b1bbcd08ef07e072d0d1674005dc Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 19 Aug 2025 12:06:40 +0100
Subject: [PATCH 016/215] change storage tracing
---
.../Tracing/BlockAccessTracer.cs | 68 ++++++++++---------
1 file changed, 36 insertions(+), 32 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
index ffbdbb9fd7f..ee791fee743 100644
--- a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
@@ -58,7 +58,19 @@ public void SetOperationMemorySize(ulong newSize) {}
public void ReportMemoryChange(long offset, in ReadOnlySpan data) {}
- public void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue) {}
+ public void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue)
+ {
+ if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
+ {
+ accountChanges = new(address);
+ _bal.AccountChanges.Add(address, accountChanges);
+ }
+
+ if (currentValue != newValue)
+ {
+ StorageChange(accountChanges, new StorageCell(address, storageIndex).Hash.BytesAsSpan, newValue);
+ }
+ }
public void LoadOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan value) {}
@@ -148,21 +160,12 @@ public void ReportAccountRead(Address address)
public void ReportStorageChange(in ReadOnlySpan key, in ReadOnlySpan value)
{
- // get address?
- Address address = Address.Zero;
-
- if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
- {
- accountChanges = new(address);
- _bal.AccountChanges.Add(address, accountChanges);
- }
-
- StorageChange(accountChanges, key, value);
+ // no address
}
public void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[] after)
{
- Address address = Address.Zero;
+ Address address = storageCell.Address;
if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
{
@@ -176,26 +179,6 @@ public void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[
}
}
- private void StorageChange(AccountChanges accountChanges, in ReadOnlySpan key, in ReadOnlySpan value)
- {
- StorageChange storageChange = new()
- {
- BlockAccessIndex = _blockAccessIndex,
- NewValue = value.ToArray()
- };
-
- StorageKey storageKey = new(key);
- if (!accountChanges.StorageChanges.TryGetValue(storageKey, out SlotChanges storageChanges))
- {
- storageChanges = new();
- }
- else if (storageChanges.Changes is not [] && storageChanges.Changes[^1].BlockAccessIndex == _blockAccessIndex)
- {
- storageChanges.Changes.RemoveAt(storageChanges.Changes.Count - 1);
- }
- storageChanges.Changes.Add(storageChange);
- }
-
public void ReportStorageRead(in StorageCell storageCell)
{
StorageKey storageKey = new()
@@ -314,4 +297,25 @@ public void Dispose()
{
// _currentTxTracer.Dispose();
}
+
+ private void StorageChange(AccountChanges accountChanges, in ReadOnlySpan key, in ReadOnlySpan value)
+ {
+ StorageChange storageChange = new()
+ {
+ BlockAccessIndex = _blockAccessIndex,
+ NewValue = value.ToArray()
+ };
+
+ StorageKey storageKey = new(key);
+ if (!accountChanges.StorageChanges.TryGetValue(storageKey, out SlotChanges storageChanges))
+ {
+ storageChanges = new();
+ }
+ else if (storageChanges.Changes is not [] && storageChanges.Changes[^1].BlockAccessIndex == _blockAccessIndex)
+ {
+ storageChanges.Changes.RemoveAt(storageChanges.Changes.Count - 1);
+ }
+ storageChanges.Changes.Add(storageChange);
+ }
+
}
From 603d56a163c40bffedb4076a73043c55ee3a084f Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 19 Aug 2025 14:50:28 +0100
Subject: [PATCH 017/215] RLP encode bal
---
.../Nethermind.Consensus/Processing/BlockProcessor.cs | 3 ++-
src/Nethermind/Nethermind.Core/BlockAccessList.cs | 3 ---
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index f41d34de2e2..a5aeb87cbd3 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -24,6 +24,7 @@
using Nethermind.Evm.Tracing;
using Nethermind.Int256;
using Nethermind.Logging;
+using Nethermind.Serialization.Rlp;
using Nethermind.Specs.Forks;
using Nethermind.State;
using static Nethermind.Consensus.Processing.IBlockProcessor;
@@ -156,7 +157,7 @@ protected virtual TxReceipt[] ProcessBlock(
}
header.Hash = header.CalculateHash();
- body.BlockAccessList = bal.Bytes;
+ body.BlockAccessList = Rlp.Encode(bal).Bytes;
return receipts;
}
diff --git a/src/Nethermind/Nethermind.Core/BlockAccessList.cs b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
index 0bd42a06b3d..8d3e53442bd 100644
--- a/src/Nethermind/Nethermind.Core/BlockAccessList.cs
+++ b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
@@ -85,7 +85,4 @@ public struct BlockAccessList()
{
// [SszList(Eip7928Constants.MaxAccounts)]
public SortedDictionary AccountChanges { get; set; } = [];
-
- // RLP encode bal
- public byte[] Bytes => [];
}
From 1726b9b343149cd8871fbb982dedd76eb15ed3ef Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 19 Aug 2025 15:13:47 +0100
Subject: [PATCH 018/215] prewarm addresses
---
.../Processing/BlockCachePreWarmer.cs | 85 +++++++++++++------
src/Nethermind/Nethermind.Core/Block.cs | 1 +
2 files changed, 58 insertions(+), 28 deletions(-)
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs
index 951b704f84b..0bab7208dac 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs
@@ -21,6 +21,8 @@
using Nethermind.Core.Collections;
using Nethermind.State;
using Nethermind.Trie;
+using Nethermind.Serialization.Rlp;
+using Nethermind.Core.BlockAccessLists;
namespace Nethermind.Consensus.Processing;
@@ -276,7 +278,7 @@ private void WarmupAddresses(ParallelOptions parallelOptions, Block block)
{
if (SystemTxAccessLists is not null)
{
- var env = envPool.Get();
+ IReadOnlyTxProcessorSource env = envPool.Get();
try
{
using IReadOnlyTxProcessingScope scope = env.Build(parent);
@@ -293,56 +295,82 @@ private void WarmupAddresses(ParallelOptions parallelOptions, Block block)
}
}
- AddressWarmingState baseState = new(envPool, block, parent);
-
- ParallelUnbalancedWork.For(
- 0,
- block.Transactions.Length,
- parallelOptions,
- baseState.InitThreadState,
- static (i, state) =>
+ WarmupTransactionAddresses(envPool, block.Transactions, true);
+ if (block.BlockAccessList is not null)
{
- Transaction tx = state.Block.Transactions[i];
- Address? sender = tx.SenderAddress;
-
+ block.DecodedBlockAccessList = Rlp.Decode(block.BlockAccessList);
+ IReadOnlyTxProcessorSource env = envPool.Get();
try
{
- if (sender is not null)
- {
- state.Scope.WorldState.WarmUp(sender);
- }
+ using IReadOnlyTxProcessingScope scope = env.Build(parent);
- Address to = tx.To;
- if (to is not null)
+ foreach (Address address in block.DecodedBlockAccessList.Value.AccountChanges.Keys)
{
- state.Scope.WorldState.WarmUp(to);
+ scope.WorldState.WarmUp(address);
}
+
+ // warmup storage locations
}
- catch (MissingTrieNodeException)
+ finally
{
+ envPool.Return(env);
}
-
- return state;
- },
- AddressWarmingState.FinallyAction);
+ }
}
catch (OperationCanceledException)
{
// Ignore, block completed cancel
}
}
+
+ private void WarmupTransactionAddresses(ObjectPool envPool, Transaction[] transactions, bool warmToAddress)
+ {
+ AddressWarmingState baseState = new(envPool, transactions, parent, warmToAddress);
+
+ ParallelUnbalancedWork.For(
+ 0,
+ transactions.Length,
+ parallelOptions,
+ baseState.InitThreadState,
+ static (i, state) =>
+ {
+ Transaction tx = state.Transactions[i];
+ Address? sender = tx.SenderAddress;
+
+ try
+ {
+ if (sender is not null)
+ {
+ state.Scope.WorldState.WarmUp(sender);
+ }
+
+ Address? to = state.WarmToAddress ? null : tx.To;
+ if (to is not null)
+ {
+ state.Scope.WorldState.WarmUp(to);
+ }
+ }
+ catch (MissingTrieNodeException)
+ {
+ }
+
+ return state;
+ },
+ AddressWarmingState.FinallyAction);
+ }
}
- private readonly struct AddressWarmingState(ObjectPool envPool, Block block, BlockHeader parent) : IDisposable
+ private readonly struct AddressWarmingState(ObjectPool envPool, Transaction[] transactions, BlockHeader parent, bool warmToAddress) : IDisposable
{
public static Action FinallyAction { get; } = DisposeThreadState;
public readonly ObjectPool EnvPool = envPool;
- public readonly Block Block = block;
+ public readonly Transaction[] Transactions = transactions;
public readonly IReadOnlyTxProcessorSource? Env;
public readonly IReadOnlyTxProcessingScope? Scope;
+ public readonly bool WarmToAddress = warmToAddress;
- public AddressWarmingState(ObjectPool envPool, Block block, BlockHeader parent, IReadOnlyTxProcessorSource env, IReadOnlyTxProcessingScope scope) : this(envPool, block, parent)
+ public AddressWarmingState(ObjectPool envPool, Transaction[] transactions, BlockHeader parent, IReadOnlyTxProcessorSource env, IReadOnlyTxProcessingScope scope, bool warmToAddress) : this(envPool, transactions, parent, warmToAddress)
{
Env = env;
Scope = scope;
@@ -351,7 +379,8 @@ public AddressWarmingState(ObjectPool envPool, Block
public AddressWarmingState InitThreadState()
{
IReadOnlyTxProcessorSource env = EnvPool.Get();
- return new(EnvPool, Block, parent, env, scope: env.Build(parent));
+ IReadOnlyTxProcessingScope scope = env.Build(parent);
+ return new(EnvPool, Transactions, parent, env, scope, WarmToAddress);
}
public void Dispose()
diff --git a/src/Nethermind/Nethermind.Core/Block.cs b/src/Nethermind/Nethermind.Core/Block.cs
index a064acc71b2..7ee9f96a136 100644
--- a/src/Nethermind/Nethermind.Core/Block.cs
+++ b/src/Nethermind/Nethermind.Core/Block.cs
@@ -149,6 +149,7 @@ public Transaction[] Transactions
_ => ToShortHashAndNumber()
};
+ public BlockAccessList? DecodedBlockAccessList;
private string ExtraDataToString()
{
if (ExtraData is null)
From 8ac6add81a8c891af64b05b26f9fb47f030de25a Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 19 Aug 2025 15:55:21 +0100
Subject: [PATCH 019/215] use bal as state provider
---
...sor.BlockValidationTransactionsExecutor.cs | 8 +-
src/Nethermind/Nethermind.Core/Block.cs | 5 +-
.../Nethermind.State/BlockAccessWorldState.cs | 230 ++++++++++++++++++
3 files changed, 238 insertions(+), 5 deletions(-)
create mode 100644 src/Nethermind/Nethermind.State/BlockAccessWorldState.cs
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
index 7293bb5240b..d749f666498 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
@@ -4,7 +4,6 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using System.Linq;
using System.Threading;
using Nethermind.Blockchain;
using Nethermind.Blockchain.Tracing;
@@ -12,7 +11,7 @@
using Nethermind.Evm;
using Nethermind.Evm.State;
using Nethermind.Evm.TransactionProcessing;
-
+using Nethermind.State;
using Metrics = Nethermind.Evm.Metrics;
namespace Nethermind.Consensus.Processing
@@ -41,18 +40,19 @@ public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processing
Transaction currentTx = block.Transactions[i];
ProcessTransaction(block, currentTx, i, receiptsTracer, processingOptions);
}
- return receiptsTracer.TxReceipts.ToArray();
+ return [.. receiptsTracer.TxReceipts];
}
protected virtual void ProcessTransaction(Block block, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions)
{
+ BlockAccessWorldState blockAccessStateProvider = new(block.DecodedBlockAccessList!.Value, (ushort)(index + 1), stateProvider);
TransactionResult result = transactionProcessor.ProcessTransaction(currentTx, receiptsTracer, processingOptions, stateProvider);
if (!result) ThrowInvalidBlockException(result, block.Header, currentTx, index);
TransactionProcessed?.Invoke(this, new TxProcessedEventArgs(index, currentTx, receiptsTracer.TxReceipts[index]));
}
[DoesNotReturn, StackTraceHidden]
- private void ThrowInvalidBlockException(TransactionResult result, BlockHeader header, Transaction currentTx, int index)
+ private static void ThrowInvalidBlockException(TransactionResult result, BlockHeader header, Transaction currentTx, int index)
{
throw new InvalidBlockException(header, $"Transaction {currentTx.Hash} at index {index} failed with error {result.Error}");
}
diff --git a/src/Nethermind/Nethermind.Core/Block.cs b/src/Nethermind/Nethermind.Core/Block.cs
index 7ee9f96a136..c9dde1df74c 100644
--- a/src/Nethermind/Nethermind.Core/Block.cs
+++ b/src/Nethermind/Nethermind.Core/Block.cs
@@ -131,6 +131,10 @@ public Transaction[] Transactions
public int? EncodedSize { get; set; }
+ [JsonIgnore]
+ public BlockAccessList? DecodedBlockAccessList { get; set; }
+
+
[JsonIgnore]
internal volatile int TransactionProcessed;
@@ -149,7 +153,6 @@ public Transaction[] Transactions
_ => ToShortHashAndNumber()
};
- public BlockAccessList? DecodedBlockAccessList;
private string ExtraDataToString()
{
if (ExtraData is null)
diff --git a/src/Nethermind/Nethermind.State/BlockAccessWorldState.cs b/src/Nethermind/Nethermind.State/BlockAccessWorldState.cs
new file mode 100644
index 00000000000..bfb452692d1
--- /dev/null
+++ b/src/Nethermind/Nethermind.State/BlockAccessWorldState.cs
@@ -0,0 +1,230 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using Nethermind.Core;
+using Nethermind.Core.BlockAccessLists;
+using Nethermind.Core.Collections;
+using Nethermind.Core.Crypto;
+using Nethermind.Core.Eip2930;
+using Nethermind.Core.Specs;
+using Nethermind.Evm.State;
+using Nethermind.Evm.Tracing.State;
+using Nethermind.Int256;
+
+namespace Nethermind.State;
+
+public class BlockAccessWorldState(BlockAccessList blockAccessList, ushort blockAccessIndex, IWorldState innerWorldState) : IWorldState
+{
+ public Hash256 StateRoot => throw new NotImplementedException();
+
+ public bool AccountExists(Address address)
+ => innerWorldState.AccountExists(address);
+
+ public void AddToBalance(Address address, in UInt256 balanceChange, IReleaseSpec spec)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool AddToBalanceAndCreateIfNotExists(Address address, in UInt256 balanceChange, IReleaseSpec spec)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void ClearStorage(Address address)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Commit(IReleaseSpec releaseSpec, bool isGenesis = false, bool commitRoots = true)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Commit(IReleaseSpec releaseSpec, IWorldStateTracer tracer, bool isGenesis = false, bool commitRoots = true)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void CommitTree(long blockNumber)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void CreateAccount(Address address, in UInt256 balance, in UInt256 nonce = default)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void CreateAccountIfNotExists(Address address, in UInt256 balance, in UInt256 nonce = default)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void DecrementNonce(Address address, UInt256 delta)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void DeleteAccount(Address address)
+ {
+ throw new NotImplementedException();
+ }
+
+ public ReadOnlySpan Get(in StorageCell storageCell)
+ {
+ throw new NotImplementedException();
+ }
+
+ public ArrayPoolList? GetAccountChanges()
+ {
+ throw new NotImplementedException();
+ }
+
+ public ref readonly UInt256 GetBalance(Address address)
+ {
+ throw new NotImplementedException();
+ }
+
+ public byte[]? GetCode(Address address)
+ {
+ if (!blockAccessList.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
+ {
+ return innerWorldState.GetCode(address);
+ }
+
+ List codeChanges = accountChanges.CodeChanges;
+ CodeChange? lastChange = null;
+ foreach (CodeChange codeChange in codeChanges)
+ {
+ if (codeChange.BlockAccessIndex >= blockAccessIndex)
+ {
+ break;
+ }
+ lastChange = codeChange;
+ }
+
+ if (lastChange is null)
+ {
+ return innerWorldState.GetCode(address);
+ }
+
+ return lastChange.Value.NewCode;
+ }
+
+ public byte[]? GetCode(in ValueHash256 codeHash)
+ {
+ throw new NotImplementedException();
+ }
+
+ public ref readonly ValueHash256 GetCodeHash(Address address)
+ {
+ throw new NotImplementedException();
+ }
+
+ public byte[] GetOriginal(in StorageCell storageCell)
+ {
+ throw new NotImplementedException();
+ }
+
+ public ReadOnlySpan GetTransientState(in StorageCell storageCell)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool HasStateForBlock(BlockHeader? baseBlock)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void IncrementNonce(Address address, UInt256 delta)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool InsertCode(Address address, in ValueHash256 codeHash, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool IsContract(Address address)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool IsDeadAccount(Address address)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RecalculateStateRoot()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Reset(bool resetBlockChanges = true)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void ResetTransient()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Restore(Snapshot snapshot)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Set(in StorageCell storageCell, byte[] newValue)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void SetBaseBlock(BlockHeader? header)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void SetNonce(Address address, in UInt256 nonce)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void SetTransientState(in StorageCell storageCell, byte[] newValue)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void SubtractFromBalance(Address address, in UInt256 balanceChange, IReleaseSpec spec)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Snapshot TakeSnapshot(bool newTransactionStart = false)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool TryGetAccount(Address address, out AccountStruct account)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void UpdateStorageRoot(Address address, Hash256 storageRoot)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void WarmUp(AccessList? accessList)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void WarmUp(Address address)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
From 190f2e48cbdde3d04c449d8fdfcf4143913d4f75 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 21 Aug 2025 01:03:35 +0100
Subject: [PATCH 020/215] reset changes using BAL
---
.../Processing/BlockCachePreWarmer.cs | 85 +++----
...sor.BlockValidationTransactionsExecutor.cs | 2 -
.../Processing/BlockProcessor.cs | 9 +-
.../Nethermind.State/BlockAccessWorldState.cs | 230 ------------------
.../Nethermind.State/StateProvider.cs | 1 -
5 files changed, 36 insertions(+), 291 deletions(-)
delete mode 100644 src/Nethermind/Nethermind.State/BlockAccessWorldState.cs
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs
index 0bab7208dac..951b704f84b 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockCachePreWarmer.cs
@@ -21,8 +21,6 @@
using Nethermind.Core.Collections;
using Nethermind.State;
using Nethermind.Trie;
-using Nethermind.Serialization.Rlp;
-using Nethermind.Core.BlockAccessLists;
namespace Nethermind.Consensus.Processing;
@@ -278,7 +276,7 @@ private void WarmupAddresses(ParallelOptions parallelOptions, Block block)
{
if (SystemTxAccessLists is not null)
{
- IReadOnlyTxProcessorSource env = envPool.Get();
+ var env = envPool.Get();
try
{
using IReadOnlyTxProcessingScope scope = env.Build(parent);
@@ -295,82 +293,56 @@ private void WarmupAddresses(ParallelOptions parallelOptions, Block block)
}
}
- WarmupTransactionAddresses(envPool, block.Transactions, true);
- if (block.BlockAccessList is not null)
+ AddressWarmingState baseState = new(envPool, block, parent);
+
+ ParallelUnbalancedWork.For(
+ 0,
+ block.Transactions.Length,
+ parallelOptions,
+ baseState.InitThreadState,
+ static (i, state) =>
{
- block.DecodedBlockAccessList = Rlp.Decode(block.BlockAccessList);
- IReadOnlyTxProcessorSource env = envPool.Get();
+ Transaction tx = state.Block.Transactions[i];
+ Address? sender = tx.SenderAddress;
+
try
{
- using IReadOnlyTxProcessingScope scope = env.Build(parent);
-
- foreach (Address address in block.DecodedBlockAccessList.Value.AccountChanges.Keys)
+ if (sender is not null)
{
- scope.WorldState.WarmUp(address);
+ state.Scope.WorldState.WarmUp(sender);
}
- // warmup storage locations
+ Address to = tx.To;
+ if (to is not null)
+ {
+ state.Scope.WorldState.WarmUp(to);
+ }
}
- finally
+ catch (MissingTrieNodeException)
{
- envPool.Return(env);
}
- }
+
+ return state;
+ },
+ AddressWarmingState.FinallyAction);
}
catch (OperationCanceledException)
{
// Ignore, block completed cancel
}
}
-
- private void WarmupTransactionAddresses(ObjectPool envPool, Transaction[] transactions, bool warmToAddress)
- {
- AddressWarmingState baseState = new(envPool, transactions, parent, warmToAddress);
-
- ParallelUnbalancedWork.For(
- 0,
- transactions.Length,
- parallelOptions,
- baseState.InitThreadState,
- static (i, state) =>
- {
- Transaction tx = state.Transactions[i];
- Address? sender = tx.SenderAddress;
-
- try
- {
- if (sender is not null)
- {
- state.Scope.WorldState.WarmUp(sender);
- }
-
- Address? to = state.WarmToAddress ? null : tx.To;
- if (to is not null)
- {
- state.Scope.WorldState.WarmUp(to);
- }
- }
- catch (MissingTrieNodeException)
- {
- }
-
- return state;
- },
- AddressWarmingState.FinallyAction);
- }
}
- private readonly struct AddressWarmingState(ObjectPool envPool, Transaction[] transactions, BlockHeader parent, bool warmToAddress) : IDisposable
+ private readonly struct AddressWarmingState(ObjectPool envPool, Block block, BlockHeader parent) : IDisposable
{
public static Action FinallyAction { get; } = DisposeThreadState;
public readonly ObjectPool EnvPool = envPool;
- public readonly Transaction[] Transactions = transactions;
+ public readonly Block Block = block;
public readonly IReadOnlyTxProcessorSource? Env;
public readonly IReadOnlyTxProcessingScope? Scope;
- public readonly bool WarmToAddress = warmToAddress;
- public AddressWarmingState(ObjectPool envPool, Transaction[] transactions, BlockHeader parent, IReadOnlyTxProcessorSource env, IReadOnlyTxProcessingScope scope, bool warmToAddress) : this(envPool, transactions, parent, warmToAddress)
+ public AddressWarmingState(ObjectPool envPool, Block block, BlockHeader parent, IReadOnlyTxProcessorSource env, IReadOnlyTxProcessingScope scope) : this(envPool, block, parent)
{
Env = env;
Scope = scope;
@@ -379,8 +351,7 @@ public AddressWarmingState(ObjectPool envPool, Trans
public AddressWarmingState InitThreadState()
{
IReadOnlyTxProcessorSource env = EnvPool.Get();
- IReadOnlyTxProcessingScope scope = env.Build(parent);
- return new(EnvPool, Transactions, parent, env, scope, WarmToAddress);
+ return new(EnvPool, Block, parent, env, scope: env.Build(parent));
}
public void Dispose()
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
index d749f666498..3a107f65749 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
@@ -11,7 +11,6 @@
using Nethermind.Evm;
using Nethermind.Evm.State;
using Nethermind.Evm.TransactionProcessing;
-using Nethermind.State;
using Metrics = Nethermind.Evm.Metrics;
namespace Nethermind.Consensus.Processing
@@ -45,7 +44,6 @@ public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processing
protected virtual void ProcessTransaction(Block block, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, ProcessingOptions processingOptions)
{
- BlockAccessWorldState blockAccessStateProvider = new(block.DecodedBlockAccessList!.Value, (ushort)(index + 1), stateProvider);
TransactionResult result = transactionProcessor.ProcessTransaction(currentTx, receiptsTracer, processingOptions, stateProvider);
if (!result) ThrowInvalidBlockException(result, block.Header, currentTx, index);
TransactionProcessed?.Invoke(this, new TxProcessedEventArgs(index, currentTx, receiptsTracer.TxReceipts[index]));
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index a5aeb87cbd3..ecdc1da7bae 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -233,7 +233,14 @@ private Block PrepareBlockForProcessing(Block suggestedBlock)
headerForProcessing.StateRoot = bh.StateRoot;
}
- return suggestedBlock.WithReplacedHeader(headerForProcessing);
+ Block block = suggestedBlock.WithReplacedHeader(headerForProcessing);
+
+ if (block.BlockAccessList is not null)
+ {
+ block.DecodedBlockAccessList = Rlp.Decode(block.BlockAccessList);
+ }
+
+ return block;
}
private void ApplyMinerRewards(Block block, IBlockTracer tracer, IReleaseSpec spec)
diff --git a/src/Nethermind/Nethermind.State/BlockAccessWorldState.cs b/src/Nethermind/Nethermind.State/BlockAccessWorldState.cs
deleted file mode 100644
index bfb452692d1..00000000000
--- a/src/Nethermind/Nethermind.State/BlockAccessWorldState.cs
+++ /dev/null
@@ -1,230 +0,0 @@
-// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
-// SPDX-License-Identifier: LGPL-3.0-only
-
-using System;
-using System.Collections.Generic;
-using Nethermind.Core;
-using Nethermind.Core.BlockAccessLists;
-using Nethermind.Core.Collections;
-using Nethermind.Core.Crypto;
-using Nethermind.Core.Eip2930;
-using Nethermind.Core.Specs;
-using Nethermind.Evm.State;
-using Nethermind.Evm.Tracing.State;
-using Nethermind.Int256;
-
-namespace Nethermind.State;
-
-public class BlockAccessWorldState(BlockAccessList blockAccessList, ushort blockAccessIndex, IWorldState innerWorldState) : IWorldState
-{
- public Hash256 StateRoot => throw new NotImplementedException();
-
- public bool AccountExists(Address address)
- => innerWorldState.AccountExists(address);
-
- public void AddToBalance(Address address, in UInt256 balanceChange, IReleaseSpec spec)
- {
- throw new NotImplementedException();
- }
-
- public bool AddToBalanceAndCreateIfNotExists(Address address, in UInt256 balanceChange, IReleaseSpec spec)
- {
- throw new NotImplementedException();
- }
-
- public void ClearStorage(Address address)
- {
- throw new NotImplementedException();
- }
-
- public void Commit(IReleaseSpec releaseSpec, bool isGenesis = false, bool commitRoots = true)
- {
- throw new NotImplementedException();
- }
-
- public void Commit(IReleaseSpec releaseSpec, IWorldStateTracer tracer, bool isGenesis = false, bool commitRoots = true)
- {
- throw new NotImplementedException();
- }
-
- public void CommitTree(long blockNumber)
- {
- throw new NotImplementedException();
- }
-
- public void CreateAccount(Address address, in UInt256 balance, in UInt256 nonce = default)
- {
- throw new NotImplementedException();
- }
-
- public void CreateAccountIfNotExists(Address address, in UInt256 balance, in UInt256 nonce = default)
- {
- throw new NotImplementedException();
- }
-
- public void DecrementNonce(Address address, UInt256 delta)
- {
- throw new NotImplementedException();
- }
-
- public void DeleteAccount(Address address)
- {
- throw new NotImplementedException();
- }
-
- public ReadOnlySpan Get(in StorageCell storageCell)
- {
- throw new NotImplementedException();
- }
-
- public ArrayPoolList? GetAccountChanges()
- {
- throw new NotImplementedException();
- }
-
- public ref readonly UInt256 GetBalance(Address address)
- {
- throw new NotImplementedException();
- }
-
- public byte[]? GetCode(Address address)
- {
- if (!blockAccessList.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
- {
- return innerWorldState.GetCode(address);
- }
-
- List codeChanges = accountChanges.CodeChanges;
- CodeChange? lastChange = null;
- foreach (CodeChange codeChange in codeChanges)
- {
- if (codeChange.BlockAccessIndex >= blockAccessIndex)
- {
- break;
- }
- lastChange = codeChange;
- }
-
- if (lastChange is null)
- {
- return innerWorldState.GetCode(address);
- }
-
- return lastChange.Value.NewCode;
- }
-
- public byte[]? GetCode(in ValueHash256 codeHash)
- {
- throw new NotImplementedException();
- }
-
- public ref readonly ValueHash256 GetCodeHash(Address address)
- {
- throw new NotImplementedException();
- }
-
- public byte[] GetOriginal(in StorageCell storageCell)
- {
- throw new NotImplementedException();
- }
-
- public ReadOnlySpan GetTransientState(in StorageCell storageCell)
- {
- throw new NotImplementedException();
- }
-
- public bool HasStateForBlock(BlockHeader? baseBlock)
- {
- throw new NotImplementedException();
- }
-
- public void IncrementNonce(Address address, UInt256 delta)
- {
- throw new NotImplementedException();
- }
-
- public bool InsertCode(Address address, in ValueHash256 codeHash, ReadOnlyMemory code, IReleaseSpec spec, bool isGenesis = false)
- {
- throw new NotImplementedException();
- }
-
- public bool IsContract(Address address)
- {
- throw new NotImplementedException();
- }
-
- public bool IsDeadAccount(Address address)
- {
- throw new NotImplementedException();
- }
-
- public void RecalculateStateRoot()
- {
- throw new NotImplementedException();
- }
-
- public void Reset(bool resetBlockChanges = true)
- {
- throw new NotImplementedException();
- }
-
- public void ResetTransient()
- {
- throw new NotImplementedException();
- }
-
- public void Restore(Snapshot snapshot)
- {
- throw new NotImplementedException();
- }
-
- public void Set(in StorageCell storageCell, byte[] newValue)
- {
- throw new NotImplementedException();
- }
-
- public void SetBaseBlock(BlockHeader? header)
- {
- throw new NotImplementedException();
- }
-
- public void SetNonce(Address address, in UInt256 nonce)
- {
- throw new NotImplementedException();
- }
-
- public void SetTransientState(in StorageCell storageCell, byte[] newValue)
- {
- throw new NotImplementedException();
- }
-
- public void SubtractFromBalance(Address address, in UInt256 balanceChange, IReleaseSpec spec)
- {
- throw new NotImplementedException();
- }
-
- public Snapshot TakeSnapshot(bool newTransactionStart = false)
- {
- throw new NotImplementedException();
- }
-
- public bool TryGetAccount(Address address, out AccountStruct account)
- {
- throw new NotImplementedException();
- }
-
- public void UpdateStorageRoot(Address address, Hash256 storageRoot)
- {
- throw new NotImplementedException();
- }
-
- public void WarmUp(AccessList? accessList)
- {
- throw new NotImplementedException();
- }
-
- public void WarmUp(Address address)
- {
- throw new NotImplementedException();
- }
-}
\ No newline at end of file
diff --git a/src/Nethermind/Nethermind.State/StateProvider.cs b/src/Nethermind/Nethermind.State/StateProvider.cs
index 5167e75cbc4..549792456cb 100644
--- a/src/Nethermind/Nethermind.State/StateProvider.cs
+++ b/src/Nethermind/Nethermind.State/StateProvider.cs
@@ -57,7 +57,6 @@ internal class StateProvider
private readonly bool _populatePreBlockCache;
private bool _needsStateRootUpdate;
- // get from block access list
public StateProvider(IScopedTrieStore? trieStore,
IKeyValueStoreWithBatching codeDb,
ILogManager logManager,
From f09890c59e9f5391abc38a1bc7d01073ce037aa6 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 21 Aug 2025 18:04:59 +0100
Subject: [PATCH 021/215] only trace when EIP enabled
---
.../Processing/BlockProcessor.cs | 24 ++++++++++++++-----
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index ecdc1da7bae..3671c6a4606 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -104,10 +104,17 @@ protected virtual TxReceipt[] ProcessBlock(
BlockBody body = block.Body;
BlockHeader header = block.Header;
- CompositeBlockTracer compositeBlockTracer = new();
- compositeBlockTracer.Add(blockTracer);
- compositeBlockTracer.Add(BlockAccessTracer);
- ReceiptsTracer.SetOtherTracer(compositeBlockTracer);
+ if (spec.BlockLevelAccessListsEnabled)
+ {
+ CompositeBlockTracer compositeBlockTracer = new();
+ compositeBlockTracer.Add(blockTracer);
+ compositeBlockTracer.Add(BlockAccessTracer);
+ ReceiptsTracer.SetOtherTracer(compositeBlockTracer);
+ }
+ else
+ {
+ ReceiptsTracer.SetOtherTracer(blockTracer);
+ }
ReceiptsTracer.StartNewBlockTrace(block);
blockTransactionsExecutor.SetBlockExecutionContext(new BlockExecutionContext(block.Header, spec));
@@ -120,7 +127,7 @@ protected virtual TxReceipt[] ProcessBlock(
_stateProvider.Commit(spec, commitRoots: false);
- BlockAccessList bal = ReceiptsTracer.GetTracer().BlockAccessList;
+ BlockAccessList? bal = ReceiptsTracer.GetTracer()?.BlockAccessList;
CalculateBlooms(receipts);
@@ -131,6 +138,7 @@ protected virtual TxReceipt[] ProcessBlock(
header.ReceiptsRoot = _receiptsRootCalculator.GetReceiptsRoot(receipts, spec, block.ReceiptsRoot);
ApplyMinerRewards(block, blockTracer, spec);
+ // build BAL
withdrawalProcessor.ProcessWithdrawals(block, spec);
// We need to do a commit here as in _executionRequestsProcessor while executing system transactions
@@ -157,7 +165,11 @@ protected virtual TxReceipt[] ProcessBlock(
}
header.Hash = header.CalculateHash();
- body.BlockAccessList = Rlp.Encode(bal).Bytes;
+
+ if (spec.BlockLevelAccessListsEnabled)
+ {
+ body.BlockAccessList = Rlp.Encode(bal).Bytes;
+ }
return receipts;
}
From f93a43cbed8a3d9b4cc66a690fa24c0b1addebe9 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 21 Aug 2025 18:21:44 +0100
Subject: [PATCH 022/215] handle withdrawals
---
.../Tracing/BlockAccessTracer.cs | 6 ++----
.../Processing/BlockProcessor.cs | 10 +++++-----
.../Withdrawals/IWithdrawalProcessor.cs | 3 ++-
.../Withdrawals/WithdrawalProcessor.cs | 14 ++++++++++++--
4 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
index ee791fee743..f448574b43c 100644
--- a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
@@ -90,8 +90,6 @@ public void ReportBalanceChange(Address address, UInt256? before, UInt256? after
_bal.AccountChanges.Add(address, accountChanges);
}
- // show should refunds be handled?
-
// don't add zero balance transfers, but add empty account changes
if ((before ?? 0) == after)
{
@@ -230,7 +228,7 @@ public void SetOperationMemory(TraceMemory memoryTrace) {}
public void ReportFees(UInt256 fees, UInt256 burntFees) {}
// private ITxTracer _currentTxTracer = NullTxTracer.Instance;
- private ushort _blockAccessIndex = 1;
+ private ushort _blockAccessIndex = 0;
// private readonly List _txReceipts = new();
private BlockAccessList _bal = new();
protected Transaction? CurrentTx;
@@ -259,7 +257,7 @@ public void ReportReward(Address author, string rewardType, UInt256 rewardValue)
public void StartNewBlockTrace(Block block)
{
Block = block;
- _blockAccessIndex = 1;
+ _blockAccessIndex = 0;
_bal = new();
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index 3671c6a4606..0ef15672e40 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -123,12 +123,13 @@ protected virtual TxReceipt[] ProcessBlock(
blockHashStore.ApplyBlockhashStateChanges(header, spec);
_stateProvider.Commit(spec, commitRoots: false);
+ // set access index to 1 since system contracts completed
+ BlockAccessTracer.EndTxTrace();
+
TxReceipt[] receipts = blockTransactionsExecutor.ProcessTransactions(block, options, ReceiptsTracer, token);
_stateProvider.Commit(spec, commitRoots: false);
- BlockAccessList? bal = ReceiptsTracer.GetTracer()?.BlockAccessList;
-
CalculateBlooms(receipts);
if (spec.IsEip4844Enabled)
@@ -138,8 +139,7 @@ protected virtual TxReceipt[] ProcessBlock(
header.ReceiptsRoot = _receiptsRootCalculator.GetReceiptsRoot(receipts, spec, block.ReceiptsRoot);
ApplyMinerRewards(block, blockTracer, spec);
- // build BAL
- withdrawalProcessor.ProcessWithdrawals(block, spec);
+ withdrawalProcessor.ProcessWithdrawals(block, spec, BlockAccessTracer);
// We need to do a commit here as in _executionRequestsProcessor while executing system transactions
// we do WorldState.Commit(SystemTransactionReleaseSpec.Instance). In SystemTransactionReleaseSpec
@@ -168,7 +168,7 @@ protected virtual TxReceipt[] ProcessBlock(
if (spec.BlockLevelAccessListsEnabled)
{
- body.BlockAccessList = Rlp.Encode(bal).Bytes;
+ body.BlockAccessList = Rlp.Encode(BlockAccessTracer.BlockAccessList).Bytes;
}
return receipts;
diff --git a/src/Nethermind/Nethermind.Consensus/Withdrawals/IWithdrawalProcessor.cs b/src/Nethermind/Nethermind.Consensus/Withdrawals/IWithdrawalProcessor.cs
index 5909ba1f220..c2eb33848ff 100644
--- a/src/Nethermind/Nethermind.Consensus/Withdrawals/IWithdrawalProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Withdrawals/IWithdrawalProcessor.cs
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using Nethermind.Blockchain.Tracing;
using Nethermind.Core;
using Nethermind.Core.Specs;
@@ -8,5 +9,5 @@ namespace Nethermind.Consensus.Withdrawals;
public interface IWithdrawalProcessor
{
- void ProcessWithdrawals(Block block, IReleaseSpec spec);
+ void ProcessWithdrawals(Block block, IReleaseSpec spec, BlockAccessTracer blockAccessTracer);
}
diff --git a/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs b/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs
index 3b526813f89..2582445a359 100644
--- a/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs
@@ -2,9 +2,11 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using Nethermind.Blockchain.Tracing;
using Nethermind.Core;
using Nethermind.Core.Specs;
using Nethermind.Evm.State;
+using Nethermind.Int256;
using Nethermind.Logging;
namespace Nethermind.Consensus.Withdrawals;
@@ -22,7 +24,7 @@ public WithdrawalProcessor(IWorldState stateProvider, ILogManager logManager)
_stateProvider = stateProvider ?? throw new ArgumentNullException(nameof(stateProvider));
}
- public void ProcessWithdrawals(Block block, IReleaseSpec spec)
+ public void ProcessWithdrawals(Block block, IReleaseSpec spec, BlockAccessTracer blockAccessTracer)
{
if (!spec.WithdrawalsEnabled)
return;
@@ -35,10 +37,18 @@ public void ProcessWithdrawals(Block block, IReleaseSpec spec)
for (int i = 0; i < blockWithdrawals.Length; i++)
{
Withdrawal withdrawal = blockWithdrawals[i];
+ Address address = withdrawal.Address;
+ UInt256 amount = withdrawal.AmountInWei;
if (_logger.IsTrace) _logger.Trace($" {withdrawal.AmountInGwei} GWei to account {withdrawal.Address}");
// Consensus clients are using Gwei for withdrawals amount. We need to convert it to Wei before applying state changes https://github.com/ethereum/execution-apis/pull/354
- _stateProvider.AddToBalanceAndCreateIfNotExists(withdrawal.Address, withdrawal.AmountInWei, spec);
+ _stateProvider.AddToBalanceAndCreateIfNotExists(address, amount, spec);
+
+ if (spec.BlockLevelAccessListsEnabled && amount != 0)
+ {
+ UInt256 newBalance = _stateProvider.GetBalance(address);
+ blockAccessTracer.ReportBalanceChange(address, null, newBalance);
+ }
}
}
From 2bf2cefcc6457ac0c22a9fa897c68954aff76f63 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 21 Aug 2025 18:33:29 +0100
Subject: [PATCH 023/215] handle system contracts
---
.../Nethermind.Blockchain/Blocks/BlockhashStore.cs | 14 ++++++++++----
.../Blocks/IBlockhashStore.cs | 5 +++--
.../Processing/BlockProcessor.cs | 9 +++++----
.../Withdrawals/IWithdrawalProcessor.cs | 4 ++--
.../Withdrawals/WithdrawalProcessor.cs | 8 +++++---
5 files changed, 25 insertions(+), 15 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs b/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs
index 00d7a44cda8..c8dbf66b1d3 100644
--- a/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Blocks/BlockhashStore.cs
@@ -8,6 +8,7 @@
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Evm.State;
+using Nethermind.Evm.Tracing;
using Nethermind.Int256;
[assembly: InternalsVisibleTo("Nethermind.Blockchain.Test")]
@@ -19,10 +20,10 @@ public class BlockhashStore(ISpecProvider specProvider, IWorldState worldState)
{
private static readonly byte[] EmptyBytes = [0];
- public void ApplyBlockhashStateChanges(BlockHeader blockHeader)
- => ApplyBlockhashStateChanges(blockHeader, specProvider.GetSpec(blockHeader));
+ public void ApplyBlockhashStateChanges(BlockHeader blockHeader, ITxTracer? tracer = null)
+ => ApplyBlockhashStateChanges(blockHeader, specProvider.GetSpec(blockHeader), tracer);
- public void ApplyBlockhashStateChanges(BlockHeader blockHeader, IReleaseSpec spec)
+ public void ApplyBlockhashStateChanges(BlockHeader blockHeader, IReleaseSpec spec, ITxTracer? tracer = null)
{
if (!spec.IsEip2935Enabled || blockHeader.IsGenesis || blockHeader.ParentHash is null) return;
@@ -32,7 +33,12 @@ public void ApplyBlockhashStateChanges(BlockHeader blockHeader, IReleaseSpec spe
Hash256 parentBlockHash = blockHeader.ParentHash;
var parentBlockIndex = new UInt256((ulong)((blockHeader.Number - 1) % Eip2935Constants.RingBufferSize));
StorageCell blockHashStoreCell = new(eip2935Account, parentBlockIndex);
- worldState.Set(blockHashStoreCell, parentBlockHash!.Bytes.WithoutLeadingZeros().ToArray());
+ byte[] newValue = parentBlockHash!.Bytes.WithoutLeadingZeros().ToArray();
+ worldState.Set(blockHashStoreCell, newValue);
+ if (tracer is not null && tracer.IsTracingStorage)
+ {
+ tracer.ReportStorageChange(blockHashStoreCell, null, newValue);
+ }
}
public Hash256? GetBlockHashFromState(BlockHeader currentHeader, long requiredBlockNumber)
diff --git a/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs b/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs
index 77cc6b214f5..035f1a543f3 100644
--- a/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Blocks/IBlockhashStore.cs
@@ -4,13 +4,14 @@
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
+using Nethermind.Evm.Tracing;
namespace Nethermind.Blockchain.Blocks;
public interface IBlockhashStore
{
- public void ApplyBlockhashStateChanges(BlockHeader blockHeader);
- public void ApplyBlockhashStateChanges(BlockHeader blockHeader, IReleaseSpec spec);
+ public void ApplyBlockhashStateChanges(BlockHeader blockHeader, ITxTracer? tracer = null);
+ public void ApplyBlockhashStateChanges(BlockHeader blockHeader, IReleaseSpec spec, ITxTracer? tracer = null);
public Hash256? GetBlockHashFromState(BlockHeader currentBlockHeader, long requiredBlockNumber);
public Hash256? GetBlockHashFromState(BlockHeader currentBlockHeader, long requiredBlockNumber, IReleaseSpec? spec);
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index 0ef15672e40..b59400afb8f 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -119,8 +119,8 @@ protected virtual TxReceipt[] ProcessBlock(
blockTransactionsExecutor.SetBlockExecutionContext(new BlockExecutionContext(block.Header, spec));
- StoreBeaconRoot(block, spec);
- blockHashStore.ApplyBlockhashStateChanges(header, spec);
+ StoreBeaconRoot(block, spec, BlockAccessTracer);
+ blockHashStore.ApplyBlockhashStateChanges(header, spec, BlockAccessTracer);
_stateProvider.Commit(spec, commitRoots: false);
// set access index to 1 since system contracts completed
@@ -189,11 +189,11 @@ private static void CalculateBlooms(TxReceipt[] receipts)
});
}
- private void StoreBeaconRoot(Block block, IReleaseSpec spec)
+ private void StoreBeaconRoot(Block block, IReleaseSpec spec, ITxTracer tracer)
{
try
{
- beaconBlockRootHandler.StoreBeaconRoot(block, spec, NullTxTracer.Instance);
+ beaconBlockRootHandler.StoreBeaconRoot(block, spec, tracer);
}
catch (Exception e)
{
@@ -287,6 +287,7 @@ private void ApplyMinerReward(Block block, BlockReward reward, IReleaseSpec spec
if (_logger.IsTrace) _logger.Trace($" {(BigInteger)reward.Value / (BigInteger)Unit.Ether:N3}{Unit.EthSymbol} for account at {reward.Address}");
_stateProvider.AddToBalanceAndCreateIfNotExists(reward.Address, reward.Value, spec);
+ // tracer here?
}
private void ApplyDaoTransition(Block block)
diff --git a/src/Nethermind/Nethermind.Consensus/Withdrawals/IWithdrawalProcessor.cs b/src/Nethermind/Nethermind.Consensus/Withdrawals/IWithdrawalProcessor.cs
index c2eb33848ff..3a42e111666 100644
--- a/src/Nethermind/Nethermind.Consensus/Withdrawals/IWithdrawalProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Withdrawals/IWithdrawalProcessor.cs
@@ -1,13 +1,13 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
-using Nethermind.Blockchain.Tracing;
using Nethermind.Core;
using Nethermind.Core.Specs;
+using Nethermind.Evm.Tracing;
namespace Nethermind.Consensus.Withdrawals;
public interface IWithdrawalProcessor
{
- void ProcessWithdrawals(Block block, IReleaseSpec spec, BlockAccessTracer blockAccessTracer);
+ void ProcessWithdrawals(Block block, IReleaseSpec spec, ITxTracer tracer = null);
}
diff --git a/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs b/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs
index 2582445a359..1243f3e95fd 100644
--- a/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Withdrawals/WithdrawalProcessor.cs
@@ -2,10 +2,12 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using System.Diagnostics.CodeAnalysis;
using Nethermind.Blockchain.Tracing;
using Nethermind.Core;
using Nethermind.Core.Specs;
using Nethermind.Evm.State;
+using Nethermind.Evm.Tracing;
using Nethermind.Int256;
using Nethermind.Logging;
@@ -24,7 +26,7 @@ public WithdrawalProcessor(IWorldState stateProvider, ILogManager logManager)
_stateProvider = stateProvider ?? throw new ArgumentNullException(nameof(stateProvider));
}
- public void ProcessWithdrawals(Block block, IReleaseSpec spec, BlockAccessTracer blockAccessTracer)
+ public void ProcessWithdrawals(Block block, IReleaseSpec spec, ITxTracer tracer = null)
{
if (!spec.WithdrawalsEnabled)
return;
@@ -44,10 +46,10 @@ public void ProcessWithdrawals(Block block, IReleaseSpec spec, BlockAccessTracer
// Consensus clients are using Gwei for withdrawals amount. We need to convert it to Wei before applying state changes https://github.com/ethereum/execution-apis/pull/354
_stateProvider.AddToBalanceAndCreateIfNotExists(address, amount, spec);
- if (spec.BlockLevelAccessListsEnabled && amount != 0)
+ if (tracer is not null && amount != 0)
{
UInt256 newBalance = _stateProvider.GetBalance(address);
- blockAccessTracer.ReportBalanceChange(address, null, newBalance);
+ tracer.ReportBalanceChange(address, null, newBalance);
}
}
}
From ce008923c08823a17d76792fd97e24e42f690695 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Thu, 21 Aug 2025 18:46:27 +0100
Subject: [PATCH 024/215] fix compile
---
.../BlockProductionWithdrawalProcessor.cs | 12 +++++-----
.../Withdrawals/NullWithdrawalProcessor.cs | 3 ++-
.../Withdrawals/AuraWithdrawalProcessor.cs | 4 +++-
.../OptimismWithdrawals.cs | 22 +++++++------------
4 files changed, 18 insertions(+), 23 deletions(-)
diff --git a/src/Nethermind/Nethermind.Consensus/Withdrawals/BlockProductionWithdrawalProcessor.cs b/src/Nethermind/Nethermind.Consensus/Withdrawals/BlockProductionWithdrawalProcessor.cs
index c03f0702002..d05d4104c11 100644
--- a/src/Nethermind/Nethermind.Consensus/Withdrawals/BlockProductionWithdrawalProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Withdrawals/BlockProductionWithdrawalProcessor.cs
@@ -5,20 +5,18 @@
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
+using Nethermind.Evm.Tracing;
using Nethermind.State.Proofs;
namespace Nethermind.Consensus.Withdrawals;
-public class BlockProductionWithdrawalProcessor : IWithdrawalProcessor
+public class BlockProductionWithdrawalProcessor(IWithdrawalProcessor processor) : IWithdrawalProcessor
{
- private readonly IWithdrawalProcessor _processor;
+ private readonly IWithdrawalProcessor _processor = processor ?? throw new ArgumentNullException(nameof(processor));
- public BlockProductionWithdrawalProcessor(IWithdrawalProcessor processor) =>
- _processor = processor ?? throw new ArgumentNullException(nameof(processor));
-
- public void ProcessWithdrawals(Block block, IReleaseSpec spec)
+ public void ProcessWithdrawals(Block block, IReleaseSpec spec, ITxTracer tracer = null)
{
- _processor.ProcessWithdrawals(block, spec);
+ _processor.ProcessWithdrawals(block, spec, tracer);
if (spec.WithdrawalsEnabled)
{
diff --git a/src/Nethermind/Nethermind.Consensus/Withdrawals/NullWithdrawalProcessor.cs b/src/Nethermind/Nethermind.Consensus/Withdrawals/NullWithdrawalProcessor.cs
index 24581691fcf..a768b1826bf 100644
--- a/src/Nethermind/Nethermind.Consensus/Withdrawals/NullWithdrawalProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Withdrawals/NullWithdrawalProcessor.cs
@@ -3,12 +3,13 @@
using Nethermind.Core;
using Nethermind.Core.Specs;
+using Nethermind.Evm.Tracing;
namespace Nethermind.Consensus.Withdrawals;
public class NullWithdrawalProcessor : IWithdrawalProcessor
{
- public void ProcessWithdrawals(Block block, IReleaseSpec spec) { }
+ public void ProcessWithdrawals(Block block, IReleaseSpec spec, ITxTracer? tracer = null) { }
public static IWithdrawalProcessor Instance { get; } = new NullWithdrawalProcessor();
}
diff --git a/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/AuraWithdrawalProcessor.cs b/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/AuraWithdrawalProcessor.cs
index 85776645e9a..4cdcb468e58 100644
--- a/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/AuraWithdrawalProcessor.cs
+++ b/src/Nethermind/Nethermind.Merge.AuRa/Withdrawals/AuraWithdrawalProcessor.cs
@@ -9,6 +9,7 @@
using Nethermind.Core.Collections;
using Nethermind.Core.Specs;
using Nethermind.Evm;
+using Nethermind.Evm.Tracing;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.Merge.AuRa.Contracts;
@@ -29,7 +30,7 @@ public AuraWithdrawalProcessor(IWithdrawalContract contract, ILogManager logMana
_logger = logManager.GetClassLogger();
}
- public void ProcessWithdrawals(Block block, IReleaseSpec spec)
+ public void ProcessWithdrawals(Block block, IReleaseSpec spec, ITxTracer? tracer = null)
{
if (!spec.WithdrawalsEnabled || block.Withdrawals is null) // The second check seems redundant
return;
@@ -50,6 +51,7 @@ public void ProcessWithdrawals(Block block, IReleaseSpec spec)
if (_logger.IsTrace) _logger.Trace($" {(BigInteger)withdrawal.AmountInWei / (BigInteger)Unit.Ether:N3}GNO to account {withdrawal.Address}");
}
+ // todo: trace state changes
try
{
_contract.ExecuteWithdrawals(block.Header, _failedWithdrawalsMaxCount, amounts, addresses);
diff --git a/src/Nethermind/Nethermind.Optimism/OptimismWithdrawals.cs b/src/Nethermind/Nethermind.Optimism/OptimismWithdrawals.cs
index 141d3ecc0d6..47b2c52db65 100644
--- a/src/Nethermind/Nethermind.Optimism/OptimismWithdrawals.cs
+++ b/src/Nethermind/Nethermind.Optimism/OptimismWithdrawals.cs
@@ -6,6 +6,7 @@
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
using Nethermind.Evm.State;
+using Nethermind.Evm.Tracing;
using Nethermind.Logging;
namespace Nethermind.Optimism;
@@ -17,28 +18,21 @@ namespace Nethermind.Optimism;
/// Constructed over the world state so that it can construct the proper withdrawals hash just before commitment.
/// https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/isthmus/exec-engine.md#l2tol1messagepasser-storage-root-in-header
///
-public class OptimismWithdrawalProcessor : IWithdrawalProcessor
+public class OptimismWithdrawalProcessor(IWorldState state, ILogManager logManager, IOptimismSpecHelper specHelper) : IWithdrawalProcessor
{
- private readonly IWorldState _state;
- private readonly IOptimismSpecHelper _specHelper;
- private readonly ILogger _logger;
+ private readonly IWorldState _state = state;
+ private readonly IOptimismSpecHelper _specHelper = specHelper;
+ private readonly ILogger _logger = logManager.GetClassLogger();
- public OptimismWithdrawalProcessor(IWorldState state, ILogManager logManager, IOptimismSpecHelper specHelper)
+ public void ProcessWithdrawals(Block block, IReleaseSpec spec, ITxTracer? tracer = null)
{
- _state = state;
- _specHelper = specHelper;
- _logger = logManager.GetClassLogger();
- }
-
- public void ProcessWithdrawals(Block block, IReleaseSpec spec)
- {
- var header = block.Header;
+ BlockHeader header = block.Header;
if (_specHelper.IsIsthmus(header))
{
_state.Commit(spec, commitRoots: true);
- if (_state.TryGetAccount(PreDeploys.L2ToL1MessagePasser, out var account))
+ if (_state.TryGetAccount(PreDeploys.L2ToL1MessagePasser, out AccountStruct account))
{
if (_logger.IsDebug)
_logger.Debug($"Setting {nameof(BlockHeader.WithdrawalsRoot)} to {account.StorageRoot}");
From 9d1d9ffa958d74cb8ee4aafa7b5f8352ae3e55d9 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 22 Aug 2025 14:58:09 +0100
Subject: [PATCH 025/215] add block processing test
---
.../BlockAccessListTests.cs | 81 +++++++++++++++++++
.../TransactionProcessorTests.cs | 2 +-
.../Tracing/BlockAccessTracer.cs | 46 +++++------
.../Processing/BlockProcessor.cs | 3 +-
.../OverridableReleaseSpec.cs | 2 +-
5 files changed, 107 insertions(+), 27 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index 5a94de1ee71..c5cc18a455d 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -2,11 +2,27 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System.Collections.Generic;
+using System.Threading;
+using Nethermind.Blockchain.BeaconBlockRoot;
+using Nethermind.Blockchain.Blocks;
+using Nethermind.Blockchain.Receipts;
+using Nethermind.Blockchain.Test.Validators;
using Nethermind.Blockchain.Tracing;
+using Nethermind.Consensus.ExecutionRequests;
+using Nethermind.Consensus.Processing;
+using Nethermind.Consensus.Rewards;
+using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
using Nethermind.Core.BlockAccessLists;
using Nethermind.Core.Test.Builders;
+using Nethermind.Evm.TransactionProcessing;
using Nethermind.Int256;
+using Nethermind.Logging;
+using Nethermind.Serialization.Rlp;
+using Nethermind.Specs;
+using Nethermind.Specs.Forks;
+using Nethermind.Specs.Test;
+using NSubstitute;
using NUnit.Framework;
//move all to correct folder
@@ -74,5 +90,70 @@ public void Balance_and_nonce_changes()
Assert.That(beneficiaryBalanceChanges[0].PostBalance, Is.EqualTo(new UInt256(GasCostOf.Transaction)));
}
}
+
+ [Test]
+ public void System_contracts_and_withdrawals()
+ {
+ BlockProcessor processor = new(HoleskySpecProvider.Instance,
+ TestBlockValidator.AlwaysValid,
+ NoBlockRewards.Instance,
+ new BlockProcessor.BlockValidationTransactionsExecutor(new ExecuteTransactionProcessorAdapter(_transactionProcessor), _stateProvider),
+ _stateProvider,
+ NullReceiptStorage.Instance,
+ new BeaconBlockRootHandler(_transactionProcessor, _stateProvider),
+ Substitute.For(), // create dummy?
+ LimboLogs.Instance,
+ new WithdrawalProcessor(_stateProvider, LimboLogs.Instance),
+ new ExecutionRequestsProcessor(_transactionProcessor));
+
+ ulong gasPrice = 2;
+ long gasLimit = 100000;
+ Transaction tx = Build.A.Transaction
+ .WithTo(TestItem.AddressB)
+ .WithSenderAddress(TestItem.AddressA)
+ .WithValue(0)
+ .WithGasPrice(gasPrice)
+ .WithGasLimit(gasLimit)
+ .TestObject;
+
+ Block block = Build.A.Block
+ .WithTransactions(tx)
+ .WithBaseFeePerGas(1)
+ .WithBeneficiary(TestItem.AddressC).TestObject;
+
+ // BlockReceiptsTracer blockReceiptsTracer = new();
+ // BlockAccessTracer accessTracer = new();
+ // blockReceiptsTracer.SetOtherTracer(accessTracer);
+ // Execute(tx, block, blockReceiptsTracer);
+
+ OverridableReleaseSpec spec = new(Prague.Instance)
+ {
+ IsEip7928Enabled = true
+ };
+ (Block processedBlock, TxReceipt[] _) = processor.ProcessOne(block, ProcessingOptions.None, NullBlockTracer.Instance, spec, CancellationToken.None);
+
+ SortedDictionary accountChanges = Rlp.Decode(processedBlock.BlockAccessList).AccountChanges;
+ Assert.That(accountChanges, Has.Count.EqualTo(3));
+
+ List senderBalanceChanges = accountChanges[TestItem.AddressA].BalanceChanges;
+ List senderNonceChanges = accountChanges[TestItem.AddressA].NonceChanges;
+ List toBalanceChanges = accountChanges[TestItem.AddressB].BalanceChanges;
+ List beneficiaryBalanceChanges = accountChanges[TestItem.AddressC].BalanceChanges;
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(senderBalanceChanges, Has.Count.EqualTo(1));
+ Assert.That(senderBalanceChanges[0].PostBalance, Is.EqualTo(AccountBalance - gasPrice * GasCostOf.Transaction));
+
+ Assert.That(senderNonceChanges, Has.Count.EqualTo(1));
+ Assert.That(senderNonceChanges[0].NewNonce, Is.EqualTo(1));
+
+ // zero balance change should not be recorded
+ Assert.That(toBalanceChanges, Is.Empty);
+
+ Assert.That(beneficiaryBalanceChanges, Has.Count.EqualTo(1));
+ Assert.That(beneficiaryBalanceChanges[0].PostBalance, Is.EqualTo(new UInt256(GasCostOf.Transaction)));
+ }
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionProcessorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionProcessorTests.cs
index 77392d405a6..b7617318245 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionProcessorTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionProcessorTests.cs
@@ -40,7 +40,7 @@ public abstract class TransactionProcessorTests
private readonly ISpecProvider _specProvider;
private IEthereumEcdsa _ethereumEcdsa;
protected ITransactionProcessor _transactionProcessor;
- private IWorldState _stateProvider;
+ protected IWorldState _stateProvider;
public TransactionProcessorTests(bool eip155Enabled)
{
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
index f448574b43c..68f6a00483f 100644
--- a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
@@ -45,18 +45,18 @@ public void MarkAsFailed(Address recipient, GasConsumed gasSpent, byte[] output,
}
- public void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env, int codeSection = 0, int functionDepth = 0) {}
+ public void StartOperation(int pc, Instruction opcode, long gas, in ExecutionEnvironment env, int codeSection = 0, int functionDepth = 0) { }
- public void ReportOperationError(EvmExceptionType error) {}
+ public void ReportOperationError(EvmExceptionType error) { }
- public void ReportOperationRemainingGas(long gas) {}
+ public void ReportOperationRemainingGas(long gas) { }
- public void ReportLog(LogEntry log) {}
+ public void ReportLog(LogEntry log) { }
- public void SetOperationMemorySize(ulong newSize) {}
+ public void SetOperationMemorySize(ulong newSize) { }
- public void ReportMemoryChange(long offset, in ReadOnlySpan data) {}
+ public void ReportMemoryChange(long offset, in ReadOnlySpan data) { }
public void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan newValue, ReadOnlySpan currentValue)
{
@@ -72,9 +72,9 @@ public void SetOperationStorage(Address address, UInt256 storageIndex, ReadOnlyS
}
}
- public void LoadOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan value) {}
+ public void LoadOperationStorage(Address address, UInt256 storageIndex, ReadOnlySpan value) { }
- public void ReportSelfDestruct(Address address, UInt256 balance, Address refundAddress) {}
+ public void ReportSelfDestruct(Address address, UInt256 balance, Address refundAddress) { }
public void ReportBalanceChange(Address address, UInt256? before, UInt256? after)
{
@@ -194,38 +194,38 @@ public void ReportStorageRead(in StorageCell storageCell)
accountChanges.StorageReads.Add(storageKey);
}
- public void ReportAction(long gas, UInt256 value, Address from, Address to, ReadOnlyMemory input, ExecutionType callType, bool isPrecompileCall = false) {}
+ public void ReportAction(long gas, UInt256 value, Address from, Address to, ReadOnlyMemory input, ExecutionType callType, bool isPrecompileCall = false) { }
- public void ReportActionEnd(long gas, ReadOnlyMemory output) {}
+ public void ReportActionEnd(long gas, ReadOnlyMemory output) { }
- public void ReportActionError(EvmExceptionType exceptionType) {}
+ public void ReportActionError(EvmExceptionType exceptionType) { }
- public void ReportActionRevert(long gasLeft, ReadOnlyMemory output) {}
+ public void ReportActionRevert(long gasLeft, ReadOnlyMemory output) { }
- public void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory deployedCode) {}
+ public void ReportActionEnd(long gas, Address deploymentAddress, ReadOnlyMemory deployedCode) { }
- public void ReportByteCode(ReadOnlyMemory byteCode) {}
+ public void ReportByteCode(ReadOnlyMemory byteCode) { }
- public void ReportGasUpdateForVmTrace(long refund, long gasAvailable) {}
+ public void ReportGasUpdateForVmTrace(long refund, long gasAvailable) { }
- public void ReportRefund(long refund) {}
+ public void ReportRefund(long refund) { }
- public void ReportExtraGasPressure(long extraGasPressure) {}
+ public void ReportExtraGasPressure(long extraGasPressure) { }
public void ReportAccess(IReadOnlyCollection accessedAddresses, IReadOnlyCollection accessedStorageCells)
{
// _bal.Add(new());
}
- public void SetOperationStack(TraceStack stack) {}
+ public void SetOperationStack(TraceStack stack) { }
- public void ReportStackPush(in ReadOnlySpan stackItem) {}
+ public void ReportStackPush(in ReadOnlySpan stackItem) { }
- public void ReportBlockHash(Hash256 blockHash) {}
+ public void ReportBlockHash(Hash256 blockHash) { }
- public void SetOperationMemory(TraceMemory memoryTrace) {}
+ public void SetOperationMemory(TraceMemory memoryTrace) { }
- public void ReportFees(UInt256 fees, UInt256 burntFees) {}
+ public void ReportFees(UInt256 fees, UInt256 burntFees) { }
// private ITxTracer _currentTxTracer = NullTxTracer.Instance;
private ushort _blockAccessIndex = 0;
@@ -252,7 +252,7 @@ public void Restore(int snapshot)
// Block.Header.GasUsed = _txReceipts.Count > 0 ? _txReceipts.Last().GasUsedTotal : 0;
}
- public void ReportReward(Address author, string rewardType, UInt256 rewardValue) {}
+ public void ReportReward(Address author, string rewardType, UInt256 rewardValue) { }
public void StartNewBlockTrace(Block block)
{
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index b59400afb8f..2dab108feff 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -247,7 +247,7 @@ private Block PrepareBlockForProcessing(Block suggestedBlock)
Block block = suggestedBlock.WithReplacedHeader(headerForProcessing);
- if (block.BlockAccessList is not null)
+ if (block.BlockAccessList is not null && block.BlockAccessList.Length != 0)
{
block.DecodedBlockAccessList = Rlp.Decode(block.BlockAccessList);
}
@@ -287,7 +287,6 @@ private void ApplyMinerReward(Block block, BlockReward reward, IReleaseSpec spec
if (_logger.IsTrace) _logger.Trace($" {(BigInteger)reward.Value / (BigInteger)Unit.Ether:N3}{Unit.EthSymbol} for account at {reward.Address}");
_stateProvider.AddToBalanceAndCreateIfNotExists(reward.Address, reward.Value, spec);
- // tracer here?
}
private void ApplyDaoTransition(Block block)
diff --git a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs
index c354ab068a3..aafe166b3fb 100644
--- a/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs
+++ b/src/Nethermind/Nethermind.Specs.Test/OverridableReleaseSpec.cs
@@ -196,6 +196,6 @@ public ulong Eip4844TransitionTimestamp
public bool IsEip7939Enabled => spec.IsEip7939Enabled;
public bool IsEip7907Enabled => spec.IsEip7907Enabled;
public bool IsRip7728Enabled => spec.IsRip7728Enabled;
- public bool IsEip7928Enabled => spec.IsEip7928Enabled;
+ public bool IsEip7928Enabled { get; set; } = spec.IsEip7928Enabled;
}
}
From 2f6829d0150ef9ffd68341edeba31d65e0ac29e3 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 22 Aug 2025 15:05:47 +0100
Subject: [PATCH 026/215] move bal decoding to suggested block validation
---
.../Messages/BlockErrorMessages.cs | 5 ++++-
.../Processing/BlockProcessor.cs | 10 +---------
.../Validators/BlockValidator.cs | 20 +++++++++++++++++++
3 files changed, 25 insertions(+), 10 deletions(-)
diff --git a/src/Nethermind/Nethermind.Consensus/Messages/BlockErrorMessages.cs b/src/Nethermind/Nethermind.Consensus/Messages/BlockErrorMessages.cs
index ec1db39e983..414f7cde0c4 100644
--- a/src/Nethermind/Nethermind.Consensus/Messages/BlockErrorMessages.cs
+++ b/src/Nethermind/Nethermind.Consensus/Messages/BlockErrorMessages.cs
@@ -153,7 +153,10 @@ public static string ExceededBlockSizeLimit(int limit) =>
public const string MissingBlockLevelAccessList = "MissingBlockLevelAccessList: Must be present in block body.";
+ public const string InvalidBlockLevelAccessList =
+ $"InvalidBlockLevelAccessList: Unable to decode.";
+
public static string InvalidBlockLevelAccessListRoot(Hash256 expected, Hash256 actual) =>
- $"InvalidBlockLevelAccessListRoot: expected {expected}, got {actual}";
+ $"InvalidBlockLevelAccessListRoot: Expected {expected}, got {actual}";
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index 2dab108feff..26a1cb5b9b2 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -15,7 +15,6 @@
using Nethermind.Consensus.Validators;
using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
-using Nethermind.Core.BlockAccessLists;
using Nethermind.Core.Specs;
using Nethermind.Core.Threading;
using Nethermind.Crypto;
@@ -245,14 +244,7 @@ private Block PrepareBlockForProcessing(Block suggestedBlock)
headerForProcessing.StateRoot = bh.StateRoot;
}
- Block block = suggestedBlock.WithReplacedHeader(headerForProcessing);
-
- if (block.BlockAccessList is not null && block.BlockAccessList.Length != 0)
- {
- block.DecodedBlockAccessList = Rlp.Decode(block.BlockAccessList);
- }
-
- return block;
+ return suggestedBlock.WithReplacedHeader(headerForProcessing);
}
private void ApplyMinerRewards(Block block, IBlockTracer tracer, IReleaseSpec spec)
diff --git a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
index 35384b53474..97c76fa5ef5 100644
--- a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
+++ b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
@@ -6,6 +6,7 @@
using Nethermind.Blockchain;
using Nethermind.Consensus.Messages;
using Nethermind.Core;
+using Nethermind.Core.BlockAccessLists;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
@@ -145,6 +146,25 @@ public bool ValidateSuggestedBlock(Block block, out string? errorMessage, bool v
}
}
+ if (spec.BlockLevelAccessListsEnabled)
+ {
+ if (block.BlockAccessList is null || block.BlockAccessList.Length == 0)
+ {
+ errorMessage = BlockErrorMessages.InvalidBlockLevelAccessList;
+ return false;
+ }
+
+ try
+ {
+ block.DecodedBlockAccessList = Rlp.Decode(block.BlockAccessList);
+ }
+ catch (RlpException)
+ {
+ errorMessage = BlockErrorMessages.InvalidBlockLevelAccessList;
+ return false;
+ }
+ }
+
return true;
}
From 23dc197af3caa98820c25a7b286193f9e70d4bf9 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 22 Aug 2025 15:07:48 +0100
Subject: [PATCH 027/215] decoding debug logs
---
.../Nethermind.Consensus/Validators/BlockValidator.cs | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
index 97c76fa5ef5..921e907afb6 100644
--- a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
+++ b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
@@ -150,6 +150,7 @@ public bool ValidateSuggestedBlock(Block block, out string? errorMessage, bool v
{
if (block.BlockAccessList is null || block.BlockAccessList.Length == 0)
{
+ if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} Block-level access list was missing or empty");
errorMessage = BlockErrorMessages.InvalidBlockLevelAccessList;
return false;
}
@@ -158,8 +159,9 @@ public bool ValidateSuggestedBlock(Block block, out string? errorMessage, bool v
{
block.DecodedBlockAccessList = Rlp.Decode(block.BlockAccessList);
}
- catch (RlpException)
+ catch (RlpException e)
{
+ if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} Block-level access list could not be decoded: {e}");
errorMessage = BlockErrorMessages.InvalidBlockLevelAccessList;
return false;
}
From 496b6869b4927c2cb8458442f15175512a0aac00 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 22 Aug 2025 15:14:36 +0100
Subject: [PATCH 028/215] empty rlp decode for bal
---
.../BlockAccessListDecoder.cs | 134 ++++++++++++++++++
1 file changed, 134 insertions(+)
create mode 100644 src/Nethermind/Nethermind.Serialization.Rlp/BlockAccessListDecoder.cs
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/BlockAccessListDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/BlockAccessListDecoder.cs
new file mode 100644
index 00000000000..880c6176840
--- /dev/null
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/BlockAccessListDecoder.cs
@@ -0,0 +1,134 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using Nethermind.Core.BlockAccessLists;
+
+namespace Nethermind.Serialization.Rlp;
+
+public class BlockAccessListDecoder : IRlpValueDecoder, IRlpStreamDecoder
+{
+ // private readonly TxDecoder _txDecoder = TxDecoder.Instance;
+ // private readonly HeaderDecoder _headerDecoder = new();
+ // private readonly WithdrawalDecoder _withdrawalDecoderDecoder = new();
+
+ private static BlockAccessListDecoder? _instance = null;
+ public static BlockAccessListDecoder Instance => _instance ??= new();
+
+ // public int GetLength(BlockBody item, RlpBehaviors rlpBehaviors)
+ // {
+ // return Rlp.LengthOfSequence(GetBodyLength(item));
+ // }
+
+ // public int GetBodyLength(BlockBody b)
+ // {
+ // (int txs, int uncles, int? withdrawals) = GetBodyComponentLength(b);
+ // return Rlp.LengthOfSequence(txs) +
+ // Rlp.LengthOfSequence(uncles) +
+ // (withdrawals is not null ? Rlp.LengthOfSequence(withdrawals.Value) : 0);
+ // }
+
+ // public (int Txs, int Uncles, int? Withdrawals) GetBodyComponentLength(BlockBody b) =>
+ // (
+ // GetTxLength(b.Transactions),
+ // GetUnclesLength(b.Uncles),
+ // b.Withdrawals is not null ? GetWithdrawalsLength(b.Withdrawals) : null
+ // );
+
+ // private int GetTxLength(Transaction[] transactions)
+ // {
+ // if (transactions.Length == 0) return 0;
+
+ // int sum = 0;
+ // foreach (Transaction tx in transactions)
+ // {
+ // sum += _txDecoder.GetLength(tx, RlpBehaviors.None);
+ // }
+
+ // return sum;
+ // }
+
+ // public BlockBody? Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ // {
+ // int sequenceLength = ctx.ReadSequenceLength();
+ // int startingPosition = ctx.Position;
+ // if (sequenceLength == 0)
+ // {
+ // return null;
+ // }
+
+ // return DecodeUnwrapped(ref ctx, startingPosition + sequenceLength);
+ // }
+
+ // public BlockBody? DecodeUnwrapped(ref Rlp.ValueDecoderContext ctx, int lastPosition)
+ // {
+
+ // // quite significant allocations (>0.5%) here based on a sample 3M blocks sync
+ // // (just on these delegates)
+ // Transaction[] transactions = ctx.DecodeArray(_txDecoder);
+ // BlockHeader[] uncles = ctx.DecodeArray(_headerDecoder);
+ // Withdrawal[]? withdrawals = null;
+
+ // if (ctx.PeekNumberOfItemsRemaining(lastPosition, 1) > 0)
+ // {
+ // withdrawals = ctx.DecodeArray(_withdrawalDecoderDecoder);
+ // }
+
+ // return new BlockBody(transactions, uncles, withdrawals);
+ // }
+
+ // public BlockBody Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ // {
+ // Span span = rlpStream.PeekNextItem();
+ // Rlp.ValueDecoderContext ctx = new Rlp.ValueDecoderContext(span);
+ // BlockBody response = Decode(ref ctx, rlpBehaviors);
+ // rlpStream.SkipItem();
+
+ // return response;
+ // }
+
+ // public void Encode(RlpStream stream, BlockBody body, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ // {
+ // stream.StartSequence(GetBodyLength(body));
+ // stream.StartSequence(GetTxLength(body.Transactions));
+ // foreach (Transaction? txn in body.Transactions)
+ // {
+ // stream.Encode(txn);
+ // }
+
+ // stream.StartSequence(GetUnclesLength(body.Uncles));
+ // foreach (BlockHeader? uncle in body.Uncles)
+ // {
+ // stream.Encode(uncle);
+ // }
+
+ // if (body.Withdrawals is not null)
+ // {
+ // stream.StartSequence(GetWithdrawalsLength(body.Withdrawals));
+ // foreach (Withdrawal? withdrawal in body.Withdrawals)
+ // {
+ // stream.Encode(withdrawal);
+ // }
+ // }
+ // }
+
+ BlockAccessList IRlpValueDecoder.Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors)
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetLength(BlockAccessList item, RlpBehaviors rlpBehaviors)
+ {
+ throw new NotImplementedException();
+ }
+
+ BlockAccessList IRlpStreamDecoder.Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Encode(RlpStream stream, BlockAccessList item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ {
+ throw new NotImplementedException();
+ }
+}
From 15bbab12c60dc3137cf7be21a6d4021886573c67 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 22 Aug 2025 15:20:03 +0100
Subject: [PATCH 029/215] move RLP decoding
---
.../{ => Eip7928}/BlockAccessListDecoder.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename src/Nethermind/Nethermind.Serialization.Rlp/{ => Eip7928}/BlockAccessListDecoder.cs (98%)
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/BlockAccessListDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs
similarity index 98%
rename from src/Nethermind/Nethermind.Serialization.Rlp/BlockAccessListDecoder.cs
rename to src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs
index 880c6176840..074ff75dfcc 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/BlockAccessListDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs
@@ -4,7 +4,7 @@
using System;
using Nethermind.Core.BlockAccessLists;
-namespace Nethermind.Serialization.Rlp;
+namespace Nethermind.Serialization.Rlp.Eip7928;
public class BlockAccessListDecoder : IRlpValueDecoder, IRlpStreamDecoder
{
From 7c31e87c10e47e9acf8fb646ded8f9027646d92d Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 22 Aug 2025 18:24:54 +0100
Subject: [PATCH 030/215] don't encode/decode for testing
---
.../Nethermind.Blockchain.Test/BlockAccessListTests.cs | 4 +++-
.../Nethermind.Consensus/Processing/BlockProcessor.cs | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index c5cc18a455d..bc98445671a 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -132,7 +132,9 @@ public void System_contracts_and_withdrawals()
};
(Block processedBlock, TxReceipt[] _) = processor.ProcessOne(block, ProcessingOptions.None, NullBlockTracer.Instance, spec, CancellationToken.None);
- SortedDictionary accountChanges = Rlp.Decode(processedBlock.BlockAccessList).AccountChanges;
+ // tmp
+ // SortedDictionary accountChanges = Rlp.Decode(processedBlock.BlockAccessList).AccountChanges;
+ SortedDictionary accountChanges = processedBlock.DecodedBlockAccessList!.Value.AccountChanges;
Assert.That(accountChanges, Has.Count.EqualTo(3));
List senderBalanceChanges = accountChanges[TestItem.AddressA].BalanceChanges;
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index 26a1cb5b9b2..155536b1c55 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -167,7 +167,9 @@ protected virtual TxReceipt[] ProcessBlock(
if (spec.BlockLevelAccessListsEnabled)
{
- body.BlockAccessList = Rlp.Encode(BlockAccessTracer.BlockAccessList).Bytes;
+ //tmp
+ block.DecodedBlockAccessList = BlockAccessTracer.BlockAccessList;
+ // body.BlockAccessList = Rlp.Encode(BlockAccessTracer.BlockAccessList).Bytes;
}
return receipts;
From 9015f703ac425f6346ff6428387f2fc696453282 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 22 Aug 2025 18:32:39 +0100
Subject: [PATCH 031/215] init beacon block roots address
---
.../Nethermind.Blockchain.Test/BlockAccessListTests.cs | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index bc98445671a..63c5033fcc9 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -14,6 +14,7 @@
using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
using Nethermind.Core.BlockAccessLists;
+using Nethermind.Core.Crypto;
using Nethermind.Core.Test.Builders;
using Nethermind.Evm.TransactionProcessing;
using Nethermind.Int256;
@@ -106,6 +107,8 @@ public void System_contracts_and_withdrawals()
new WithdrawalProcessor(_stateProvider, LimboLogs.Instance),
new ExecutionRequestsProcessor(_transactionProcessor));
+ _stateProvider.CreateAccount(Eip4788Constants.BeaconRootsAddress, 10);
+
ulong gasPrice = 2;
long gasLimit = 100000;
Transaction tx = Build.A.Transaction
@@ -117,6 +120,8 @@ public void System_contracts_and_withdrawals()
.TestObject;
Block block = Build.A.Block
+ .WithParentBeaconBlockRoot(Hash256.Zero)
+ .WithNumber(100)
.WithTransactions(tx)
.WithBaseFeePerGas(1)
.WithBeneficiary(TestItem.AddressC).TestObject;
From 8ac89395697c159b34f1bdb543d38ebd65796b2d Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 22 Aug 2025 18:41:46 +0100
Subject: [PATCH 032/215] setup execution requests contracts
---
.../Nethermind.Blockchain.Test/BlockAccessListTests.cs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index 63c5033fcc9..2aae0778869 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -15,6 +15,7 @@
using Nethermind.Core;
using Nethermind.Core.BlockAccessLists;
using Nethermind.Core.Crypto;
+using Nethermind.Core.Test;
using Nethermind.Core.Test.Builders;
using Nethermind.Evm.TransactionProcessing;
using Nethermind.Int256;
@@ -107,7 +108,12 @@ public void System_contracts_and_withdrawals()
new WithdrawalProcessor(_stateProvider, LimboLogs.Instance),
new ExecutionRequestsProcessor(_transactionProcessor));
+ // todo: just use test blockchain?
_stateProvider.CreateAccount(Eip4788Constants.BeaconRootsAddress, 10);
+ _stateProvider.CreateAccount(Eip7002Constants.WithdrawalRequestPredeployAddress, 0, Eip7002TestConstants.Nonce);
+ _stateProvider.InsertCode(Eip7002Constants.WithdrawalRequestPredeployAddress, Eip7002TestConstants.CodeHash, Eip7002TestConstants.Code, Prague.Instance);
+ _stateProvider.CreateAccount(Eip7251Constants.ConsolidationRequestPredeployAddress, 0, Eip7251TestConstants.Nonce);
+ _stateProvider.InsertCode(Eip7251Constants.ConsolidationRequestPredeployAddress, Eip7251TestConstants.CodeHash, Eip7251TestConstants.Code, Prague.Instance);
ulong gasPrice = 2;
long gasLimit = 100000;
From 4a507b6a5e7bd6e1facec75083bc7d4f7135e053 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 26 Aug 2025 12:07:02 +0100
Subject: [PATCH 033/215] start implementing rlp
---
.../BlockAccessListTests.cs | 20 +++++++++
.../Nethermind.Core/BlockAccessList.cs | 16 +++----
.../Eip7928/AccountChangesDecoder.cs | 39 +++++++++++++++++
.../Eip7928/BalanceChangeDecoder.cs | 42 ++++++++++++++++++
.../Eip7928/CodeChangeDecoder.cs | 42 ++++++++++++++++++
.../Eip7928/NonceChangeDecoder.cs | 42 ++++++++++++++++++
.../Eip7928/SlotChangesDecoder.cs | 43 +++++++++++++++++++
.../Eip7928/StorageChangeDecoder.cs | 42 ++++++++++++++++++
.../Nethermind.Serialization.Rlp/Rlp.cs | 39 +++++++++++++++++
9 files changed, 317 insertions(+), 8 deletions(-)
create mode 100644 src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
create mode 100644 src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
create mode 100644 src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
create mode 100644 src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
create mode 100644 src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
create mode 100644 src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index 2aae0778869..247559e0c45 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -168,5 +168,25 @@ public void System_contracts_and_withdrawals()
Assert.That(beneficiaryBalanceChanges[0].PostBalance, Is.EqualTo(new UInt256(GasCostOf.Transaction)));
}
}
+
+ [Test]
+ public void Fun_test()
+ {
+ StorageChange s = new()
+ {
+ BlockAccessIndex = 5,
+ NewValue = []
+ };
+ byte[] x = Rlp.Encode(s).Bytes;
+ // Assert.That(x, Has.Length.EqualTo(10));
+
+ BalanceChange b = new()
+ {
+ BlockAccessIndex = 5,
+ PostBalance = 69
+ };
+ byte[] y = Rlp.Encode(b).Bytes;
+ Assert.That(x, Has.Length.EqualTo(10));
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Core/BlockAccessList.cs b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
index 8d3e53442bd..160a3a0e79f 100644
--- a/src/Nethermind/Nethermind.Core/BlockAccessList.cs
+++ b/src/Nethermind/Nethermind.Core/BlockAccessList.cs
@@ -43,17 +43,17 @@ public struct CodeChange
public struct SlotChanges()
{
// [SszVector(32)]
- // public byte[] Slot { get; set; }
+ public byte[] Slot { get; set; } = [];
// [SszList(Eip7928Constants.MaxTxs)]
public List Changes { get; set; } = [];
}
-public struct StorageKey(ReadOnlySpan key)
-{
- // [SszVector(32)]
- public byte[] Key { get; set; } = key.ToArray();
-}
+// public struct StorageKey(ReadOnlySpan key)
+// {
+// // [SszVector(32)]
+// public byte[] Key { get; set; } = key.ToArray();
+// }
public struct AccountChanges(Address address)
{
@@ -62,11 +62,11 @@ public struct AccountChanges(Address address)
// Storage changes (slot -> [tx_index -> new_value])
// [SszList(Eip7928Constants.MaxSlots)]
- public SortedDictionary StorageChanges { get; set; } = [];
+ public SortedDictionary StorageChanges { get; set; } = [];
// Read-only storage keys
// [SszList(Eip7928Constants.MaxSlots)]
- public List StorageReads { get; set; } = [];
+ public List StorageReads { get; set; } = [];
// Balance changes ([tx_index -> post_balance])
// [SszList(Eip7928Constants.MaxTxs)]
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
new file mode 100644
index 00000000000..9d1e63a401c
--- /dev/null
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
@@ -0,0 +1,39 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using Nethermind.Core.BlockAccessLists;
+
+namespace Nethermind.Serialization.Rlp.Eip7928;
+
+public class AccountChangesDecoder : IRlpValueDecoder, IRlpStreamDecoder
+{
+ private static AccountChangesDecoder? _instance = null;
+ public static AccountChangesDecoder Instance => _instance ??= new();
+
+ public AccountChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
+ => new()
+ {
+ BlockAccessIndex = ctx.DecodeUShort(),
+ PostBalance = ctx.DecodeUInt256()
+ };
+
+ public int GetLength(AccountChanges item, RlpBehaviors rlpBehaviors) => Length;
+
+ public AccountChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
+ {
+ Span span = rlpStream.PeekNextItem();
+ Rlp.ValueDecoderContext ctx = new(span);
+ AccountChanges response = Decode(ref ctx, rlpBehaviors);
+ rlpStream.SkipItem();
+
+ return response;
+ }
+
+ public void Encode(RlpStream stream, AccountChanges item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ {
+ stream.StartSequence(Length);
+ stream.Encode(item.BlockAccessIndex);
+ stream.Encode(item.PostBalance);
+ }
+}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
new file mode 100644
index 00000000000..a58f309db1c
--- /dev/null
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
@@ -0,0 +1,42 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using Nethermind.Core.BlockAccessLists;
+
+namespace Nethermind.Serialization.Rlp.Eip7928;
+
+public class BalanceChangeDecoder : IRlpValueDecoder, IRlpStreamDecoder
+{
+ // ushort + UInt256
+ private const int Length = 2 + 32;
+
+ private static BalanceChangeDecoder? _instance = null;
+ public static BalanceChangeDecoder Instance => _instance ??= new();
+
+ public BalanceChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
+ => new()
+ {
+ BlockAccessIndex = ctx.DecodeUShort(),
+ PostBalance = ctx.DecodeUInt256()
+ };
+
+ public int GetLength(BalanceChange item, RlpBehaviors rlpBehaviors) => Length;
+
+ public BalanceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
+ {
+ Span span = rlpStream.PeekNextItem();
+ Rlp.ValueDecoderContext ctx = new(span);
+ BalanceChange response = Decode(ref ctx, rlpBehaviors);
+ rlpStream.SkipItem();
+
+ return response;
+ }
+
+ public void Encode(RlpStream stream, BalanceChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ {
+ stream.StartSequence(Length);
+ stream.Encode(item.BlockAccessIndex);
+ stream.Encode(item.PostBalance);
+ }
+}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
new file mode 100644
index 00000000000..63b66698739
--- /dev/null
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
@@ -0,0 +1,42 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using Nethermind.Core.BlockAccessLists;
+
+namespace Nethermind.Serialization.Rlp.Eip7928;
+
+public class CodeChangeDecoder : IRlpValueDecoder, IRlpStreamDecoder
+{
+ // ushort + UInt256
+ private const int Length = 2 + 32;
+
+ private static CodeChangeDecoder? _instance = null;
+ public static CodeChangeDecoder Instance => _instance ??= new();
+
+ public CodeChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
+ => new()
+ {
+ BlockAccessIndex = ctx.DecodeUShort(),
+ NewCode = ctx.DecodeByteArray()
+ };
+
+ public int GetLength(CodeChange item, RlpBehaviors rlpBehaviors) => Length;
+
+ public CodeChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
+ {
+ Span span = rlpStream.PeekNextItem();
+ Rlp.ValueDecoderContext ctx = new(span);
+ CodeChange response = Decode(ref ctx, rlpBehaviors);
+ rlpStream.SkipItem();
+
+ return response;
+ }
+
+ public void Encode(RlpStream stream, CodeChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ {
+ stream.StartSequence(Length);
+ stream.Encode(item.BlockAccessIndex);
+ stream.Encode(item.NewCode);
+ }
+}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
new file mode 100644
index 00000000000..6703dbf6616
--- /dev/null
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
@@ -0,0 +1,42 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using Nethermind.Core.BlockAccessLists;
+
+namespace Nethermind.Serialization.Rlp.Eip7928;
+
+public class NonceChangeDecoder : IRlpValueDecoder, IRlpStreamDecoder
+{
+ // ushort + UInt256
+ private const int Length = 2 + 32;
+
+ private static BalanceChangeDecoder? _instance = null;
+ public static BalanceChangeDecoder Instance => _instance ??= new();
+
+ public BalanceChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
+ => new()
+ {
+ BlockAccessIndex = ctx.DecodeUShort(),
+ PostBalance = ctx.DecodeUInt256()
+ };
+
+ public int GetLength(BalanceChange item, RlpBehaviors rlpBehaviors) => Length;
+
+ public BalanceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
+ {
+ Span span = rlpStream.PeekNextItem();
+ Rlp.ValueDecoderContext ctx = new(span);
+ BalanceChange response = Decode(ref ctx, rlpBehaviors);
+ rlpStream.SkipItem();
+
+ return response;
+ }
+
+ public void Encode(RlpStream stream, BalanceChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ {
+ stream.StartSequence(Length);
+ stream.Encode(item.BlockAccessIndex);
+ stream.Encode(item.PostBalance);
+ }
+}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
new file mode 100644
index 00000000000..467621714eb
--- /dev/null
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
@@ -0,0 +1,43 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Linq;
+using Nethermind.Core.BlockAccessLists;
+
+namespace Nethermind.Serialization.Rlp.Eip7928;
+
+public class SlotChangesDecoder : IRlpValueDecoder, IRlpStreamDecoder
+{
+ private static SlotChangesDecoder? _instance = null;
+ public static SlotChangesDecoder Instance => _instance ??= new();
+
+ public SlotChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
+ => new()
+ {
+ Slot = ctx.DecodeByteArray(),
+ Changes = [.. ctx.DecodeArray(StorageChangeDecoder.Instance)]
+ };
+
+ public int GetLength(SlotChanges item, RlpBehaviors rlpBehaviors) => 0;
+
+ public SlotChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
+ {
+ Span span = rlpStream.PeekNextItem();
+ Rlp.ValueDecoderContext ctx = new(span);
+ SlotChanges response = Decode(ref ctx, rlpBehaviors);
+ rlpStream.SkipItem();
+
+ return response;
+ }
+
+ public void Encode(RlpStream stream, SlotChanges item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ {
+ stream.StartSequence(0);
+ stream.Encode(item.Slot);
+ foreach (StorageChange change in item.Changes)
+ {
+ StorageChangeDecoder.Instance.Encode(stream, change);
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs
new file mode 100644
index 00000000000..993d4986823
--- /dev/null
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs
@@ -0,0 +1,42 @@
+// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using Nethermind.Core.BlockAccessLists;
+
+namespace Nethermind.Serialization.Rlp.Eip7928;
+
+public class StorageChangeDecoder : IRlpValueDecoder, IRlpStreamDecoder
+{
+ // ushort + 32 byte vector
+ private const int Length = 2 + 32;
+
+ private static StorageChangeDecoder? _instance = null;
+ public static StorageChangeDecoder Instance => _instance ??= new();
+
+ public StorageChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
+ => new()
+ {
+ BlockAccessIndex = ctx.DecodeUShort(),
+ NewValue = ctx.DecodeByteArray()
+ };
+
+ public int GetLength(StorageChange item, RlpBehaviors rlpBehaviors) => Length;
+
+ public StorageChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
+ {
+ Span span = rlpStream.PeekNextItem();
+ Rlp.ValueDecoderContext ctx = new(span);
+ StorageChange response = Decode(ref ctx, rlpBehaviors);
+ rlpStream.SkipItem();
+
+ return response;
+ }
+
+ public void Encode(RlpStream stream, StorageChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ {
+ stream.StartSequence(Length);
+ stream.Encode(item.BlockAccessIndex);
+ stream.Encode(item.NewValue);
+ }
+}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs
index 582df031495..642ba81bae2 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs
@@ -1573,6 +1573,45 @@ internal byte[][] DecodeByteArrays()
return result;
}
+ public ushort DecodeUShort()
+ {
+ int prefix = ReadByte();
+
+ switch (prefix)
+ {
+ case 0:
+ throw new RlpException($"Non-canonical ushort (leading zero bytes) at position {Position}");
+ case < 128:
+ return (ushort)prefix;
+ case 128:
+ return 0;
+ }
+
+ int length = prefix - 128;
+ if (length > 8)
+ {
+ throw new RlpException($"Unexpected length of ushort value: {length}");
+ }
+
+ ushort result = 0;
+ for (int i = 2; i > 0; i--)
+ {
+ result <<= 8;
+ if (i <= length)
+ {
+ result |= PeekByte(length - i);
+ if (result == 0)
+ {
+ throw new RlpException($"Non-canonical ushort (leading zero bytes) at position {Position}");
+ }
+ }
+ }
+
+ SkipBytes(length);
+
+ return result;
+ }
+
public byte DecodeByte()
{
byte byteValue = PeekByte();
From 87dc02c45175b74ce02621b1a132d7085ebf7754 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Tue, 26 Aug 2025 16:10:30 +0100
Subject: [PATCH 034/215] account changes rlp+
---
.../Eip7928/AccountChangesDecoder.cs | 80 +++++++++++++++++--
.../Eip7928/CodeChangeDecoder.cs | 7 +-
.../Eip7928/NonceChangeDecoder.cs | 24 +++---
.../Eip7928/SlotChangesDecoder.cs | 12 ++-
4 files changed, 98 insertions(+), 25 deletions(-)
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
index 9d1e63a401c..7574830ba64 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
@@ -2,6 +2,8 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using System.Collections.Generic;
+using System.Linq;
using Nethermind.Core.BlockAccessLists;
namespace Nethermind.Serialization.Rlp.Eip7928;
@@ -12,13 +14,53 @@ public class AccountChangesDecoder : IRlpValueDecoder, IRlpStrea
public static AccountChangesDecoder Instance => _instance ??= new();
public AccountChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
- => new()
+ {
+ byte[] address = ctx.DecodeAddress().Bytes;
+ SlotChanges[] slotChanges = ctx.DecodeArray(SlotChangesDecoder.Instance);
+ SortedDictionary slotChangesMap = new(slotChanges.ToDictionary(s => s.Slot, s => s));
+ byte[][] storageReads = ctx.DecodeByteArrays();
+ BalanceChange[] balanceChanges = ctx.DecodeArray(BalanceChangeDecoder.Instance);
+ NonceChange[] nonceChanges = ctx.DecodeArray(NonceChangeDecoder.Instance);
+ CodeChange[] codeChanges = ctx.DecodeArray(CodeChangeDecoder.Instance);
+ return new()
{
- BlockAccessIndex = ctx.DecodeUShort(),
- PostBalance = ctx.DecodeUInt256()
+ Address = address,
+ StorageChanges = slotChangesMap,
+ StorageReads = [.. storageReads],
+ BalanceChanges = [.. balanceChanges],
+ NonceChanges = [.. nonceChanges],
+ CodeChanges = [.. codeChanges]
};
+ }
+
+ public int GetLength(AccountChanges item, RlpBehaviors rlpBehaviors)
+ {
+ int len = 20; // address
+
+ foreach (SlotChanges slotChanges in item.StorageChanges.Values)
+ {
+ len += SlotChangesDecoder.Instance.GetLength(slotChanges, rlpBehaviors);
+ }
+
+ len += item.StorageReads.Count * 32;
+
+ foreach (BalanceChange balanceChange in item.BalanceChanges)
+ {
+ len += BalanceChangeDecoder.Instance.GetLength(balanceChange, rlpBehaviors);
+ }
+
+ foreach (NonceChange nonceChange in item.NonceChanges)
+ {
+ len += NonceChangeDecoder.Instance.GetLength(nonceChange, rlpBehaviors);
+ }
+
+ foreach (CodeChange codeChange in item.CodeChanges)
+ {
+ len += CodeChangeDecoder.Instance.GetLength(codeChange, rlpBehaviors);
+ }
- public int GetLength(AccountChanges item, RlpBehaviors rlpBehaviors) => Length;
+ return len;
+ }
public AccountChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
@@ -32,8 +74,32 @@ public AccountChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
public void Encode(RlpStream stream, AccountChanges item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- stream.StartSequence(Length);
- stream.Encode(item.BlockAccessIndex);
- stream.Encode(item.PostBalance);
+ stream.StartSequence(GetLength(item, rlpBehaviors));
+ stream.Encode(item.Address);
+
+ foreach (SlotChanges slotChanges in item.StorageChanges.Values)
+ {
+ SlotChangesDecoder.Instance.Encode(stream, slotChanges);
+ }
+
+ foreach (byte[] storageKey in item.StorageReads)
+ {
+ stream.Encode(storageKey);
+ }
+
+ foreach (BalanceChange balanceChange in item.BalanceChanges)
+ {
+ BalanceChangeDecoder.Instance.Encode(stream, balanceChange);
+ }
+
+ foreach (NonceChange nonceChange in item.NonceChanges)
+ {
+ NonceChangeDecoder.Instance.Encode(stream, nonceChange);
+ }
+
+ foreach (CodeChange codeChange in item.CodeChanges)
+ {
+ CodeChangeDecoder.Instance.Encode(stream, codeChange);
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
index 63b66698739..00e22fce156 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
@@ -8,9 +8,6 @@ namespace Nethermind.Serialization.Rlp.Eip7928;
public class CodeChangeDecoder : IRlpValueDecoder, IRlpStreamDecoder
{
- // ushort + UInt256
- private const int Length = 2 + 32;
-
private static CodeChangeDecoder? _instance = null;
public static CodeChangeDecoder Instance => _instance ??= new();
@@ -21,7 +18,7 @@ public CodeChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehavi
NewCode = ctx.DecodeByteArray()
};
- public int GetLength(CodeChange item, RlpBehaviors rlpBehaviors) => Length;
+ public int GetLength(CodeChange item, RlpBehaviors rlpBehaviors) => 2 + item.NewCode.Length;
public CodeChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
@@ -35,7 +32,7 @@ public CodeChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
public void Encode(RlpStream stream, CodeChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- stream.StartSequence(Length);
+ stream.StartSequence(GetLength(item, rlpBehaviors));
stream.Encode(item.BlockAccessIndex);
stream.Encode(item.NewCode);
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
index 6703dbf6616..ff72867bfcd 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
@@ -6,37 +6,37 @@
namespace Nethermind.Serialization.Rlp.Eip7928;
-public class NonceChangeDecoder : IRlpValueDecoder, IRlpStreamDecoder
+public class NonceChangeDecoder : IRlpValueDecoder, IRlpStreamDecoder
{
- // ushort + UInt256
- private const int Length = 2 + 32;
+ // ushort + ulong
+ private const int Length = 2 + 8;
- private static BalanceChangeDecoder? _instance = null;
- public static BalanceChangeDecoder Instance => _instance ??= new();
+ private static NonceChangeDecoder? _instance = null;
+ public static NonceChangeDecoder Instance => _instance ??= new();
- public BalanceChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
+ public NonceChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
=> new()
{
BlockAccessIndex = ctx.DecodeUShort(),
- PostBalance = ctx.DecodeUInt256()
+ NewNonce = ctx.DecodeULong()
};
- public int GetLength(BalanceChange item, RlpBehaviors rlpBehaviors) => Length;
+ public int GetLength(NonceChange item, RlpBehaviors rlpBehaviors) => Length;
- public BalanceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
+ public NonceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
Span span = rlpStream.PeekNextItem();
Rlp.ValueDecoderContext ctx = new(span);
- BalanceChange response = Decode(ref ctx, rlpBehaviors);
+ NonceChange response = Decode(ref ctx, rlpBehaviors);
rlpStream.SkipItem();
return response;
}
- public void Encode(RlpStream stream, BalanceChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
+ public void Encode(RlpStream stream, NonceChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
stream.StartSequence(Length);
stream.Encode(item.BlockAccessIndex);
- stream.Encode(item.PostBalance);
+ stream.Encode(item.NewNonce);
}
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
index 467621714eb..12c3ea10a36 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
@@ -19,7 +19,17 @@ public SlotChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehav
Changes = [.. ctx.DecodeArray(StorageChangeDecoder.Instance)]
};
- public int GetLength(SlotChanges item, RlpBehaviors rlpBehaviors) => 0;
+ public int GetLength(SlotChanges item, RlpBehaviors rlpBehaviors)
+ {
+ int len = 32; // slot
+
+ foreach (StorageChange slotChange in item.Changes)
+ {
+ len += StorageChangeDecoder.Instance.GetLength(slotChange, rlpBehaviors);
+ }
+
+ return len;
+ }
public SlotChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
From a9f0e93c04de88ec3541c7185c92d7bb2c2bed32 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Wed, 27 Aug 2025 10:58:39 +0100
Subject: [PATCH 035/215] bal encoding / decoding
---
.../BlockAccessListTests.cs | 20 ---
.../Eip7928/AccountChangesDecoder.cs | 4 +-
.../Eip7928/BalanceChangeDecoder.cs | 4 +-
.../Eip7928/BlockAccessListDecoder.cs | 138 ++++--------------
.../Eip7928/CodeChangeDecoder.cs | 4 +-
.../Eip7928/NonceChangeDecoder.cs | 4 +-
.../Eip7928/SlotChangesDecoder.cs | 4 +-
.../Eip7928/StorageChangeDecoder.cs | 4 +-
8 files changed, 43 insertions(+), 139 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index 247559e0c45..2aae0778869 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -168,25 +168,5 @@ public void System_contracts_and_withdrawals()
Assert.That(beneficiaryBalanceChanges[0].PostBalance, Is.EqualTo(new UInt256(GasCostOf.Transaction)));
}
}
-
- [Test]
- public void Fun_test()
- {
- StorageChange s = new()
- {
- BlockAccessIndex = 5,
- NewValue = []
- };
- byte[] x = Rlp.Encode(s).Bytes;
- // Assert.That(x, Has.Length.EqualTo(10));
-
- BalanceChange b = new()
- {
- BlockAccessIndex = 5,
- PostBalance = 69
- };
- byte[] y = Rlp.Encode(b).Bytes;
- Assert.That(x, Has.Length.EqualTo(10));
- }
}
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
index 7574830ba64..8aca07f706f 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
@@ -66,10 +66,10 @@ public AccountChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
Span span = rlpStream.PeekNextItem();
Rlp.ValueDecoderContext ctx = new(span);
- AccountChanges response = Decode(ref ctx, rlpBehaviors);
+ AccountChanges res = Decode(ref ctx, rlpBehaviors);
rlpStream.SkipItem();
- return response;
+ return res;
}
public void Encode(RlpStream stream, AccountChanges item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
index a58f309db1c..c526b31b3e1 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
@@ -27,10 +27,10 @@ public BalanceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
Span span = rlpStream.PeekNextItem();
Rlp.ValueDecoderContext ctx = new(span);
- BalanceChange response = Decode(ref ctx, rlpBehaviors);
+ BalanceChange res = Decode(ref ctx, rlpBehaviors);
rlpStream.SkipItem();
- return response;
+ return res;
}
public void Encode(RlpStream stream, BalanceChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs
index 074ff75dfcc..a88428c04ee 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs
@@ -2,133 +2,57 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using System.Collections.Generic;
+using System.Linq;
+using Nethermind.Core;
using Nethermind.Core.BlockAccessLists;
namespace Nethermind.Serialization.Rlp.Eip7928;
public class BlockAccessListDecoder : IRlpValueDecoder, IRlpStreamDecoder
{
- // private readonly TxDecoder _txDecoder = TxDecoder.Instance;
- // private readonly HeaderDecoder _headerDecoder = new();
- // private readonly WithdrawalDecoder _withdrawalDecoderDecoder = new();
-
private static BlockAccessListDecoder? _instance = null;
public static BlockAccessListDecoder Instance => _instance ??= new();
- // public int GetLength(BlockBody item, RlpBehaviors rlpBehaviors)
- // {
- // return Rlp.LengthOfSequence(GetBodyLength(item));
- // }
-
- // public int GetBodyLength(BlockBody b)
- // {
- // (int txs, int uncles, int? withdrawals) = GetBodyComponentLength(b);
- // return Rlp.LengthOfSequence(txs) +
- // Rlp.LengthOfSequence(uncles) +
- // (withdrawals is not null ? Rlp.LengthOfSequence(withdrawals.Value) : 0);
- // }
-
- // public (int Txs, int Uncles, int? Withdrawals) GetBodyComponentLength(BlockBody b) =>
- // (
- // GetTxLength(b.Transactions),
- // GetUnclesLength(b.Uncles),
- // b.Withdrawals is not null ? GetWithdrawalsLength(b.Withdrawals) : null
- // );
-
- // private int GetTxLength(Transaction[] transactions)
- // {
- // if (transactions.Length == 0) return 0;
-
- // int sum = 0;
- // foreach (Transaction tx in transactions)
- // {
- // sum += _txDecoder.GetLength(tx, RlpBehaviors.None);
- // }
-
- // return sum;
- // }
-
- // public BlockBody? Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
- // {
- // int sequenceLength = ctx.ReadSequenceLength();
- // int startingPosition = ctx.Position;
- // if (sequenceLength == 0)
- // {
- // return null;
- // }
-
- // return DecodeUnwrapped(ref ctx, startingPosition + sequenceLength);
- // }
-
- // public BlockBody? DecodeUnwrapped(ref Rlp.ValueDecoderContext ctx, int lastPosition)
- // {
-
- // // quite significant allocations (>0.5%) here based on a sample 3M blocks sync
- // // (just on these delegates)
- // Transaction[] transactions = ctx.DecodeArray(_txDecoder);
- // BlockHeader[] uncles = ctx.DecodeArray(_headerDecoder);
- // Withdrawal[]? withdrawals = null;
-
- // if (ctx.PeekNumberOfItemsRemaining(lastPosition, 1) > 0)
- // {
- // withdrawals = ctx.DecodeArray(_withdrawalDecoderDecoder);
- // }
-
- // return new BlockBody(transactions, uncles, withdrawals);
- // }
-
- // public BlockBody Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
- // {
- // Span span = rlpStream.PeekNextItem();
- // Rlp.ValueDecoderContext ctx = new Rlp.ValueDecoderContext(span);
- // BlockBody response = Decode(ref ctx, rlpBehaviors);
- // rlpStream.SkipItem();
-
- // return response;
- // }
-
- // public void Encode(RlpStream stream, BlockBody body, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
- // {
- // stream.StartSequence(GetBodyLength(body));
- // stream.StartSequence(GetTxLength(body.Transactions));
- // foreach (Transaction? txn in body.Transactions)
- // {
- // stream.Encode(txn);
- // }
-
- // stream.StartSequence(GetUnclesLength(body.Uncles));
- // foreach (BlockHeader? uncle in body.Uncles)
- // {
- // stream.Encode(uncle);
- // }
+ public int GetLength(BlockAccessList item, RlpBehaviors rlpBehaviors)
+ {
+ int len = 0;
- // if (body.Withdrawals is not null)
- // {
- // stream.StartSequence(GetWithdrawalsLength(body.Withdrawals));
- // foreach (Withdrawal? withdrawal in body.Withdrawals)
- // {
- // stream.Encode(withdrawal);
- // }
- // }
- // }
+ foreach (AccountChanges accountChange in item.AccountChanges.Values)
+ {
+ len += AccountChangesDecoder.Instance.GetLength(accountChange, rlpBehaviors);
+ }
- BlockAccessList IRlpValueDecoder.Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors)
- {
- throw new NotImplementedException();
+ return len;
}
- public int GetLength(BlockAccessList item, RlpBehaviors rlpBehaviors)
+ public BlockAccessList Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
{
- throw new NotImplementedException();
+ AccountChanges[] accountChanges = ctx.DecodeArray(AccountChangesDecoder.Instance);
+ SortedDictionary accountChangesMap = new(accountChanges.ToDictionary(a => new Address(a.Address), a => a));
+ return new()
+ {
+ AccountChanges = accountChangesMap
+ };
}
- BlockAccessList IRlpStreamDecoder.Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
+ public BlockAccessList Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
- throw new NotImplementedException();
+ Span span = rlpStream.PeekNextItem();
+ Rlp.ValueDecoderContext ctx = new(span);
+ BlockAccessList res = Decode(ref ctx, rlpBehaviors);
+ rlpStream.SkipItem();
+
+ return res;
}
public void Encode(RlpStream stream, BlockAccessList item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- throw new NotImplementedException();
+ stream.StartSequence(GetLength(item, rlpBehaviors));
+
+ foreach (AccountChanges accountChanges in item.AccountChanges.Values)
+ {
+ AccountChangesDecoder.Instance.Encode(stream, accountChanges);
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
index 00e22fce156..64199c527f1 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
@@ -24,10 +24,10 @@ public CodeChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
Span span = rlpStream.PeekNextItem();
Rlp.ValueDecoderContext ctx = new(span);
- CodeChange response = Decode(ref ctx, rlpBehaviors);
+ CodeChange res = Decode(ref ctx, rlpBehaviors);
rlpStream.SkipItem();
- return response;
+ return res;
}
public void Encode(RlpStream stream, CodeChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
index ff72867bfcd..3d95b07ddbc 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
@@ -27,10 +27,10 @@ public NonceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
Span span = rlpStream.PeekNextItem();
Rlp.ValueDecoderContext ctx = new(span);
- NonceChange response = Decode(ref ctx, rlpBehaviors);
+ NonceChange res= Decode(ref ctx, rlpBehaviors);
rlpStream.SkipItem();
- return response;
+ return res;
}
public void Encode(RlpStream stream, NonceChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
index 12c3ea10a36..bd0606ee86f 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
@@ -35,10 +35,10 @@ public SlotChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
Span span = rlpStream.PeekNextItem();
Rlp.ValueDecoderContext ctx = new(span);
- SlotChanges response = Decode(ref ctx, rlpBehaviors);
+ SlotChanges res = Decode(ref ctx, rlpBehaviors);
rlpStream.SkipItem();
- return response;
+ return res;
}
public void Encode(RlpStream stream, SlotChanges item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs
index 993d4986823..6d928b1fc64 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs
@@ -27,10 +27,10 @@ public StorageChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
Span span = rlpStream.PeekNextItem();
Rlp.ValueDecoderContext ctx = new(span);
- StorageChange response = Decode(ref ctx, rlpBehaviors);
+ StorageChange res = Decode(ref ctx, rlpBehaviors);
rlpStream.SkipItem();
- return response;
+ return res;
}
public void Encode(RlpStream stream, StorageChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
From d12d0b5d8267dcc3763a58bb9fa974a3cebbc254 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Wed, 27 Aug 2025 11:05:12 +0100
Subject: [PATCH 036/215] change storagekey to bytes, use rlp in test
---
.../Nethermind.Blockchain.Test/BlockAccessListTests.cs | 4 ++--
.../Nethermind.Blockchain/Tracing/BlockAccessTracer.cs | 9 +++------
.../Nethermind.Consensus/Processing/BlockProcessor.cs | 4 ++--
3 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index 2aae0778869..3963ba98cc8 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -144,8 +144,8 @@ public void System_contracts_and_withdrawals()
(Block processedBlock, TxReceipt[] _) = processor.ProcessOne(block, ProcessingOptions.None, NullBlockTracer.Instance, spec, CancellationToken.None);
// tmp
- // SortedDictionary accountChanges = Rlp.Decode(processedBlock.BlockAccessList).AccountChanges;
- SortedDictionary accountChanges = processedBlock.DecodedBlockAccessList!.Value.AccountChanges;
+ SortedDictionary accountChanges = Rlp.Decode(processedBlock.BlockAccessList).AccountChanges;
+ // SortedDictionary accountChanges = processedBlock.DecodedBlockAccessList!.Value.AccountChanges;
Assert.That(accountChanges, Has.Count.EqualTo(3));
List senderBalanceChanges = accountChanges[TestItem.AddressA].BalanceChanges;
diff --git a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
index 68f6a00483f..a3894486f6a 100644
--- a/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Tracing/BlockAccessTracer.cs
@@ -179,11 +179,8 @@ public void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[
public void ReportStorageRead(in StorageCell storageCell)
{
- StorageKey storageKey = new()
- {
- Key = storageCell.Hash.ToByteArray()
- };
- Address address = Address.Zero;
+ byte[] storageKey = storageCell.Hash.ToByteArray();
+ Address address = storageCell.Address;
if (!_bal.AccountChanges.TryGetValue(address, out AccountChanges accountChanges))
{
@@ -304,7 +301,7 @@ private void StorageChange(AccountChanges accountChanges, in ReadOnlySpan
NewValue = value.ToArray()
};
- StorageKey storageKey = new(key);
+ byte[] storageKey = [.. key];
if (!accountChanges.StorageChanges.TryGetValue(storageKey, out SlotChanges storageChanges))
{
storageChanges = new();
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index 155536b1c55..bf1d2b595c4 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -168,8 +168,8 @@ protected virtual TxReceipt[] ProcessBlock(
if (spec.BlockLevelAccessListsEnabled)
{
//tmp
- block.DecodedBlockAccessList = BlockAccessTracer.BlockAccessList;
- // body.BlockAccessList = Rlp.Encode(BlockAccessTracer.BlockAccessList).Bytes;
+ // block.DecodedBlockAccessList = BlockAccessTracer.BlockAccessList;
+ body.BlockAccessList = Rlp.Encode(BlockAccessTracer.BlockAccessList).Bytes;
}
return receipts;
From 3223680e8241e3aa03e41189c4fe48326cced66e Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Wed, 27 Aug 2025 13:15:16 +0100
Subject: [PATCH 037/215] always start new sequence rlp
---
.../Eip7928/AccountChangesDecoder.cs | 85 +++++++++++++------
.../Eip7928/SlotChangesDecoder.cs | 10 ++-
2 files changed, 64 insertions(+), 31 deletions(-)
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
index 8aca07f706f..192a4a2561b 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Nethermind.Core;
using Nethermind.Core.BlockAccessLists;
namespace Nethermind.Serialization.Rlp.Eip7928;
@@ -34,33 +35,7 @@ public AccountChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBe
}
public int GetLength(AccountChanges item, RlpBehaviors rlpBehaviors)
- {
- int len = 20; // address
-
- foreach (SlotChanges slotChanges in item.StorageChanges.Values)
- {
- len += SlotChangesDecoder.Instance.GetLength(slotChanges, rlpBehaviors);
- }
-
- len += item.StorageReads.Count * 32;
-
- foreach (BalanceChange balanceChange in item.BalanceChanges)
- {
- len += BalanceChangeDecoder.Instance.GetLength(balanceChange, rlpBehaviors);
- }
-
- foreach (NonceChange nonceChange in item.NonceChanges)
- {
- len += NonceChangeDecoder.Instance.GetLength(nonceChange, rlpBehaviors);
- }
-
- foreach (CodeChange codeChange in item.CodeChanges)
- {
- len += CodeChangeDecoder.Instance.GetLength(codeChange, rlpBehaviors);
- }
-
- return len;
- }
+ => GetContentLength(item, rlpBehaviors).Total;
public AccountChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
@@ -74,32 +49,86 @@ public AccountChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
public void Encode(RlpStream stream, AccountChanges item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- stream.StartSequence(GetLength(item, rlpBehaviors));
+ ContentLengths contentLengths = GetContentLength(item, rlpBehaviors);
+ stream.StartSequence(contentLengths.Total);
stream.Encode(item.Address);
+ stream.StartSequence(contentLengths.SlotChanges);
foreach (SlotChanges slotChanges in item.StorageChanges.Values)
{
SlotChangesDecoder.Instance.Encode(stream, slotChanges);
}
+ stream.StartSequence(contentLengths.StorageReads);
foreach (byte[] storageKey in item.StorageReads)
{
stream.Encode(storageKey);
}
+ stream.StartSequence(contentLengths.BalanceChanges);
foreach (BalanceChange balanceChange in item.BalanceChanges)
{
BalanceChangeDecoder.Instance.Encode(stream, balanceChange);
}
+ stream.StartSequence(contentLengths.NonceChanges);
foreach (NonceChange nonceChange in item.NonceChanges)
{
NonceChangeDecoder.Instance.Encode(stream, nonceChange);
}
+ stream.StartSequence(contentLengths.CodeChanges);
foreach (CodeChange codeChange in item.CodeChanges)
{
CodeChangeDecoder.Instance.Encode(stream, codeChange);
}
}
+
+ private static ContentLengths GetContentLength(AccountChanges item, RlpBehaviors rlpBehaviors)
+ {
+ ContentLengths res = new()
+ {
+ Total = Address.Size,
+ SlotChanges = 0,
+ StorageReads = 0,
+ BalanceChanges = 0,
+ NonceChanges = 0,
+ CodeChanges = 0
+ };
+
+ foreach (SlotChanges slotChanges in item.StorageChanges.Values)
+ {
+ res.SlotChanges += SlotChangesDecoder.Instance.GetLength(slotChanges, rlpBehaviors);
+ }
+
+ res.StorageReads = item.StorageReads.Count * 32;
+
+ foreach (BalanceChange balanceChange in item.BalanceChanges)
+ {
+ res.BalanceChanges += BalanceChangeDecoder.Instance.GetLength(balanceChange, rlpBehaviors);
+ }
+
+ foreach (NonceChange nonceChange in item.NonceChanges)
+ {
+ res.NonceChanges += NonceChangeDecoder.Instance.GetLength(nonceChange, rlpBehaviors);
+ }
+
+ foreach (CodeChange codeChange in item.CodeChanges)
+ {
+ res.CodeChanges += CodeChangeDecoder.Instance.GetLength(codeChange, rlpBehaviors);
+ }
+
+ res.Total += res.SlotChanges + res.StorageReads + res.BalanceChanges + res.NonceChanges + res.CodeChanges;
+ return res;
+ }
+
+ private struct ContentLengths
+ {
+ public int Total;
+ public int SlotChanges;
+ public int StorageReads;
+ public int BalanceChanges;
+ public int NonceChanges;
+ public int CodeChanges;
+ }
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
index bd0606ee86f..c27ff75d315 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
-using System.Linq;
using Nethermind.Core.BlockAccessLists;
namespace Nethermind.Serialization.Rlp.Eip7928;
@@ -12,6 +11,8 @@ public class SlotChangesDecoder : IRlpValueDecoder, IRlpStreamDecod
private static SlotChangesDecoder? _instance = null;
public static SlotChangesDecoder Instance => _instance ??= new();
+ private const int SlotSize = 32;
+
public SlotChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
=> new()
{
@@ -21,7 +22,7 @@ public SlotChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehav
public int GetLength(SlotChanges item, RlpBehaviors rlpBehaviors)
{
- int len = 32; // slot
+ int len = SlotSize;
foreach (StorageChange slotChange in item.Changes)
{
@@ -43,8 +44,11 @@ public SlotChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
public void Encode(RlpStream stream, SlotChanges item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- stream.StartSequence(0);
+ int len = GetLength(item, rlpBehaviors);
+ stream.StartSequence(len);
stream.Encode(item.Slot);
+
+ stream.StartSequence(len - SlotSize);
foreach (StorageChange change in item.Changes)
{
StorageChangeDecoder.Instance.Encode(stream, change);
From 7009deed72cdb6d58bf19329e5c1c1ac0c0357e3 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Wed, 27 Aug 2025 17:13:54 +0100
Subject: [PATCH 038/215] fix bal encoding length
---
.../BlockAccessListTests.cs | 9 +++++++
.../Eip7928/BlockAccessListDecoder.cs | 25 +++++++++++--------
2 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index 3963ba98cc8..d14f838c765 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -93,6 +93,15 @@ public void Balance_and_nonce_changes()
}
}
+ [Test]
+ public void Encoding_decoding_test()
+ {
+ BlockAccessList b = new();
+ byte[] bytes = Rlp.Encode(b).Bytes;
+ BlockAccessList b2 = Rlp.Decode(bytes);
+ Assert.That(b, Is.EqualTo(b2));
+ }
+
[Test]
public void System_contracts_and_withdrawals()
{
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs
index a88428c04ee..ec385d2011a 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BlockAccessListDecoder.cs
@@ -15,16 +15,7 @@ public class BlockAccessListDecoder : IRlpValueDecoder, IRlpStr
public static BlockAccessListDecoder Instance => _instance ??= new();
public int GetLength(BlockAccessList item, RlpBehaviors rlpBehaviors)
- {
- int len = 0;
-
- foreach (AccountChanges accountChange in item.AccountChanges.Values)
- {
- len += AccountChangesDecoder.Instance.GetLength(accountChange, rlpBehaviors);
- }
-
- return len;
- }
+ => Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors));
public BlockAccessList Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
{
@@ -48,11 +39,23 @@ public BlockAccessList Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
public void Encode(RlpStream stream, BlockAccessList item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- stream.StartSequence(GetLength(item, rlpBehaviors));
+ stream.StartSequence(GetContentLength(item, rlpBehaviors));
foreach (AccountChanges accountChanges in item.AccountChanges.Values)
{
AccountChangesDecoder.Instance.Encode(stream, accountChanges);
}
}
+
+ private static int GetContentLength(BlockAccessList item, RlpBehaviors rlpBehaviors)
+ {
+ int len = 0;
+
+ foreach (AccountChanges accountChange in item.AccountChanges.Values)
+ {
+ len += AccountChangesDecoder.Instance.GetLength(accountChange, rlpBehaviors);
+ }
+
+ return len;
+ }
}
From f30d1b5c2189bd6c2195b3d1f9146a1f43d2f4b0 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Wed, 27 Aug 2025 17:42:12 +0100
Subject: [PATCH 039/215] fix all rlp lengths
---
.../BlockAccessListTests.cs | 2 +-
.../Eip7928/AccountChangesDecoder.cs | 11 ++++---
.../Eip7928/BalanceChangeDecoder.cs | 11 +++----
.../Eip7928/CodeChangeDecoder.cs | 6 +++-
.../Eip7928/NonceChangeDecoder.cs | 11 +++----
.../Eip7928/SlotChangesDecoder.cs | 30 +++++++++++--------
.../Eip7928/StorageChangeDecoder.cs | 11 +++----
.../Nethermind.Serialization.Rlp/Rlp.cs | 13 ++++++++
8 files changed, 61 insertions(+), 34 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index d14f838c765..e3ac6f75a0a 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -93,13 +93,13 @@ public void Balance_and_nonce_changes()
}
}
+ // tmp
[Test]
public void Encoding_decoding_test()
{
BlockAccessList b = new();
byte[] bytes = Rlp.Encode(b).Bytes;
BlockAccessList b2 = Rlp.Decode(bytes);
- Assert.That(b, Is.EqualTo(b2));
}
[Test]
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
index 192a4a2561b..403b1ba8f76 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Nethermind.Core;
using Nethermind.Core.BlockAccessLists;
namespace Nethermind.Serialization.Rlp.Eip7928;
@@ -35,7 +34,7 @@ public AccountChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBe
}
public int GetLength(AccountChanges item, RlpBehaviors rlpBehaviors)
- => GetContentLength(item, rlpBehaviors).Total;
+ => Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors).Total);
public AccountChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
@@ -88,7 +87,7 @@ private static ContentLengths GetContentLength(AccountChanges item, RlpBehaviors
{
ContentLengths res = new()
{
- Total = Address.Size,
+ Total = Rlp.LengthOfAddressRlp,
SlotChanges = 0,
StorageReads = 0,
BalanceChanges = 0,
@@ -100,23 +99,27 @@ private static ContentLengths GetContentLength(AccountChanges item, RlpBehaviors
{
res.SlotChanges += SlotChangesDecoder.Instance.GetLength(slotChanges, rlpBehaviors);
}
+ res.SlotChanges = Rlp.LengthOfSequence(res.SlotChanges);
- res.StorageReads = item.StorageReads.Count * 32;
+ res.StorageReads = Rlp.LengthOfSequence(item.StorageReads.Count * 32);
foreach (BalanceChange balanceChange in item.BalanceChanges)
{
res.BalanceChanges += BalanceChangeDecoder.Instance.GetLength(balanceChange, rlpBehaviors);
}
+ res.BalanceChanges = Rlp.LengthOfSequence(res.BalanceChanges);
foreach (NonceChange nonceChange in item.NonceChanges)
{
res.NonceChanges += NonceChangeDecoder.Instance.GetLength(nonceChange, rlpBehaviors);
}
+ res.NonceChanges = Rlp.LengthOfSequence(res.NonceChanges);
foreach (CodeChange codeChange in item.CodeChanges)
{
res.CodeChanges += CodeChangeDecoder.Instance.GetLength(codeChange, rlpBehaviors);
}
+ res.CodeChanges = Rlp.LengthOfSequence(res.CodeChanges);
res.Total += res.SlotChanges + res.StorageReads + res.BalanceChanges + res.NonceChanges + res.CodeChanges;
return res;
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
index c526b31b3e1..d1a717819da 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
@@ -8,9 +8,6 @@ namespace Nethermind.Serialization.Rlp.Eip7928;
public class BalanceChangeDecoder : IRlpValueDecoder, IRlpStreamDecoder
{
- // ushort + UInt256
- private const int Length = 2 + 32;
-
private static BalanceChangeDecoder? _instance = null;
public static BalanceChangeDecoder Instance => _instance ??= new();
@@ -21,7 +18,8 @@ public BalanceChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBeh
PostBalance = ctx.DecodeUInt256()
};
- public int GetLength(BalanceChange item, RlpBehaviors rlpBehaviors) => Length;
+ public int GetLength(BalanceChange item, RlpBehaviors rlpBehaviors)
+ => Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors));
public BalanceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
@@ -35,8 +33,11 @@ public BalanceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
public void Encode(RlpStream stream, BalanceChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- stream.StartSequence(Length);
+ stream.StartSequence(GetContentLength(item, rlpBehaviors));
stream.Encode(item.BlockAccessIndex);
stream.Encode(item.PostBalance);
}
+
+ public static int GetContentLength(BalanceChange item, RlpBehaviors rlpBehaviors)
+ => Rlp.LengthOf(item.BlockAccessIndex) + Rlp.LengthOf(item.PostBalance);
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
index 64199c527f1..61519946373 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/CodeChangeDecoder.cs
@@ -18,7 +18,8 @@ public CodeChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehavi
NewCode = ctx.DecodeByteArray()
};
- public int GetLength(CodeChange item, RlpBehaviors rlpBehaviors) => 2 + item.NewCode.Length;
+ public int GetLength(CodeChange item, RlpBehaviors rlpBehaviors)
+ => Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors));
public CodeChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
@@ -36,4 +37,7 @@ public void Encode(RlpStream stream, CodeChange item, RlpBehaviors rlpBehaviors
stream.Encode(item.BlockAccessIndex);
stream.Encode(item.NewCode);
}
+
+ public static int GetContentLength(CodeChange item, RlpBehaviors rlpBehaviors)
+ => Rlp.LengthOf(item.BlockAccessIndex) + Rlp.LengthOf(item.NewCode);
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
index 3d95b07ddbc..c5e06bc473d 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/NonceChangeDecoder.cs
@@ -8,9 +8,6 @@ namespace Nethermind.Serialization.Rlp.Eip7928;
public class NonceChangeDecoder : IRlpValueDecoder, IRlpStreamDecoder
{
- // ushort + ulong
- private const int Length = 2 + 8;
-
private static NonceChangeDecoder? _instance = null;
public static NonceChangeDecoder Instance => _instance ??= new();
@@ -21,7 +18,8 @@ public NonceChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehav
NewNonce = ctx.DecodeULong()
};
- public int GetLength(NonceChange item, RlpBehaviors rlpBehaviors) => Length;
+ public int GetLength(NonceChange item, RlpBehaviors rlpBehaviors)
+ => Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors));
public NonceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
@@ -35,8 +33,11 @@ public NonceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
public void Encode(RlpStream stream, NonceChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- stream.StartSequence(Length);
+ stream.StartSequence(GetContentLength(item, rlpBehaviors));
stream.Encode(item.BlockAccessIndex);
stream.Encode(item.NewNonce);
}
+
+ public static int GetContentLength(NonceChange item, RlpBehaviors rlpBehaviors)
+ => Rlp.LengthOf(item.BlockAccessIndex) + Rlp.LengthOf(item.NewNonce);
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
index c27ff75d315..8507ec41f74 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using Nethermind.Core;
using Nethermind.Core.BlockAccessLists;
namespace Nethermind.Serialization.Rlp.Eip7928;
@@ -21,16 +22,7 @@ public SlotChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehav
};
public int GetLength(SlotChanges item, RlpBehaviors rlpBehaviors)
- {
- int len = SlotSize;
-
- foreach (StorageChange slotChange in item.Changes)
- {
- len += StorageChangeDecoder.Instance.GetLength(slotChange, rlpBehaviors);
- }
-
- return len;
- }
+ => Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors).Total);
public SlotChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
@@ -44,14 +36,26 @@ public SlotChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
public void Encode(RlpStream stream, SlotChanges item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- int len = GetLength(item, rlpBehaviors);
- stream.StartSequence(len);
+ (int Total, int SlotChanges) len = GetContentLength(item, rlpBehaviors);
+ stream.StartSequence(len.Total);
stream.Encode(item.Slot);
- stream.StartSequence(len - SlotSize);
+ stream.StartSequence(len.SlotChanges);
foreach (StorageChange change in item.Changes)
{
StorageChangeDecoder.Instance.Encode(stream, change);
}
}
+
+ public static (int Total, int SlotChanges) GetContentLength(SlotChanges item, RlpBehaviors rlpBehaviors)
+ {
+ int slotChangeLen = 0;
+
+ foreach (StorageChange slotChange in item.Changes)
+ {
+ slotChangeLen += StorageChangeDecoder.Instance.GetLength(slotChange, rlpBehaviors);
+ }
+
+ return (slotChangeLen + Rlp.LengthOf(item.Slot), slotChangeLen);
+ }
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs
index 6d928b1fc64..6cdd2b76076 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/StorageChangeDecoder.cs
@@ -8,9 +8,6 @@ namespace Nethermind.Serialization.Rlp.Eip7928;
public class StorageChangeDecoder : IRlpValueDecoder, IRlpStreamDecoder
{
- // ushort + 32 byte vector
- private const int Length = 2 + 32;
-
private static StorageChangeDecoder? _instance = null;
public static StorageChangeDecoder Instance => _instance ??= new();
@@ -21,7 +18,8 @@ public StorageChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBeh
NewValue = ctx.DecodeByteArray()
};
- public int GetLength(StorageChange item, RlpBehaviors rlpBehaviors) => Length;
+ public int GetLength(StorageChange item, RlpBehaviors rlpBehaviors)
+ => Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors));
public StorageChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
@@ -35,8 +33,11 @@ public StorageChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
public void Encode(RlpStream stream, StorageChange item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- stream.StartSequence(Length);
+ stream.StartSequence(GetContentLength(item, rlpBehaviors));
stream.Encode(item.BlockAccessIndex);
stream.Encode(item.NewValue);
}
+
+ public static int GetContentLength(StorageChange item, RlpBehaviors rlpBehaviors)
+ => Rlp.LengthOf(item.BlockAccessIndex) + Rlp.LengthOf(item.NewValue);
}
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs
index 642ba81bae2..542d50f821e 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs
@@ -1767,6 +1767,19 @@ public static int LengthOf(long value)
public static int LengthOf(int value) => LengthOf((long)value);
+ public static int LengthOf(ushort value)
+ {
+ if (value < 128)
+ {
+ return 1;
+ }
+ else
+ {
+ // everything has a length prefix
+ return 1 + sizeof(ushort) - (BitOperations.LeadingZeroCount(value) / 2);
+ }
+ }
+
public static int LengthOf(Hash256? item)
{
return item is null ? 1 : 33;
From c49c33cc0f8a4e27f62ddf25e9cdd527c3726cd7 Mon Sep 17 00:00:00 2001
From: Marc Harvey-Hill <10379486+Marchhill@users.noreply.github.com>
Date: Fri, 29 Aug 2025 09:51:46 +0100
Subject: [PATCH 040/215] fix storagechange and slotchanges encodings
---
.../BlockAccessListTests.cs | 23 ++++++++--
.../Eip7928/AccountChangesDecoder.cs | 9 ++++
.../Eip7928/BalanceChangeDecoder.cs | 6 +--
.../Eip7928/SlotChangesDecoder.cs | 46 +++++++++++++------
.../Eip7928/StorageChangeDecoder.cs | 14 +++++-
5 files changed, 78 insertions(+), 20 deletions(-)
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
index e3ac6f75a0a..a5ff14ee5d2 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/BlockAccessListTests.cs
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using Nethermind.Blockchain.BeaconBlockRoot;
using Nethermind.Blockchain.Blocks;
@@ -97,9 +98,25 @@ public void Balance_and_nonce_changes()
[Test]
public void Encoding_decoding_test()
{
- BlockAccessList b = new();
- byte[] bytes = Rlp.Encode(b).Bytes;
- BlockAccessList b2 = Rlp.Decode(bytes);
+ StorageChange s = new()
+ {
+ BlockAccessIndex = 10,
+ NewValue = [.. Enumerable.Repeat(50, 32)]
+ };
+ byte[] b = Rlp.Encode(s, RlpBehaviors.None).Bytes;
+ StorageChange s2 = Rlp.Decode(b, RlpBehaviors.None);
+
+ SlotChanges sc = new()
+ {
+ Slot = [.. Enumerable.Repeat(100, 32)],
+ Changes = [s, s]
+ };
+ byte[] b2 = Rlp.Encode(sc, RlpBehaviors.None).Bytes;
+ SlotChanges sc2 = Rlp.Decode(b2, RlpBehaviors.None);
+ Assert.That(true);
+ // BlockAccessList b = new();
+ // byte[] bytes = Rlp.Encode(b).Bytes;
+ // BlockAccessList b2 = Rlp.Decode(bytes);
}
[Test]
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
index 403b1ba8f76..47da196ce41 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/AccountChangesDecoder.cs
@@ -15,6 +15,9 @@ public class AccountChangesDecoder : IRlpValueDecoder, IRlpStrea
public AccountChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
{
+ int length = ctx.ReadSequenceLength();
+ int check = length + ctx.Position;
+
byte[] address = ctx.DecodeAddress().Bytes;
SlotChanges[] slotChanges = ctx.DecodeArray(SlotChangesDecoder.Instance);
SortedDictionary slotChangesMap = new(slotChanges.ToDictionary(s => s.Slot, s => s));
@@ -22,6 +25,12 @@ public AccountChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBe
BalanceChange[] balanceChanges = ctx.DecodeArray(BalanceChangeDecoder.Instance);
NonceChange[] nonceChanges = ctx.DecodeArray(NonceChangeDecoder.Instance);
CodeChange[] codeChanges = ctx.DecodeArray(CodeChangeDecoder.Instance);
+
+ if (!rlpBehaviors.HasFlag(RlpBehaviors.AllowExtraBytes))
+ {
+ ctx.Check(check);
+ }
+
return new()
{
Address = address,
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
index d1a717819da..c1699f77988 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/BalanceChangeDecoder.cs
@@ -11,6 +11,9 @@ public class BalanceChangeDecoder : IRlpValueDecoder, IRlpStreamD
private static BalanceChangeDecoder? _instance = null;
public static BalanceChangeDecoder Instance => _instance ??= new();
+ public int GetLength(BalanceChange item, RlpBehaviors rlpBehaviors)
+ => Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors));
+
public BalanceChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
=> new()
{
@@ -18,9 +21,6 @@ public BalanceChange Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBeh
PostBalance = ctx.DecodeUInt256()
};
- public int GetLength(BalanceChange item, RlpBehaviors rlpBehaviors)
- => Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors));
-
public BalanceChange Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
{
Span span = rlpStream.PeekNextItem();
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
index 8507ec41f74..dca45d3642b 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7928/SlotChangesDecoder.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
-using Nethermind.Core;
using Nethermind.Core.BlockAccessLists;
namespace Nethermind.Serialization.Rlp.Eip7928;
@@ -12,15 +11,31 @@ public class SlotChangesDecoder : IRlpValueDecoder, IRlpStreamDecod
private static SlotChangesDecoder? _instance = null;
public static SlotChangesDecoder Instance => _instance ??= new();
- private const int SlotSize = 32;
public SlotChanges Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors)
- => new()
+ {
+ int length = ctx.ReadSequenceLength();
+ int check = length + ctx.Position;
+
+ byte[] slot = ctx.DecodeByteArray();
+
+ // int changesLength = ctx.ReadSequenceLength();
+ // int changesCheck = length + ctx.Position;
+
+ SlotChanges slotChanges = new()
{
- Slot = ctx.DecodeByteArray(),
+ Slot = slot,
Changes = [.. ctx.DecodeArray(StorageChangeDecoder.Instance)]
};
+ if (!rlpBehaviors.HasFlag(RlpBehaviors.AllowExtraBytes))
+ {
+ ctx.Check(check);
+ }
+
+ return slotChanges;
+ }
+
public int GetLength(SlotChanges item, RlpBehaviors rlpBehaviors)
=> Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors).Total);
@@ -36,18 +51,21 @@ public SlotChanges Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors)
public void Encode(RlpStream stream, SlotChanges item, RlpBehaviors rlpBehaviors = RlpBehaviors.None)
{
- (int Total, int SlotChanges) len = GetContentLength(item, rlpBehaviors);
- stream.StartSequence(len.Total);
+ (int Total, int Slot, int SlotChanges) = GetContentLength(item, rlpBehaviors);
+ stream.StartSequence(Total);
+
+ // stream.StartSequence(Slot);
stream.Encode(item.Slot);
- stream.StartSequence(len.SlotChanges);
- foreach (StorageChange change in item.Changes)
- {
- StorageChangeDecoder.Instance.Encode(stream, change);
- }
+ // stream.StartSequence(SlotChanges);
+ // foreach (StorageChange change in item.Changes)
+ // {
+ // StorageChangeDecoder.Instance.Encode(stream, change);
+ // }
+ stream.EncodeArray