diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/KeccaksIterator.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/KeccaksIterator.cs index e883f6d5616..f137e928f63 100644 --- a/src/Nethermind/Nethermind.Blockchain/Receipts/KeccaksIterator.cs +++ b/src/Nethermind/Nethermind.Blockchain/Receipts/KeccaksIterator.cs @@ -11,14 +11,14 @@ public ref struct KeccaksIterator { private readonly int _length; private readonly int _startPosition; - private Rlp.ValueDecoderContext _decoderContext; + private RlpValueStream _decoderContext; private readonly Span _buffer; public long Index { get; private set; } public KeccaksIterator(ReadOnlySpan data, Span buffer) { if (buffer.Length != 32) throw new ArgumentException("Buffer must be 32 bytes long"); - _decoderContext = new Rlp.ValueDecoderContext(data); + _decoderContext = new RlpValueStream(data); _length = _decoderContext.ReadSequenceLength(); _startPosition = _decoderContext.Position; _buffer = buffer; diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/LogEntriesIterator.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/LogEntriesIterator.cs index 0a20a36ea88..9b23e981fc4 100644 --- a/src/Nethermind/Nethermind.Blockchain/Receipts/LogEntriesIterator.cs +++ b/src/Nethermind/Nethermind.Blockchain/Receipts/LogEntriesIterator.cs @@ -11,13 +11,13 @@ public ref struct LogEntriesIterator { private readonly LogEntry[]? _logs; private readonly int _length; - private Rlp.ValueDecoderContext _decoderContext; + private RlpValueStream _decoderContext; private readonly IReceiptRefDecoder _receiptRefDecoder; public long Index { get; private set; } public LogEntriesIterator(ReadOnlySpan data, IReceiptRefDecoder receiptRefDecoder) { - _decoderContext = new Rlp.ValueDecoderContext(data); + _decoderContext = new RlpValueStream(data); _length = _decoderContext.ReadSequenceLength(); Index = -1; _logs = null; @@ -26,7 +26,7 @@ public LogEntriesIterator(ReadOnlySpan data, IReceiptRefDecoder receiptRef public LogEntriesIterator(LogEntry[] logs) { - _decoderContext = new Rlp.ValueDecoderContext(); + _decoderContext = new RlpValueStream(); _length = logs.Length; Index = -1; _logs = logs; diff --git a/src/Nethermind/Nethermind.Blockchain/Receipts/ReceiptsIterator.cs b/src/Nethermind/Nethermind.Blockchain/Receipts/ReceiptsIterator.cs index df94d852740..2f7afbbd323 100644 --- a/src/Nethermind/Nethermind.Blockchain/Receipts/ReceiptsIterator.cs +++ b/src/Nethermind/Nethermind.Blockchain/Receipts/ReceiptsIterator.cs @@ -14,7 +14,7 @@ public ref struct ReceiptsIterator { private readonly IDb _blocksDb; private readonly int _length; - private Rlp.ValueDecoderContext _decoderContext; + private RlpValueStream _decoderContext; private readonly int _startingPosition; private readonly TxReceipt[]? _receipts; @@ -51,7 +51,7 @@ public ReceiptsIterator(scoped in Span receiptsData, IDb blocksDb, Func public ReceiptsIterator(TxReceipt[] receipts) { - _decoderContext = new Rlp.ValueDecoderContext(); + _decoderContext = new RlpValueStream(); _length = receipts.Length; _blocksDb = null; _receipts = receipts; @@ -118,7 +118,7 @@ public readonly LogEntriesIterator IterateLogs(TxReceiptStructRef receipt) return receipt.Logs is null ? new LogEntriesIterator(receipt.LogsRlp, _receiptRefDecoder) : new LogEntriesIterator(receipt.Logs); } - public readonly Hash256[] DecodeTopics(Rlp.ValueDecoderContext valueDecoderContext) + public readonly Hash256[] DecodeTopics(RlpValueStream valueDecoderContext) { return _receiptRefDecoder.DecodeTopics(valueDecoderContext); } diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/AccessListDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/AccessListDecoderTests.cs index 1adf7d79769..054ae0c65ec 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/AccessListDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/AccessListDecoderTests.cs @@ -108,7 +108,7 @@ public void Roundtrip_value((string TestName, AccessList? AccessList) testCase) RlpStream rlpStream = new(10000); _decoder.Encode(rlpStream, testCase.AccessList); rlpStream.Position = 0; - Rlp.ValueDecoderContext ctx = rlpStream.Data.AsSpan().AsRlpValueContext(); + RlpValueStream ctx = rlpStream.Data.AsSpan().AsRlpValueContext(); AccessList decoded = _decoder.Decode(ref ctx)!; if (testCase.AccessList is null) { diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/AuthorizationTupleDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/AuthorizationTupleDecoderTests.cs index 5452208032c..89b5cc869f9 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/AuthorizationTupleDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/AuthorizationTupleDecoderTests.cs @@ -43,8 +43,8 @@ public void DecodeValueDecoderContext_CodeAddressIsNull_ThrowsRlpException() AuthorizationTupleDecoder sut = new(); Assert.That(() => { - Rlp.ValueDecoderContext decoderContext = new Rlp.ValueDecoderContext(stream.Data); - sut.Decode(ref decoderContext, RlpBehaviors.None); + RlpValueStream rlpStream = new RlpValueStream(stream.Data); + sut.Decode(ref rlpStream, RlpBehaviors.None); } , Throws.TypeOf()); } diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs index 47335ed1726..7f61a90095b 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs @@ -114,7 +114,7 @@ public void Can_do_roundtrip_regression([Values(true, false)] bool valueDecoder) BlockDecoder decoder = new(); byte[] bytes = Bytes.FromHexString(regression5644); - Rlp.ValueDecoderContext valueDecoderContext = new(bytes); + RlpValueStream valueDecoderContext = new(bytes); Block? decoded = valueDecoder ? decoder.Decode(ref valueDecoderContext) : decoder.Decode(new RlpStream(bytes)); Rlp encoded = decoder.Encode(decoded); Assert.That(encoded.Bytes.ToHexString(), Is.EqualTo(bytes.ToHexString())); @@ -127,7 +127,7 @@ public void Can_do_roundtrip_scenarios([Values(true, false)] bool valueDecoder) foreach (Block block in _scenarios) { Rlp encoded = decoder.Encode(block); - Rlp.ValueDecoderContext valueDecoderContext = new(encoded.Bytes); + RlpValueStream valueDecoderContext = new(encoded.Bytes); Block? decoded = valueDecoder ? decoder.Decode(ref valueDecoderContext) : decoder.Decode(new RlpStream(encoded.Bytes)); Rlp encoded2 = decoder.Encode(decoded); Assert.That(encoded2.Bytes.ToHexString(), Is.EqualTo(encoded.Bytes.ToHexString())); diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/CompactReceiptStorageDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/CompactReceiptStorageDecoderTests.cs index 6c63361f2b8..2ddced24b1d 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/CompactReceiptStorageDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/CompactReceiptStorageDecoderTests.cs @@ -82,7 +82,7 @@ TxReceipt BuildReceipt() TxReceipt? deserialized; if (valueDecoder) { - Rlp.ValueDecoderContext valueContext = rlp.Bytes.AsRlpValueContext(); + RlpValueStream valueContext = rlp.Bytes.AsRlpValueContext(); deserialized = decoder.Decode(ref valueContext, RlpBehaviors.Storage); } else @@ -134,7 +134,7 @@ public void Can_do_roundtrip_storage_ref_struct() CompactReceiptStorageDecoder decoder = new(); byte[] rlpStreamResult = decoder.Encode(txReceipt, RlpBehaviors.Storage).Bytes; - Rlp.ValueDecoderContext ctx = new(rlpStreamResult); + RlpValueStream ctx = new(rlpStreamResult); decoder.DecodeStructRef(ref ctx, RlpBehaviors.Storage, out var deserialized); Assert.That(deserialized.TxType, Is.EqualTo(txReceipt.TxType), "tx type"); diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs index 26859ba2874..08337713cf7 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs @@ -27,8 +27,8 @@ public void Can_decode(bool hasWithdrawalsRoot) HeaderDecoder decoder = new(); Rlp rlp = decoder.Encode(header); - Rlp.ValueDecoderContext decoderContext = new(rlp.Bytes); - BlockHeader? decoded = decoder.Decode(ref decoderContext); + RlpValueStream rlpStream = new(rlp.Bytes); + BlockHeader? decoded = decoder.Decode(ref rlpStream); decoded!.Hash = decoded.CalculateHash(); Assert.That(decoded.Hash, Is.EqualTo(header.Hash), "hash"); @@ -45,8 +45,8 @@ public void Can_decode_aura() HeaderDecoder decoder = new(); Rlp rlp = decoder.Encode(header); - Rlp.ValueDecoderContext decoderContext = new(rlp.Bytes); - BlockHeader? decoded = decoder.Decode(ref decoderContext); + RlpValueStream rlpStream = new(rlp.Bytes); + BlockHeader? decoded = decoder.Decode(ref rlpStream); decoded!.Hash = decoded.CalculateHash(); Assert.That(decoded.Hash, Is.EqualTo(header.Hash), "hash"); diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/LogEntryDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/LogEntryDecoderTests.cs index 9f3f323fe9e..c655b96a7ec 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/LogEntryDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/LogEntryDecoderTests.cs @@ -31,7 +31,7 @@ public void Can_do_roundtrip_ref_struct() { LogEntry logEntry = new(TestItem.AddressA, new byte[] { 1, 2, 3 }, new[] { TestItem.KeccakA, TestItem.KeccakB }); Rlp rlp = Rlp.Encode(logEntry); - Rlp.ValueDecoderContext valueDecoderContext = new(rlp.Bytes); + RlpValueStream valueDecoderContext = new(rlp.Bytes); LogEntryDecoder.DecodeStructRef(ref valueDecoderContext, RlpBehaviors.None, out LogEntryStructRef decoded); Assert.That(Bytes.AreEqual(logEntry.Data, decoded.Data), "data"); diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/ReceiptDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/ReceiptDecoderTests.cs index 3b962af183e..88258a350ba 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/ReceiptDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/ReceiptDecoderTests.cs @@ -63,7 +63,7 @@ TxReceipt BuildReceipt() TxReceipt? deserialized; if (valueDecoder) { - Rlp.ValueDecoderContext valueContext = rlp.Bytes.AsRlpValueContext(); + RlpValueStream valueContext = rlp.Bytes.AsRlpValueContext(); deserialized = decoder.Decode(ref valueContext, RlpBehaviors.Storage); } else diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/ShardBlobTxDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/ShardBlobTxDecoderTests.cs index 68b67af3490..f6fd8007e90 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/ShardBlobTxDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/ShardBlobTxDecoderTests.cs @@ -50,9 +50,9 @@ public void Roundtrip_ValueDecoderContext_ExecutionPayloadForm_for_shard_blobs(( _txDecoder.Encode(rlpStream, testCase.Tx); Span spanIncomingTxRlp = rlpStream.Data.AsSpan(); - Rlp.ValueDecoderContext decoderContext = new(spanIncomingTxRlp); + RlpValueStream rlpValueStream = new(spanIncomingTxRlp); rlpStream.Position = 0; - Transaction? decoded = _txDecoder.Decode(ref decoderContext); + Transaction? decoded = _txDecoder.Decode(ref rlpValueStream); decoded!.SenderAddress = new EthereumEcdsa(TestBlockchainIds.ChainId).RecoverAddress(decoded); decoded.Hash = decoded.CalculateHash(); @@ -64,10 +64,10 @@ public void NetworkWrapper_is_decoded_correctly(string rlp, Hash256 signedHash, { RlpStream incomingTxRlp = Bytes.FromHexString(rlp).AsRlpStream(); byte[] spanIncomingTxRlp = Bytes.FromHexString(rlp); - Rlp.ValueDecoderContext decoderContext = new(spanIncomingTxRlp.AsSpan()); + RlpValueStream rlpStream = new(spanIncomingTxRlp.AsSpan()); Transaction? decoded = _txDecoder.Decode(incomingTxRlp, rlpBehaviors); - Transaction? decodedByValueDecoderContext = _txDecoder.Decode(ref decoderContext, rlpBehaviors); + Transaction? decodedByValueDecoderContext = _txDecoder.Decode(ref rlpStream, rlpBehaviors); Assert.That(decoded!.Hash, Is.EqualTo(signedHash)); Assert.That(decodedByValueDecoderContext!.Hash, Is.EqualTo(signedHash)); diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/TxDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/TxDecoderTests.cs index b2cb2ecdfcd..f611ee38d80 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/TxDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/TxDecoderTests.cs @@ -107,9 +107,9 @@ public void Roundtrip_ValueDecoderContext((Transaction Tx, string Description) t _txDecoder.Encode(rlpStream, testCase.Tx); Span spanIncomingTxRlp = rlpStream.Data.AsSpan(); - Rlp.ValueDecoderContext decoderContext = new(spanIncomingTxRlp); + RlpValueStream rlpValueStream = new(spanIncomingTxRlp); rlpStream.Position = 0; - Transaction? decoded = _txDecoder.Decode(ref decoderContext); + Transaction? decoded = _txDecoder.Decode(ref rlpValueStream); decoded!.SenderAddress = new EthereumEcdsa(TestBlockchainIds.ChainId).RecoverAddress(decoded); decoded.Hash = decoded.CalculateHash(); @@ -122,9 +122,9 @@ public void Roundtrip_ValueDecoderContext_WithMemorySlice((Transaction Tx, strin RlpStream rlpStream = new(10000); _txDecoder.Encode(rlpStream, testCase.Tx); - Rlp.ValueDecoderContext decoderContext = new(rlpStream.Data.ToArray(), true); + RlpValueStream rlpValueStream = new(rlpStream.Data.ToArray(), true); rlpStream.Position = 0; - Transaction? decoded = _txDecoder.Decode(ref decoderContext); + Transaction? decoded = _txDecoder.Decode(ref rlpValueStream); decoded!.SenderAddress = new EthereumEcdsa(TestBlockchainIds.ChainId).RecoverAddress(decoded); decoded.Hash = decoded.CalculateHash(); @@ -139,9 +139,9 @@ public void ValueDecoderContext_DecodeWithMemorySlice_ShouldUseSameBuffer((Trans RlpStream rlpStream = new(10000); _txDecoder.Encode(rlpStream, testCase.Tx); - Rlp.ValueDecoderContext decoderContext = new(rlpStream.Data.ToArray(), true); + RlpValueStream rlpValueStream = new(rlpStream.Data.ToArray(), true); rlpStream.Position = 0; - Transaction? decoded = _txDecoder.Decode(ref decoderContext); + Transaction? decoded = _txDecoder.Decode(ref rlpValueStream); byte[] data1 = decoded!.Data!.Value.ToArray(); data1.AsSpan().Fill(1); @@ -219,8 +219,8 @@ private void ValueDecoderContext_return_the_same_transaction_as_rlp_stream( TestContext.Out.WriteLine($"Testing {testCase.Hash}"); RlpStream incomingTxRlp = Bytes.FromHexString(testCase.IncomingRlpHex).AsRlpStream(); Span spanIncomingTxRlp = Bytes.FromHexString(testCase.IncomingRlpHex).AsSpan(); - Rlp.ValueDecoderContext decoderContext = new(spanIncomingTxRlp); - Transaction decodedByValueDecoderContext = _txDecoder.Decode(ref decoderContext, wrapping ? RlpBehaviors.SkipTypedWrapping : RlpBehaviors.None)!; + RlpValueStream rlpStream = new(spanIncomingTxRlp); + Transaction decodedByValueDecoderContext = _txDecoder.Decode(ref rlpStream, wrapping ? RlpBehaviors.SkipTypedWrapping : RlpBehaviors.None)!; Transaction decoded = _txDecoder.Decode(incomingTxRlp, wrapping ? RlpBehaviors.SkipTypedWrapping : RlpBehaviors.None)!; Rlp encoded = _txDecoder.Encode(decoded); Rlp encodedWithDecodedByValueDecoderContext = _txDecoder.Encode(decodedByValueDecoderContext); diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/WithdrawalDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/WithdrawalDecoderTests.cs index 25c2bf458c8..c0741225e4b 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/WithdrawalDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/WithdrawalDecoderTests.cs @@ -56,8 +56,8 @@ public void Should_decode_with_ValueDecoderContext() codec.Encode(stream, withdrawal); - Rlp.ValueDecoderContext decoderContext = new(stream.Data.AsSpan()); - Withdrawal? decoded = codec.Decode(ref decoderContext); + RlpValueStream rlpStream = new(stream.Data.AsSpan()); + Withdrawal? decoded = codec.Decode(ref rlpStream); decoded.Should().BeEquivalentTo(withdrawal); } diff --git a/src/Nethermind/Nethermind.Core.Test/RlpTests.cs b/src/Nethermind/Nethermind.Core.Test/RlpTests.cs index bf362b02544..273f74cc300 100644 --- a/src/Nethermind/Nethermind.Core.Test/RlpTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/RlpTests.cs @@ -260,7 +260,7 @@ public void RlpContextWithSliceMemory_shouldNotCopyUnderlyingData(bool sliceValu stream.Encode(randomBytes); Memory memory = stream.Data.ToArray(); - Rlp.ValueDecoderContext context = new Rlp.ValueDecoderContext(memory, sliceValue); + RlpValueStream context = new RlpValueStream(memory, sliceValue); for (int i = 0; i < 3; i++) { diff --git a/src/Nethermind/Nethermind.Facade/Find/LogFinder.cs b/src/Nethermind/Nethermind.Facade/Find/LogFinder.cs index c687d3413f5..7d458316d64 100644 --- a/src/Nethermind/Nethermind.Facade/Find/LogFinder.cs +++ b/src/Nethermind/Nethermind.Facade/Find/LogFinder.cs @@ -247,7 +247,7 @@ private static IEnumerable FilterLogsInBlockLowMemoryAllocation(LogFi logList ??= new List(); Hash256[] topics = log.Topics; - topics ??= iterator.DecodeTopics(new Rlp.ValueDecoderContext(log.TopicsRlp)); + topics ??= iterator.DecodeTopics(new RlpValueStream(log.TopicsRlp)); logList.Add(new FilterLog( logIndexInBlock, diff --git a/src/Nethermind/Nethermind.Network/P2P/Messages/DisconnectMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Messages/DisconnectMessageSerializer.cs index a8a53930f99..c983b24e59a 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Messages/DisconnectMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Messages/DisconnectMessageSerializer.cs @@ -42,10 +42,10 @@ public DisconnectMessage Deserialize(IByteBuffer msgBytes) } Span msg = msgBytes.ReadAllBytesAsSpan(); - Rlp.ValueDecoderContext rlpStream = msg.AsRlpValueContext(); + RlpValueStream rlpStream = msg.AsRlpValueContext(); if (!rlpStream.IsSequenceNext()) { - rlpStream = new Rlp.ValueDecoderContext(rlpStream.DecodeByteArraySpan()); + rlpStream = new RlpValueStream(rlpStream.DecodeByteArraySpan()); } rlpStream.ReadSequenceLength(); diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessageSerializer.cs index 714a3999dcc..ea1714ef71e 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessageSerializer.cs @@ -45,7 +45,7 @@ public BlockBodiesMessage Deserialize(IByteBuffer byteBuffer) { NettyBufferMemoryOwner memoryOwner = new(byteBuffer); - Rlp.ValueDecoderContext ctx = new(memoryOwner.Memory, true); + RlpValueStream ctx = new(memoryOwner.Memory, true); int startingPosition = ctx.Position; BlockBody[]? bodies = ctx.DecodeArray(_blockBodyDecoder, false); byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startingPosition)); diff --git a/src/Nethermind/Nethermind.Network/Rlpx/FrameHeaderReader.cs b/src/Nethermind/Nethermind.Network/Rlpx/FrameHeaderReader.cs index f4087825ef8..9d4dff85707 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/FrameHeaderReader.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/FrameHeaderReader.cs @@ -20,7 +20,7 @@ public FrameInfo ReadFrameHeader(IByteBuffer input) frameSize = (frameSize << 8) + (HeaderBytes[1] & 0xFF); frameSize = (frameSize << 8) + (HeaderBytes[2] & 0xFF); - Rlp.ValueDecoderContext headerBodyItems = HeaderBytes.AsSpan(3, 13).AsRlpValueContext(); + RlpValueStream headerBodyItems = HeaderBytes.AsSpan(3, 13).AsRlpValueContext(); int headerDataEnd = headerBodyItems.ReadSequenceLength() + headerBodyItems.Position; int numberOfItems = headerBodyItems.PeekNumberOfItemsRemaining(headerDataEnd); headerBodyItems.DecodeInt(); // not needed - adaptive IDs - DO NOT COMMENT OUT!!! - decode takes int of the RLP sequence and moves the position diff --git a/src/Nethermind/Nethermind.Optimism.Test/ReceiptDecoderTests.cs b/src/Nethermind/Nethermind.Optimism.Test/ReceiptDecoderTests.cs index 37e1a5e4df7..a1546c15c0d 100644 --- a/src/Nethermind/Nethermind.Optimism.Test/ReceiptDecoderTests.cs +++ b/src/Nethermind/Nethermind.Optimism.Test/ReceiptDecoderTests.cs @@ -47,7 +47,7 @@ static OptimismTxReceipt TestStorageEncodingRoundTrip(OptimismTxReceipt decodedR Assert.That(decodedStorageReceipt.DepositReceiptVersion, includesVersion ? Is.Not.Null : Is.Null); }); - Rlp.ValueDecoderContext valueDecoderCtx = new(encodedRlp.Data); + RlpValueStream valueDecoderCtx = new(encodedRlp.Data); decodedStorageReceipt = decoder.Decode(ref valueDecoderCtx, RlpBehaviors.SkipTypedWrapping); Assert.Multiple(() => diff --git a/src/Nethermind/Nethermind.Optimism/OptimismReceiptStorageDecoder.cs b/src/Nethermind/Nethermind.Optimism/OptimismReceiptStorageDecoder.cs index 034ec815058..7aadc9ed73a 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismReceiptStorageDecoder.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismReceiptStorageDecoder.cs @@ -15,7 +15,11 @@ public class OptimismCompactReceiptStorageDecoder : IRlpStreamDecoder, IRlpValueDecoder, IRlpObjectDecoder, IReceiptRefDecoder, IRlpStreamDecoder, IRlpValueDecoder, IRlpObjectDecoder { - public OptimismTxReceipt Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public OptimismTxReceipt Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => + Decode(ref rlpStream, rlpBehaviors); + + public OptimismTxReceipt Decode(ref T rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + where T : IRlpStream, allows ref struct { if (rlpStream.IsNextItemNull()) { @@ -41,11 +45,12 @@ public OptimismTxReceipt Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = int sequenceLength = rlpStream.ReadSequenceLength(); int logEntriesCheck = sequenceLength + rlpStream.Position; - using ArrayPoolList logEntries = new(sequenceLength * 2 / LengthOfAddressRlp); + // Don't know the size exactly, I'll just assume its just an address and add some margin + using ArrayPoolList logEntries = new(sequenceLength * 2 / LengthOfAddressRlp); while (rlpStream.Position < logEntriesCheck) { - logEntries.Add(CompactLogEntryDecoder.Decode(rlpStream, RlpBehaviors.AllowExtraBytes)!); + logEntries.Add(CompactLogEntryDecoder.Decode(ref rlpStream, RlpBehaviors.AllowExtraBytes)!); } txReceipt.Logs = [.. logEntries]; @@ -55,12 +60,12 @@ public OptimismTxReceipt Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = int remainingItems = rlpStream.PeekNumberOfItemsRemaining(lastCheck); if (remainingItems > 0) { - txReceipt.DepositNonce = rlpStream.DecodeUlong(); + txReceipt.DepositNonce = rlpStream.DecodeULong(); } if (remainingItems > 1) { - txReceipt.DepositReceiptVersion = rlpStream.DecodeUlong(); + txReceipt.DepositReceiptVersion = rlpStream.DecodeULong(); } } @@ -75,83 +80,23 @@ public OptimismTxReceipt Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = return txReceipt; } - public OptimismTxReceipt Decode(ref ValueDecoderContext decoderContext, - RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - if (decoderContext.IsNextItemNull()) - { - decoderContext.ReadByte(); - return null!; - } - - OptimismTxReceipt txReceipt = new(); - int lastCheck = decoderContext.ReadSequenceLength() + decoderContext.Position; - - byte[] firstItem = decoderContext.DecodeByteArray(); - if (firstItem.Length == 1) - { - txReceipt.StatusCode = firstItem[0]; - } - else - { - txReceipt.PostTransactionState = firstItem.Length == 0 ? null : new Hash256(firstItem); - } - - txReceipt.Sender = decoderContext.DecodeAddress(); - txReceipt.GasUsedTotal = (long)decoderContext.DecodeUBigInt(); - - int sequenceLength = decoderContext.ReadSequenceLength(); - int logEntriesCheck = sequenceLength + decoderContext.Position; - - // Don't know the size exactly, I'll just assume its just an address and add some margin - using ArrayPoolList logEntries = new(sequenceLength * 2 / LengthOfAddressRlp); - while (decoderContext.Position < logEntriesCheck) - { - logEntries.Add(CompactLogEntryDecoder.Decode(ref decoderContext, RlpBehaviors.AllowExtraBytes)!); - } - - txReceipt.Logs = [.. logEntries]; + public OptimismTxReceipt Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => + Decode(ref rlpStream, rlpBehaviors); - if (lastCheck > decoderContext.Position) - { - int remainingItems = decoderContext.PeekNumberOfItemsRemaining(lastCheck); - if (remainingItems > 0) - { - txReceipt.DepositNonce = decoderContext.DecodeULong(); - } - - if (remainingItems > 1) - { - txReceipt.DepositReceiptVersion = decoderContext.DecodeULong(); - } - } - - bool allowExtraBytes = (rlpBehaviors & RlpBehaviors.AllowExtraBytes) != 0; - if (!allowExtraBytes) - { - decoderContext.Check(lastCheck); - } - - txReceipt.Bloom = new Bloom(txReceipt.Logs); - - return txReceipt; - } - - public void DecodeStructRef(scoped ref ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors, - out TxReceiptStructRef item) + public void DecodeStructRef(scoped ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors, out TxReceiptStructRef item) { // Note: This method runs at 2.5 million times/sec on my machine item = new TxReceiptStructRef(); - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); return; } - int lastCheck = decoderContext.ReadSequenceLength() + decoderContext.Position; + int lastCheck = rlpStream.ReadSequenceLength() + rlpStream.Position; - ReadOnlySpan firstItem = decoderContext.DecodeByteArraySpan(); + ReadOnlySpan firstItem = rlpStream.DecodeByteArraySpan(); if (firstItem.Length == 1) { item.StatusCode = firstItem[0]; @@ -162,42 +107,38 @@ public void DecodeStructRef(scoped ref ValueDecoderContext decoderContext, RlpBe firstItem.Length == 0 ? new Hash256StructRef() : new Hash256StructRef(firstItem); } - decoderContext.DecodeAddressStructRef(out item.Sender); - item.GasUsedTotal = (long)decoderContext.DecodeUBigInt(); + rlpStream.DecodeAddressStructRef(out item.Sender); + item.GasUsedTotal = (long)rlpStream.DecodeUBigInt(); (int PrefixLength, int ContentLength) = - decoderContext.PeekPrefixAndContentLength(); + rlpStream.PeekPrefixAndContentLength(); int logsBytes = ContentLength + PrefixLength; - item.LogsRlp = decoderContext.Data.Slice(decoderContext.Position, logsBytes); + item.LogsRlp = rlpStream.Data.Slice(rlpStream.Position, logsBytes); - if (lastCheck > decoderContext.Position) + if (lastCheck > rlpStream.Position) { - int remainingItems = decoderContext.PeekNumberOfItemsRemaining(lastCheck); + int remainingItems = rlpStream.PeekNumberOfItemsRemaining(lastCheck); if (remainingItems > 1) { - decoderContext.SkipItem(); + rlpStream.SkipItem(); } if (remainingItems > 2) { - decoderContext.SkipItem(); + rlpStream.SkipItem(); } } - decoderContext.SkipItem(); + rlpStream.SkipItem(); } - public void DecodeLogEntryStructRef(scoped ref ValueDecoderContext decoderContext, RlpBehaviors none, - out LogEntryStructRef current) + public void DecodeLogEntryStructRef(scoped ref RlpValueStream rlpStream, RlpBehaviors none, out LogEntryStructRef current) { - CompactLogEntryDecoder.DecodeLogEntryStructRef(ref decoderContext, none, out current); + CompactLogEntryDecoder.DecodeLogEntryStructRef(ref rlpStream, none, out current); } - public Hash256[] DecodeTopics(ValueDecoderContext valueDecoderContext) - { - return CompactLogEntryDecoder.DecodeTopics(valueDecoderContext); - } + public Hash256[] DecodeTopics(RlpValueStream valueDecoderContext) => CompactLogEntryDecoder.DecodeTopics(valueDecoderContext); // Refstruct decode does not generate bloom public bool CanDecodeBloom => false; @@ -305,8 +246,8 @@ private static int GetLogsLength(OptimismTxReceipt item) public int GetLength(OptimismTxReceipt item, RlpBehaviors rlpBehaviors) { - (int Total, _) = GetContentLength(item, rlpBehaviors); - return LengthOfSequence(Total); + (int total, _) = GetContentLength(item, rlpBehaviors); + return LengthOfSequence(total); } TxReceipt IRlpStreamDecoder.Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors) @@ -324,9 +265,9 @@ public int GetLength(TxReceipt item, RlpBehaviors rlpBehaviors) return GetLength((OptimismTxReceipt)item, rlpBehaviors); } - TxReceipt IRlpValueDecoder.Decode(ref ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors) + TxReceipt IRlpValueDecoder.Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors) { - return Decode(ref decoderContext, rlpBehaviors); + return Decode(ref rlpStream, rlpBehaviors); } public Rlp Encode(TxReceipt? item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) diff --git a/src/Nethermind/Nethermind.Optimism/OptimismTxDecoder.cs b/src/Nethermind/Nethermind.Optimism/OptimismTxDecoder.cs index 9bb2e77fcdd..a19c391439f 100644 --- a/src/Nethermind/Nethermind.Optimism/OptimismTxDecoder.cs +++ b/src/Nethermind/Nethermind.Optimism/OptimismTxDecoder.cs @@ -30,17 +30,17 @@ protected override void DecodePayload(Transaction transaction, RlpStream rlpStre transaction.Data = rlpStream.DecodeByteArray(); } - protected override void DecodePayload(Transaction transaction, ref Rlp.ValueDecoderContext decoderContext, + protected override void DecodePayload(Transaction transaction, ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - transaction.SourceHash = decoderContext.DecodeKeccak(); - transaction.SenderAddress = decoderContext.DecodeAddress(); - transaction.To = decoderContext.DecodeAddress(); - transaction.Mint = decoderContext.DecodeUInt256(); - transaction.Value = decoderContext.DecodeUInt256(); - transaction.GasLimit = decoderContext.DecodeLong(); - transaction.IsOPSystemTransaction = decoderContext.DecodeBool(); - transaction.Data = decoderContext.DecodeByteArray(); + transaction.SourceHash = rlpStream.DecodeKeccak(); + transaction.SenderAddress = rlpStream.DecodeAddress(); + transaction.To = rlpStream.DecodeAddress(); + transaction.Mint = rlpStream.DecodeUInt256(); + transaction.Value = rlpStream.DecodeUInt256(); + transaction.GasLimit = rlpStream.DecodeLong(); + transaction.IsOPSystemTransaction = rlpStream.DecodeBool(); + transaction.Data = rlpStream.DecodeByteArray(); } protected override Signature? DecodeSignature(ulong v, ReadOnlySpan rBytes, ReadOnlySpan sBytes, Signature? fallbackSignature = null, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs index 1aafefca57e..ed0801eaaad 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/AccountDecoder.cs @@ -33,7 +33,7 @@ public AccountDecoder(bool slimFormat = false) return (codeHash, storageRoot); } - public Hash256 DecodeStorageRootOnly(ref Rlp.ValueDecoderContext context) + public Hash256 DecodeStorageRootOnly(ref RlpValueStream context) { context.SkipLength(); context.SkipItem(); @@ -189,7 +189,7 @@ private Hash256 DecodeStorageRoot(RlpStream rlpStream) return storageRoot; } - private Hash256 DecodeStorageRoot(Rlp.ValueDecoderContext context) + private Hash256 DecodeStorageRoot(RlpValueStream context) { Hash256 storageRoot; if (_slimFormat && context.IsNextItemEmptyArray()) @@ -222,18 +222,18 @@ private Hash256 DecodeCodeHash(RlpStream rlpStream) return codeHash; } - public Account? Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public Account? Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - int length = decoderContext.ReadSequenceLength(); + int length = rlpStream.ReadSequenceLength(); if (length == 1) { return null; } - UInt256 nonce = decoderContext.DecodeUInt256(); - UInt256 balance = decoderContext.DecodeUInt256(); - Hash256 storageRoot = DecodeStorageRoot(ref decoderContext); - Hash256 codeHash = DecodeCodeHash(ref decoderContext); + UInt256 nonce = rlpStream.DecodeUInt256(); + UInt256 balance = rlpStream.DecodeUInt256(); + Hash256 storageRoot = DecodeStorageRoot(ref rlpStream); + Hash256 codeHash = DecodeCodeHash(ref rlpStream); if (ReferenceEquals(storageRoot, Keccak.EmptyTreeHash) && ReferenceEquals(codeHash, Keccak.OfAnEmptyString)) { return new(nonce, balance); @@ -242,7 +242,7 @@ private Hash256 DecodeCodeHash(RlpStream rlpStream) return new(nonce, balance, storageRoot, codeHash); } - private Hash256 DecodeStorageRoot(ref Rlp.ValueDecoderContext rlpStream) + private Hash256 DecodeStorageRoot(ref RlpValueStream rlpStream) { Hash256 storageRoot; if (_slimFormat && rlpStream.IsNextItemEmptyArray()) @@ -258,7 +258,7 @@ private Hash256 DecodeStorageRoot(ref Rlp.ValueDecoderContext rlpStream) return storageRoot; } - private Hash256 DecodeCodeHash(ref Rlp.ValueDecoderContext rlpStream) + private Hash256 DecodeCodeHash(ref RlpValueStream rlpStream) { Hash256 codeHash; if (_slimFormat && rlpStream.IsNextItemEmptyArray()) @@ -274,7 +274,7 @@ private Hash256 DecodeCodeHash(ref Rlp.ValueDecoderContext rlpStream) return codeHash; } - private ValueHash256 DecodeStorageRootStruct(ref Rlp.ValueDecoderContext rlpStream) + private ValueHash256 DecodeStorageRootStruct(ref RlpValueStream rlpStream) { ValueHash256 storageRoot; if (_slimFormat && rlpStream.IsNextItemEmptyArray()) @@ -290,7 +290,7 @@ private ValueHash256 DecodeStorageRootStruct(ref Rlp.ValueDecoderContext rlpStre return storageRoot; } - private ValueHash256 DecodeCodeHashStruct(ref Rlp.ValueDecoderContext rlpStream) + private ValueHash256 DecodeCodeHashStruct(ref RlpValueStream rlpStream) { ValueHash256 codeHash; if (_slimFormat && rlpStream.IsNextItemEmptyArray()) @@ -306,19 +306,19 @@ private ValueHash256 DecodeCodeHashStruct(ref Rlp.ValueDecoderContext rlpStream) return codeHash; } - public bool TryDecodeStruct(ref Rlp.ValueDecoderContext decoderContext, out AccountStruct account) + public bool TryDecodeStruct(ref RlpValueStream rlpStream, out AccountStruct account) { - int length = decoderContext.ReadSequenceLength(); + int length = rlpStream.ReadSequenceLength(); if (length == 1) { account = AccountStruct.TotallyEmpty; return false; } - UInt256 nonce = decoderContext.DecodeUInt256(); - UInt256 balance = decoderContext.DecodeUInt256(); - ValueHash256 storageRoot = DecodeStorageRootStruct(ref decoderContext); - ValueHash256 codeHash = DecodeCodeHashStruct(ref decoderContext); + UInt256 nonce = rlpStream.DecodeUInt256(); + UInt256 balance = rlpStream.DecodeUInt256(); + ValueHash256 storageRoot = DecodeStorageRootStruct(ref rlpStream); + ValueHash256 codeHash = DecodeCodeHashStruct(ref rlpStream); account = new AccountStruct(nonce, balance, storageRoot, codeHash); return true; } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/BlockBodyDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/BlockBodyDecoder.cs index df648cf3945..48136f574ae 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/BlockBodyDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/BlockBodyDecoder.cs @@ -46,7 +46,7 @@ public int GetBodyLength(BlockBody b) private int GetWithdrawalsLength(Withdrawal[] withdrawals) => withdrawals.Sum(t => _withdrawalDecoderDecoder.GetLength(t, RlpBehaviors.None)); - public BlockBody? Decode(ref Rlp.ValueDecoderContext ctx, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public BlockBody? Decode(ref RlpValueStream ctx, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { int sequenceLength = ctx.ReadSequenceLength(); int startingPosition = ctx.Position; @@ -58,7 +58,7 @@ public int GetBodyLength(BlockBody b) return DecodeUnwrapped(ref ctx, startingPosition + sequenceLength); } - public BlockBody? DecodeUnwrapped(ref Rlp.ValueDecoderContext ctx, int lastPosition) + public BlockBody? DecodeUnwrapped(ref RlpValueStream ctx, int lastPosition) { // quite significant allocations (>0.5%) here based on a sample 3M blocks sync diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs index 3f4f542307e..eb09fb484bf 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs @@ -26,7 +26,7 @@ public class BlockDecoder : IRlpValueDecoder, IRlpStreamDecoder } Span contentSpan = rlpStream.PeekNextItem(); - Rlp.ValueDecoderContext ctx = new Rlp.ValueDecoderContext(contentSpan); + RlpValueStream ctx = new RlpValueStream(contentSpan); Block? decoded = Decode(ref ctx, rlpBehaviors); rlpStream.Position += contentSpan.Length; return decoded; @@ -56,19 +56,19 @@ public int GetLength(Block? item, RlpBehaviors rlpBehaviors) return Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors).Total); } - public Block? Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public Block? Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); return null; } - int sequenceLength = decoderContext.ReadSequenceLength(); - int blockCheck = decoderContext.Position + sequenceLength; + int sequenceLength = rlpStream.ReadSequenceLength(); + int blockCheck = rlpStream.Position + sequenceLength; - BlockHeader header = Rlp.Decode(ref decoderContext); - BlockBody body = _blockBodyDecoder.DecodeUnwrapped(ref decoderContext, blockCheck); + BlockHeader header = Rlp.Decode(ref rlpStream); + BlockBody body = _blockBodyDecoder.DecodeUnwrapped(ref rlpStream, blockCheck); return new(header, body); } @@ -120,33 +120,33 @@ public void Encode(RlpStream stream, Block? item, RlpBehaviors rlpBehaviors = Rl public static ReceiptRecoveryBlock? DecodeToReceiptRecoveryBlock(MemoryManager? memoryManager, Memory memory, RlpBehaviors rlpBehaviors) { - Rlp.ValueDecoderContext decoderContext = new Rlp.ValueDecoderContext(memory, true); + RlpValueStream rlpStream = new RlpValueStream(memory, true); - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); return null; } - int sequenceLength = decoderContext.ReadSequenceLength(); - int blockCheck = decoderContext.Position + sequenceLength; + int sequenceLength = rlpStream.ReadSequenceLength(); + int blockCheck = rlpStream.Position + sequenceLength; - BlockHeader header = Rlp.Decode(ref decoderContext); + BlockHeader header = Rlp.Decode(ref rlpStream); - int contentLength = decoderContext.ReadSequenceLength(); - int transactionCount = decoderContext.PeekNumberOfItemsRemaining(decoderContext.Position + contentLength); + int contentLength = rlpStream.ReadSequenceLength(); + int transactionCount = rlpStream.PeekNumberOfItemsRemaining(rlpStream.Position + contentLength); - Memory transactionMemory = decoderContext.ReadMemory(contentLength); + Memory transactionMemory = rlpStream.ReadMemory(contentLength); - decoderContext.SkipItem(); // Skip uncles + rlpStream.SkipItem(); // Skip uncles - if (decoderContext.Position != blockCheck) + if (rlpStream.Position != blockCheck) { - decoderContext.SkipItem(); // Skip withdrawals + rlpStream.SkipItem(); // Skip withdrawals } if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes) { - decoderContext.Check(blockCheck); + rlpStream.Check(blockCheck); } return new ReceiptRecoveryBlock(memoryManager, header, transactionMemory, transactionCount); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/BlockInfoDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/BlockInfoDecoder.cs index 69ee52db06c..e76a5225bc2 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/BlockInfoDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/BlockInfoDecoder.cs @@ -94,30 +94,30 @@ public int GetLength(BlockInfo? item, RlpBehaviors rlpBehaviors = RlpBehaviors.N return item is null ? Rlp.OfEmptySequence.Length : Rlp.LengthOfSequence(GetContentLength(item, rlpBehaviors)); } - public BlockInfo? Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public BlockInfo? Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); return null; } - int lastCheck = decoderContext.ReadSequenceLength() + decoderContext.Position; + int lastCheck = rlpStream.ReadSequenceLength() + rlpStream.Position; - Hash256? blockHash = decoderContext.DecodeKeccak(); - bool wasProcessed = decoderContext.DecodeBool(); - UInt256 totalDifficulty = decoderContext.DecodeUInt256(); + Hash256? blockHash = rlpStream.DecodeKeccak(); + bool wasProcessed = rlpStream.DecodeBool(); + UInt256 totalDifficulty = rlpStream.DecodeUInt256(); BlockMetadata metadata = BlockMetadata.None; // if we hadn't reached the end of the stream, assume we have metadata to decode - if (decoderContext.Position != lastCheck) + if (rlpStream.Position != lastCheck) { - metadata = (BlockMetadata)decoderContext.DecodeInt(); + metadata = (BlockMetadata)rlpStream.DecodeInt(); } if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes) { - decoderContext.Check(lastCheck); + rlpStream.Check(lastCheck); } if (blockHash is null) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/ByteArrayExtensions.cs b/src/Nethermind/Nethermind.Serialization.Rlp/ByteArrayExtensions.cs index 2397b3a589c..30d0556339f 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/ByteArrayExtensions.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/ByteArrayExtensions.cs @@ -28,19 +28,19 @@ public static RlpFactory AsRlpFactory(in this CappedArray bytes) return new(in bytes.IsNotNull ? ref bytes : ref CappedArray.Empty); } - public static Rlp.ValueDecoderContext AsRlpValueContext(this byte[]? bytes) + public static RlpValueStream AsRlpValueContext(this byte[]? bytes) { return new(bytes ?? []); } - public static Rlp.ValueDecoderContext AsRlpValueContext(this Span span) + public static RlpValueStream AsRlpValueContext(this Span span) { return ((ReadOnlySpan)span).AsRlpValueContext(); } - public static Rlp.ValueDecoderContext AsRlpValueContext(this ReadOnlySpan span) + public static RlpValueStream AsRlpValueContext(this ReadOnlySpan span) { - return span.IsEmpty ? new Rlp.ValueDecoderContext([]) : new Rlp.ValueDecoderContext(span); + return span.IsEmpty ? new RlpValueStream([]) : new RlpValueStream(span); } } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/ChainLevelDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/ChainLevelDecoder.cs index aaf60db469f..9a6050d4604 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/ChainLevelDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/ChainLevelDecoder.cs @@ -72,23 +72,23 @@ public void Encode(RlpStream stream, ChainLevelInfo? item, RlpBehaviors rlpBehav } } - public ChainLevelInfo? Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public ChainLevelInfo? Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { return null; } - int lastCheck = decoderContext.ReadSequenceLength() + decoderContext.Position; - bool hasMainChainBlock = decoderContext.DecodeBool(); + int lastCheck = rlpStream.ReadSequenceLength() + rlpStream.Position; + bool hasMainChainBlock = rlpStream.DecodeBool(); List blockInfos = new(); - decoderContext.ReadSequenceLength(); - while (decoderContext.Position < lastCheck) + rlpStream.ReadSequenceLength(); + while (rlpStream.Position < lastCheck) { // block info can be null for corrupted states (also cases where block hash is null from the old DBs) - BlockInfo? blockInfo = Rlp.Decode(ref decoderContext, RlpBehaviors.AllowExtraBytes); + BlockInfo? blockInfo = Rlp.Decode(ref rlpStream, RlpBehaviors.AllowExtraBytes); if (blockInfo is not null) { blockInfos.Add(blockInfo); @@ -97,7 +97,7 @@ public void Encode(RlpStream stream, ChainLevelInfo? item, RlpBehaviors rlpBehav if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes) { - decoderContext.Check(lastCheck); + rlpStream.Check(lastCheck); } ChainLevelInfo info = new(hasMainChainBlock, blockInfos.ToArray()); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/CompactLogEntryDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/CompactLogEntryDecoder.cs index 2ce1c1348c7..a02855bbde8 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/CompactLogEntryDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/CompactLogEntryDecoder.cs @@ -15,7 +15,8 @@ public class CompactLogEntryDecoder : IRlpDecoder { public static CompactLogEntryDecoder Instance { get; } = new(); - public static LogEntry? Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public static LogEntry? Decode(ref T rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + where T : IRlpStream, allows ref struct { if (rlpStream.IsNextItemNull()) { @@ -38,60 +39,34 @@ public class CompactLogEntryDecoder : IRlpDecoder byte[] data = new byte[zeroPrefix + rlpData.Length]; rlpData.CopyTo(data.AsSpan(zeroPrefix)); - return new LogEntry(address, data, topics.ToArray()); + return new LogEntry(address!, data, topics.ToArray()); } - public static LogEntry? Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public static void DecodeLogEntryStructRef(scoped ref RlpValueStream rlpStream, RlpBehaviors behaviors, out LogEntryStructRef item) { - if (decoderContext.IsNextItemNull()) - { - decoderContext.ReadByte(); - return null; - } - - decoderContext.ReadSequenceLength(); - Address? address = decoderContext.DecodeAddress(); - long sequenceLength = decoderContext.ReadSequenceLength(); - long untilPosition = decoderContext.Position + sequenceLength; - using ArrayPoolList topics = new((int)(sequenceLength * 2 / Rlp.LengthOfKeccakRlp)); - while (decoderContext.Position < untilPosition) - { - topics.Add(decoderContext.DecodeZeroPrefixKeccak()); - } - - int zeroPrefix = decoderContext.DecodeInt(); - ReadOnlySpan rlpData = decoderContext.DecodeByteArraySpan(); - byte[] data = new byte[zeroPrefix + rlpData.Length]; - rlpData.CopyTo(data.AsSpan(zeroPrefix)); - - return new LogEntry(address, data, topics.ToArray()); - } - - public static void DecodeLogEntryStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors behaviors, out LogEntryStructRef item) - { - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); item = new LogEntryStructRef(); return; } - decoderContext.ReadSequenceLength(); - decoderContext.DecodeAddressStructRef(out var address); - var (PrefixLength, ContentLength) = decoderContext.PeekPrefixAndContentLength(); + rlpStream.ReadSequenceLength(); + rlpStream.DecodeAddressStructRef(out var address); + var (PrefixLength, ContentLength) = rlpStream.PeekPrefixAndContentLength(); var sequenceLength = PrefixLength + ContentLength; - var topics = decoderContext.Data.Slice(decoderContext.Position, sequenceLength); - decoderContext.SkipItem(); + var topics = rlpStream.Data.Slice(rlpStream.Position, sequenceLength); + rlpStream.SkipItem(); - int zeroPrefix = decoderContext.DecodeInt(); - ReadOnlySpan rlpData = decoderContext.DecodeByteArraySpan(); + int zeroPrefix = rlpStream.DecodeInt(); + ReadOnlySpan rlpData = rlpStream.DecodeByteArraySpan(); byte[] data = new byte[zeroPrefix + rlpData.Length]; rlpData.CopyTo(data.AsSpan(zeroPrefix)); item = new LogEntryStructRef(address, data, topics); } - public static Hash256[] DecodeTopics(Rlp.ValueDecoderContext valueDecoderContext) + public static Hash256[] DecodeTopics(RlpValueStream valueDecoderContext) { long sequenceLength = valueDecoderContext.ReadSequenceLength(); long untilPosition = valueDecoderContext.Position + sequenceLength; @@ -129,15 +104,8 @@ public static void Encode(RlpStream rlpStream, LogEntry? item, RlpBehaviors rlpB rlpStream.Encode(withoutLeadingZero); } - public int GetLength(LogEntry? item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - if (item is null) - { - return 1; - } - - return Rlp.LengthOfSequence(GetContentLength(item).Total); - } + public int GetLength(LogEntry? item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => + item is null ? 1 : Rlp.LengthOfSequence(GetContentLength(item).Total); private static (int Total, int Topics) GetContentLength(LogEntry? item) { diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/CompactReceiptStorageDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/CompactReceiptStorageDecoder.cs index 80ef6e8681e..a266e03b6f0 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/CompactReceiptStorageDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/CompactReceiptStorageDecoder.cs @@ -51,7 +51,7 @@ public CompactReceiptStorageDecoder() while (rlpStream.Position < lastCheck) { - logEntries.Add(CompactLogEntryDecoder.Decode(rlpStream, RlpBehaviors.AllowExtraBytes)); + logEntries.Add(CompactLogEntryDecoder.Decode(ref rlpStream, RlpBehaviors.AllowExtraBytes)); } txReceipt.Logs = logEntries.ToArray(); @@ -67,19 +67,19 @@ public CompactReceiptStorageDecoder() return txReceipt; } - public TxReceipt? Decode(ref Rlp.ValueDecoderContext decoderContext, + public TxReceipt? Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); return null; } TxReceipt txReceipt = new(); - decoderContext.ReadSequenceLength(); + rlpStream.ReadSequenceLength(); - byte[] firstItem = decoderContext.DecodeByteArray(); + byte[] firstItem = rlpStream.DecodeByteArray(); if (firstItem.Length == 1) { txReceipt.StatusCode = firstItem[0]; @@ -89,17 +89,17 @@ public CompactReceiptStorageDecoder() txReceipt.PostTransactionState = firstItem.Length == 0 ? null : new Hash256(firstItem); } - txReceipt.Sender = decoderContext.DecodeAddress(); - txReceipt.GasUsedTotal = (long)decoderContext.DecodeUBigInt(); + txReceipt.Sender = rlpStream.DecodeAddress(); + txReceipt.GasUsedTotal = (long)rlpStream.DecodeUBigInt(); - int sequenceLength = decoderContext.ReadSequenceLength(); - int lastCheck = sequenceLength + decoderContext.Position; + int sequenceLength = rlpStream.ReadSequenceLength(); + int lastCheck = sequenceLength + rlpStream.Position; // Don't know the size exactly, I'll just assume its just an address and add some margin using ArrayPoolList logEntries = new(sequenceLength * 2 / Rlp.LengthOfAddressRlp); - while (decoderContext.Position < lastCheck) + while (rlpStream.Position < lastCheck) { - logEntries.Add(CompactLogEntryDecoder.Decode(ref decoderContext, RlpBehaviors.AllowExtraBytes)); + logEntries.Add(CompactLogEntryDecoder.Decode(ref rlpStream, RlpBehaviors.AllowExtraBytes)); } txReceipt.Logs = logEntries.ToArray(); @@ -107,7 +107,7 @@ public CompactReceiptStorageDecoder() bool allowExtraBytes = (rlpBehaviors & RlpBehaviors.AllowExtraBytes) != 0; if (!allowExtraBytes) { - decoderContext.Check(lastCheck); + rlpStream.Check(lastCheck); } txReceipt.Bloom = new Bloom(txReceipt.Logs); @@ -115,21 +115,21 @@ public CompactReceiptStorageDecoder() return txReceipt; } - public void DecodeStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors, + public void DecodeStructRef(scoped ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors, out TxReceiptStructRef item) { // Note: This method runs at 2.5 million times/sec on my machine item = new TxReceiptStructRef(); - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); return; } - decoderContext.SkipLength(); + rlpStream.SkipLength(); - ReadOnlySpan firstItem = decoderContext.DecodeByteArraySpan(); + ReadOnlySpan firstItem = rlpStream.DecodeByteArraySpan(); if (firstItem.Length == 1) { item.StatusCode = firstItem[0]; @@ -140,23 +140,23 @@ public void DecodeStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, R firstItem.Length == 0 ? new Hash256StructRef() : new Hash256StructRef(firstItem); } - decoderContext.DecodeAddressStructRef(out item.Sender); - item.GasUsedTotal = (long)decoderContext.DecodeUBigInt(); + rlpStream.DecodeAddressStructRef(out item.Sender); + item.GasUsedTotal = (long)rlpStream.DecodeUBigInt(); (int PrefixLength, int ContentLength) = - decoderContext.PeekPrefixAndContentLength(); + rlpStream.PeekPrefixAndContentLength(); int logsBytes = ContentLength + PrefixLength; - item.LogsRlp = decoderContext.Data.Slice(decoderContext.Position, logsBytes); - decoderContext.SkipItem(); + item.LogsRlp = rlpStream.Data.Slice(rlpStream.Position, logsBytes); + rlpStream.SkipItem(); } - public void DecodeLogEntryStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors none, + public void DecodeLogEntryStructRef(scoped ref RlpValueStream rlpStream, RlpBehaviors none, out LogEntryStructRef current) { - CompactLogEntryDecoder.DecodeLogEntryStructRef(ref decoderContext, none, out current); + CompactLogEntryDecoder.DecodeLogEntryStructRef(ref rlpStream, none, out current); } - public Hash256[] DecodeTopics(Rlp.ValueDecoderContext valueDecoderContext) + public Hash256[] DecodeTopics(RlpValueStream valueDecoderContext) { return CompactLogEntryDecoder.DecodeTopics(valueDecoderContext); } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip2930/AccessListDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip2930/AccessListDecoder.cs index 741cac9aa4d..44f4d2e4974 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip2930/AccessListDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip2930/AccessListDecoder.cs @@ -21,7 +21,20 @@ public class AccessListDecoder : IRlpStreamDecoder, IRlpValueDecode /// RLP serializable item and keep it as a compiled call available at runtime. /// It would be slightly slower but still much faster than what we would get from using dynamic serializers. /// - public AccessList? Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public AccessList? Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => + Decode(ref rlpStream, rlpBehaviors); + + /// + /// We pay a big copy-paste tax to maintain ValueDecoders but we believe that the amount of allocations saved + /// make it worth it. To be reviewed periodically. + /// Question to Lukasz here -> would it be fine to always use ValueDecoderContext only? + /// I believe it cannot be done for the network items decoding and is only relevant for the DB loads. + /// + public AccessList? Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => + Decode(ref rlpStream, rlpBehaviors); + + private AccessList? Decode(ref T rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + where T : IRlpStream, allows ref struct { if (rlpStream.IsNextItemNull()) { @@ -73,66 +86,6 @@ public class AccessListDecoder : IRlpStreamDecoder, IRlpValueDecode return accessListBuilder.Build(); } - /// - /// We pay a big copy-paste tax to maintain ValueDecoders but we believe that the amount of allocations saved - /// make it worth it. To be reviewed periodically. - /// Question to Lukasz here -> would it be fine to always use ValueDecoderContext only? - /// I believe it cannot be done for the network items decoding and is only relevant for the DB loads. - /// - public AccessList? Decode( - ref Rlp.ValueDecoderContext decoderContext, - RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - if (decoderContext.IsNextItemNull()) - { - decoderContext.ReadByte(); - return null; - } - - int length = decoderContext.ReadSequenceLength(); - int check = decoderContext.Position + length; - - AccessList.Builder accessListBuilder = new(); - while (decoderContext.Position < check) - { - int accessListItemLength = decoderContext.ReadSequenceLength(); - int accessListItemCheck = decoderContext.Position + accessListItemLength; - Address address = decoderContext.DecodeAddress() ?? throw new RlpException("Invalid tx access list format - address is null"); - accessListBuilder.AddAddress(address); - - if (decoderContext.Position < check) - { - int storagesLength = decoderContext.ReadSequenceLength(); - int storagesCheck = decoderContext.Position + storagesLength; - while (decoderContext.Position < storagesCheck) - { - int storageItemCheck = decoderContext.Position + IndexLength + 1; - UInt256 index = decoderContext.DecodeUInt256(IndexLength); - accessListBuilder.AddStorage(index); - if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes) - { - decoderContext.Check(storageItemCheck); - } - } - if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes) - { - decoderContext.Check(storagesCheck); - } - } - if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes) - { - decoderContext.Check(accessListItemCheck); - } - } - - if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes) - { - decoderContext.Check(check); - } - - return accessListBuilder.Build(); - } - public void Encode(RlpStream stream, AccessList? item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { if (item is null) @@ -197,11 +150,9 @@ public AccessItemLengths(int indexesCount) public int SequenceLength { get; } } - private static int GetContentLength(AccessList accessList) - { - return accessList + private static int GetContentLength(AccessList accessList) => + accessList .Select(entry => new AccessItemLengths(entry.StorageKeys.Count())) .Sum(lengths => lengths.SequenceLength); - } } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs index 46bbc1cf887..178d323c9b2 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Eip7702/AuthorizationTupleDecoder.cs @@ -15,44 +15,27 @@ public class AuthorizationTupleDecoder : IRlpStreamDecoder, { public static readonly AuthorizationTupleDecoder Instance = new(); - public AuthorizationTuple Decode(RlpStream stream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - int length = stream.ReadSequenceLength(); - int check = length + stream.Position; - ulong chainId = stream.DecodeULong(); - Address? codeAddress = stream.DecodeAddress(); - ulong nonce = stream.DecodeULong(); - byte yParity = stream.DecodeByte(); - UInt256 r = stream.DecodeUInt256(); - UInt256 s = stream.DecodeUInt256(); - - if (!rlpBehaviors.HasFlag(RlpBehaviors.AllowExtraBytes)) - { - stream.Check(check); - } - - if (codeAddress is null) - { - ThrowMissingCodeAddressException(); - } + public AuthorizationTuple Decode(RlpStream stream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => + Decode(ref stream, rlpBehaviors); - return new AuthorizationTuple(chainId, codeAddress, nonce, yParity, r, s); - } + public AuthorizationTuple Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => + Decode(ref rlpStream, rlpBehaviors); - public AuthorizationTuple Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public AuthorizationTuple Decode(ref T rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + where T : IRlpStream, allows ref struct { - int length = decoderContext.ReadSequenceLength(); - int check = length + decoderContext.Position; - ulong chainId = decoderContext.DecodeULong(); - Address? codeAddress = decoderContext.DecodeAddress(); - ulong nonce = decoderContext.DecodeULong(); - byte yParity = decoderContext.DecodeByte(); - UInt256 r = decoderContext.DecodeUInt256(); - UInt256 s = decoderContext.DecodeUInt256(); + int length = rlpStream.ReadSequenceLength(); + int check = length + rlpStream.Position; + ulong chainId = rlpStream.DecodeULong(); + Address? codeAddress = rlpStream.DecodeAddress(); + ulong nonce = rlpStream.DecodeULong(); + byte yParity = rlpStream.DecodeByte(); + UInt256 r = rlpStream.DecodeUInt256(); + UInt256 s = rlpStream.DecodeUInt256(); if (!rlpBehaviors.HasFlag(RlpBehaviors.AllowExtraBytes)) { - decoderContext.Check(check); + rlpStream.Check(check); } if (codeAddress is null) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs index e70f2c9c9b6..2317d63fb51 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs @@ -12,31 +12,31 @@ public class HeaderDecoder : IRlpValueDecoder, IRlpStreamDecoder, IRlpStreamDecoder 0 && - decoderContext.PeekPrefixAndContentLength().ContentLength == Hash256.Size) + rlpStream.PeekPrefixAndContentLength().ContentLength == Hash256.Size) { - blockHeader.WithdrawalsRoot = decoderContext.DecodeKeccak(); + blockHeader.WithdrawalsRoot = rlpStream.DecodeKeccak(); - if (itemsRemaining >= 3 && decoderContext.Position != headerCheck) + if (itemsRemaining >= 3 && rlpStream.Position != headerCheck) { - blockHeader.BlobGasUsed = decoderContext.DecodeULong(); - blockHeader.ExcessBlobGas = decoderContext.DecodeULong(); + blockHeader.BlobGasUsed = rlpStream.DecodeULong(); + blockHeader.ExcessBlobGas = rlpStream.DecodeULong(); } - if (itemsRemaining >= 4 && decoderContext.Position != headerCheck) + if (itemsRemaining >= 4 && rlpStream.Position != headerCheck) { - blockHeader.ParentBeaconBlockRoot = decoderContext.DecodeKeccak(); + blockHeader.ParentBeaconBlockRoot = rlpStream.DecodeKeccak(); } - if (itemsRemaining >= 5 && decoderContext.Position != headerCheck) + if (itemsRemaining >= 5 && rlpStream.Position != headerCheck) { - blockHeader.RequestsHash = decoderContext.DecodeKeccak(); + blockHeader.RequestsHash = rlpStream.DecodeKeccak(); } } if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes) { - decoderContext.Check(headerCheck); + rlpStream.Check(headerCheck); } return blockHeader; diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/IReceiptRefDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/IReceiptRefDecoder.cs index e4e744a0dfc..2dafe7ea4a9 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/IReceiptRefDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/IReceiptRefDecoder.cs @@ -8,8 +8,8 @@ namespace Nethermind.Serialization.Rlp; public interface IReceiptRefDecoder { - void DecodeStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors, out TxReceiptStructRef item); - void DecodeLogEntryStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors none, out LogEntryStructRef current); - Hash256[] DecodeTopics(Rlp.ValueDecoderContext valueDecoderContext); + void DecodeStructRef(scoped ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors, out TxReceiptStructRef item); + void DecodeLogEntryStructRef(scoped ref RlpValueStream rlpStream, RlpBehaviors none, out LogEntryStructRef current); + Hash256[] DecodeTopics(RlpValueStream valueDecoderContext); bool CanDecodeBloom { get; } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/IRlpDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/IRlpDecoder.cs index 4895b9e46d2..695b98ff210 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/IRlpDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/IRlpDecoder.cs @@ -27,14 +27,14 @@ public interface IRlpObjectDecoder : IRlpDecoder public interface IRlpValueDecoder : IRlpDecoder { - T Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None); + T Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None); } public static class RlpValueDecoderExtensions { public static T Decode(this IRlpValueDecoder decoder, ReadOnlySpan bytes, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - Rlp.ValueDecoderContext context = new(bytes); + RlpValueStream context = new(bytes); return decoder.Decode(ref context, rlpBehaviors); } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/IRlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/IRlpStream.cs new file mode 100644 index 00000000000..685d24e07a4 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.Rlp/IRlpStream.cs @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Numerics; +using Nethermind.Core; +using Nethermind.Core.Collections; +using Nethermind.Core.Crypto; +using Nethermind.Int256; + +namespace Nethermind.Serialization.Rlp; + +public interface IRlpStream +{ + int Position { get; set; } + void Check(int nextCheck); + bool IsNextItemNull(); + int ReadSequenceLength(); + int PeekNumberOfItemsRemaining(int? beforePosition = null, int maxSearch = int.MaxValue); + byte ReadByte(); + + + byte[] DecodeByteArray(); + ReadOnlySpan DecodeByteArraySpan(); + + byte DecodeByte(); + int DecodeInt(); + ulong DecodeULong(); + UInt256 DecodeUInt256(int length = -1); + BigInteger DecodeUBigInt(); + + Hash256? DecodeZeroPrefixKeccak(); + + Address? DecodeAddress(); +} diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/KeccakDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/KeccakDecoder.cs index 89dd7e56486..b7cdfae6262 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/KeccakDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/KeccakDecoder.cs @@ -9,7 +9,7 @@ public class KeccakDecoder : IRlpValueDecoder { public static readonly KeccakDecoder Instance = new(); - public Hash256? Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => decoderContext.DecodeKeccak(); + public Hash256? Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => rlpStream.DecodeKeccak(); public static Rlp Encode(Hash256 item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) => Rlp.Encode(item); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/LogEntryDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/LogEntryDecoder.cs index c2bfe06fcd9..fdf5e59cc97 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/LogEntryDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/LogEntryDecoder.cs @@ -32,24 +32,24 @@ public class LogEntryDecoder : IRlpStreamDecoder, IRlpValueDecoder receiptsData) if (receiptsData.Length > 0 && receiptsData[0] == CompactEncoding) { - var decoderContext = new Rlp.ValueDecoderContext(receiptsData[1..]); - return CompactValueDecoder.DecodeArray(ref decoderContext, RlpBehaviors.Storage); + var rlpStream = new RlpValueStream(receiptsData[1..]); + return CompactValueDecoder.DecodeArray(ref rlpStream, RlpBehaviors.Storage); } else { - var decoderContext = new Rlp.ValueDecoderContext(receiptsData); + var rlpStream = new RlpValueStream(receiptsData); try { - return ValueDecoder.DecodeArray(ref decoderContext, RlpBehaviors.Storage); + return ValueDecoder.DecodeArray(ref rlpStream, RlpBehaviors.Storage); } catch (RlpException) { - decoderContext.Position = 0; - return ValueDecoder.DecodeArray(ref decoderContext); + rlpStream.Position = 0; + return ValueDecoder.DecodeArray(ref rlpStream); } } } public TxReceipt DeserializeReceiptObsolete(Hash256 hash, Span receiptData) { - var context = new Rlp.ValueDecoderContext(receiptData); + var context = new RlpValueStream(receiptData); try { var receipt = ValueDecoder.Decode(ref context, RlpBehaviors.Storage); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptRecoveryBlock.cs b/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptRecoveryBlock.cs index 911dc31c9d5..d996cdd35a5 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptRecoveryBlock.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptRecoveryBlock.cs @@ -51,13 +51,13 @@ public Transaction GetNextTransaction() return _transactions[_currentTransactionIndex++]; } - Rlp.ValueDecoderContext decoderContext = new(_transactionData, true) + RlpValueStream rlpStream = new(_transactionData, true) { Position = _currentTransactionPosition }; - TxDecoder.Instance.Decode(ref decoderContext, ref _txBuffer, RlpBehaviors.AllowUnsigned); + TxDecoder.Instance.Decode(ref rlpStream, ref _txBuffer, RlpBehaviors.AllowUnsigned); Hash256 _ = _txBuffer.Hash; // Force Hash evaluation - _currentTransactionPosition = decoderContext.Position; + _currentTransactionPosition = rlpStream.Position; return _txBuffer; } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptStorageDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptStorageDecoder.cs index 655dadabfcf..c67adad38e7 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptStorageDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptStorageDecoder.cs @@ -100,25 +100,25 @@ public ReceiptStorageDecoder() : this(true) return txReceipt; } - public TxReceipt? Decode(ref Rlp.ValueDecoderContext decoderContext, + public TxReceipt? Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); return null; } bool isStorage = (rlpBehaviors & RlpBehaviors.Storage) != 0; TxReceipt txReceipt = new(); - if (!decoderContext.IsSequenceNext()) + if (!rlpStream.IsSequenceNext()) { - decoderContext.SkipLength(); - txReceipt.TxType = (TxType)decoderContext.ReadByte(); + rlpStream.SkipLength(); + txReceipt.TxType = (TxType)rlpStream.ReadByte(); } - decoderContext.ReadSequenceLength(); - byte[] firstItem = decoderContext.DecodeByteArray(); + rlpStream.ReadSequenceLength(); + byte[] firstItem = rlpStream.DecodeByteArray(); if (firstItem.Length == 1) { txReceipt.StatusCode = firstItem[0]; @@ -128,28 +128,28 @@ public ReceiptStorageDecoder() : this(true) txReceipt.PostTransactionState = firstItem.Length == 0 ? null : new Hash256(firstItem); } - if (isStorage) txReceipt.BlockHash = decoderContext.DecodeKeccak(); - if (isStorage) txReceipt.BlockNumber = (long)decoderContext.DecodeUInt256(); - if (isStorage) txReceipt.Index = decoderContext.DecodeInt(); - if (isStorage) txReceipt.Sender = decoderContext.DecodeAddress(); - if (isStorage) txReceipt.Recipient = decoderContext.DecodeAddress(); - if (isStorage) txReceipt.ContractAddress = decoderContext.DecodeAddress(); - if (isStorage) txReceipt.GasUsed = (long)decoderContext.DecodeUBigInt(); - txReceipt.GasUsedTotal = (long)decoderContext.DecodeUBigInt(); - txReceipt.Bloom = decoderContext.DecodeBloom(); - - int lastCheck = decoderContext.ReadSequenceLength() + decoderContext.Position; + if (isStorage) txReceipt.BlockHash = rlpStream.DecodeKeccak(); + if (isStorage) txReceipt.BlockNumber = (long)rlpStream.DecodeUInt256(); + if (isStorage) txReceipt.Index = rlpStream.DecodeInt(); + if (isStorage) txReceipt.Sender = rlpStream.DecodeAddress(); + if (isStorage) txReceipt.Recipient = rlpStream.DecodeAddress(); + if (isStorage) txReceipt.ContractAddress = rlpStream.DecodeAddress(); + if (isStorage) txReceipt.GasUsed = (long)rlpStream.DecodeUBigInt(); + txReceipt.GasUsedTotal = (long)rlpStream.DecodeUBigInt(); + txReceipt.Bloom = rlpStream.DecodeBloom(); + + int lastCheck = rlpStream.ReadSequenceLength() + rlpStream.Position; List logEntries = new(); - while (decoderContext.Position < lastCheck) + while (rlpStream.Position < lastCheck) { - logEntries.Add(Rlp.Decode(ref decoderContext, RlpBehaviors.AllowExtraBytes)); + logEntries.Add(Rlp.Decode(ref rlpStream, RlpBehaviors.AllowExtraBytes)); } bool allowExtraBytes = (rlpBehaviors & RlpBehaviors.AllowExtraBytes) != 0; if (!allowExtraBytes) { - decoderContext.Check(lastCheck); + rlpStream.Check(lastCheck); } if (!allowExtraBytes) @@ -157,17 +157,17 @@ public ReceiptStorageDecoder() : this(true) if (isStorage && _supportTxHash) { // since txHash was added later and may not be in rlp, we provide special mark byte that it will be next - if (decoderContext.PeekByte() == MarkTxHashByte) + if (rlpStream.PeekByte() == MarkTxHashByte) { - decoderContext.ReadByte(); - txReceipt.TxHash = decoderContext.DecodeKeccak(); + rlpStream.ReadByte(); + txReceipt.TxHash = rlpStream.DecodeKeccak(); } } // since error was added later we can only rely on it in cases where we read receipt only and no data follows, empty errors might not be serialized - if (decoderContext.Position != decoderContext.Length) + if (rlpStream.Position != rlpStream.Length) { - txReceipt.Error = decoderContext.DecodeString(); + txReceipt.Error = rlpStream.DecodeString(); } } @@ -333,26 +333,26 @@ public int GetLength(TxReceipt item, RlpBehaviors rlpBehaviors) return result; } - public void DecodeStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors, + public void DecodeStructRef(scoped ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors, out TxReceiptStructRef item) { item = new TxReceiptStructRef(); - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); return; } bool isStorage = (rlpBehaviors & RlpBehaviors.Storage) != 0; - if (!decoderContext.IsSequenceNext()) + if (!rlpStream.IsSequenceNext()) { - decoderContext.SkipLength(); - item.TxType = (TxType)decoderContext.ReadByte(); + rlpStream.SkipLength(); + item.TxType = (TxType)rlpStream.ReadByte(); } - decoderContext.ReadSequenceLength(); - ReadOnlySpan firstItem = decoderContext.DecodeByteArraySpan(); + rlpStream.ReadSequenceLength(); + ReadOnlySpan firstItem = rlpStream.DecodeByteArraySpan(); if (firstItem.Length == 1) { item.StatusCode = firstItem[0]; @@ -365,22 +365,22 @@ public void DecodeStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, R if (isStorage) { - decoderContext.DecodeKeccakStructRef(out item.BlockHash); - item.BlockNumber = (long)decoderContext.DecodeUInt256(); - item.Index = decoderContext.DecodeInt(); - decoderContext.DecodeAddressStructRef(out item.Sender); - decoderContext.DecodeAddressStructRef(out item.Recipient); - decoderContext.DecodeAddressStructRef(out item.ContractAddress); - item.GasUsed = (long)decoderContext.DecodeUBigInt(); + rlpStream.DecodeKeccakStructRef(out item.BlockHash); + item.BlockNumber = (long)rlpStream.DecodeUInt256(); + item.Index = rlpStream.DecodeInt(); + rlpStream.DecodeAddressStructRef(out item.Sender); + rlpStream.DecodeAddressStructRef(out item.Recipient); + rlpStream.DecodeAddressStructRef(out item.ContractAddress); + item.GasUsed = (long)rlpStream.DecodeUBigInt(); } - item.GasUsedTotal = (long)decoderContext.DecodeUBigInt(); - decoderContext.DecodeBloomStructRef(out item.Bloom); + item.GasUsedTotal = (long)rlpStream.DecodeUBigInt(); + rlpStream.DecodeBloomStructRef(out item.Bloom); (int PrefixLength, int ContentLength) = - decoderContext.PeekPrefixAndContentLength(); + rlpStream.PeekPrefixAndContentLength(); int logsBytes = ContentLength + PrefixLength; - item.LogsRlp = decoderContext.Data.Slice(decoderContext.Position, logsBytes); - decoderContext.SkipItem(); + item.LogsRlp = rlpStream.Data.Slice(rlpStream.Position, logsBytes); + rlpStream.SkipItem(); bool allowExtraBytes = (rlpBehaviors & RlpBehaviors.AllowExtraBytes) != 0; if (!allowExtraBytes) @@ -388,28 +388,28 @@ public void DecodeStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, R if (isStorage && _supportTxHash) { // since txHash was added later and may not be in rlp, we provide special mark byte that it will be next - if (decoderContext.PeekByte() == MarkTxHashByte) + if (rlpStream.PeekByte() == MarkTxHashByte) { - decoderContext.ReadByte(); - decoderContext.DecodeKeccakStructRef(out item.TxHash); + rlpStream.ReadByte(); + rlpStream.DecodeKeccakStructRef(out item.TxHash); } } // since error was added later we can only rely on it in cases where we read receipt only and no data follows, empty errors might not be serialized - if (decoderContext.Position != decoderContext.Length) + if (rlpStream.Position != rlpStream.Length) { - item.Error = decoderContext.DecodeString(); + item.Error = rlpStream.DecodeString(); } } } - public void DecodeLogEntryStructRef(scoped ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors behaviour, + public void DecodeLogEntryStructRef(scoped ref RlpValueStream rlpStream, RlpBehaviors behaviour, out LogEntryStructRef current) { - LogEntryDecoder.DecodeStructRef(ref decoderContext, behaviour, out current); + LogEntryDecoder.DecodeStructRef(ref rlpStream, behaviour, out current); } - public Hash256[] DecodeTopics(Rlp.ValueDecoderContext valueDecoderContext) + public Hash256[] DecodeTopics(RlpValueStream valueDecoderContext) { return KeccakDecoder.Instance.DecodeArray(ref valueDecoderContext); } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs index fee3ded8129..5298d5c2ed4 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs @@ -11,7 +11,6 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text; using Nethermind.Core; using Nethermind.Core.Collections; using Nethermind.Core.Crypto; @@ -262,14 +261,14 @@ public static T Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBe return result; } - public static T Decode(ref ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public static T Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { IRlpValueDecoder? rlpDecoder = GetValueDecoder(); - bool shouldCheckStream = decoderContext.Position == 0 && (rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes; - int length = decoderContext.Length; - T? result = rlpDecoder is not null ? rlpDecoder.Decode(ref decoderContext, rlpBehaviors) : throw new RlpException($"{nameof(Rlp)} does not support decoding {typeof(T).Name}"); + bool shouldCheckStream = rlpStream.Position == 0 && (rlpBehaviors & RlpBehaviors.AllowExtraBytes) != RlpBehaviors.AllowExtraBytes; + int length = rlpStream.Length; + T? result = rlpDecoder is not null ? rlpDecoder.Decode(ref rlpStream, rlpBehaviors) : throw new RlpException($"{nameof(Rlp)} does not support decoding {typeof(T).Name}"); if (shouldCheckStream) - decoderContext.Check(length); + rlpStream.Check(length); return result; } @@ -617,1010 +616,6 @@ public static Rlp Encode(params Rlp[] sequence) return new Rlp(allBytes); } - public ref struct ValueDecoderContext - { - public ValueDecoderContext(scoped in ReadOnlySpan data) - { - Data = data; - Position = 0; - } - - public ValueDecoderContext(Memory memory, bool sliceMemory = false) - { - Memory = memory; - Data = memory.Span; - Position = 0; - - // Slice memory is turned off by default. Because if you are not careful and being explicit about it, - // you can end up with a memory leak. - _sliceMemory = sliceMemory; - } - - public Memory? Memory { get; } - - private bool _sliceMemory = false; - - public ReadOnlySpan Data { get; } - - public readonly bool IsEmpty => Data.IsEmpty; - - public int Position { get; set; } - - public readonly int Length => Data.Length; - - public readonly bool ShouldSliceMemory => _sliceMemory; - - public readonly bool IsSequenceNext() - { - return Data[Position] >= 192; - } - - public int PeekNumberOfItemsRemaining(int? beforePosition = null, int maxSearch = int.MaxValue) - { - int positionStored = Position; - int numberOfItems = 0; - while (Position < (beforePosition ?? Data.Length)) - { - int prefix = ReadByte(); - if (prefix <= 128) - { - } - else if (prefix <= 183) - { - int length = prefix - 128; - Position += length; - } - else if (prefix < 192) - { - int lengthOfLength = prefix - 183; - int length = DeserializeLength(lengthOfLength); - if (length < 56) - { - throw new RlpException("Expected length greater or equal 56 and was {length}"); - } - - Position += length; - } - else - { - Position--; - int sequenceLength = ReadSequenceLength(); - Position += sequenceLength; - } - - numberOfItems++; - if (numberOfItems >= maxSearch) - { - break; - } - } - - Position = positionStored; - return numberOfItems; - } - - public void SkipLength() - { - Position += PeekPrefixAndContentLength().PrefixLength; - } - - public int PeekNextRlpLength() - { - (int a, int b) = PeekPrefixAndContentLength(); - return a + b; - } - - public ReadOnlySpan Peek(int length) - { - ReadOnlySpan item = Read(length); - Position -= item.Length; - return item; - } - - public (int PrefixLength, int ContentLength) ReadPrefixAndContentLength() - { - (int prefixLength, int contentLengt) result; - int prefix = ReadByte(); - if (prefix <= 128) - { - result = (0, 1); - } - else if (prefix <= 183) - { - result = (1, prefix - 128); - } - else if (prefix < 192) - { - int lengthOfLength = prefix - 183; - if (lengthOfLength > 4) - { - // strange but needed to pass tests - seems that spec gives int64 length and tests int32 length - throw new RlpException("Expected length of length less or equal 4"); - } - - int length = DeserializeLength(lengthOfLength); - if (length < 56) - { - throw new RlpException("Expected length greater or equal 56 and was {length}"); - } - - result = (lengthOfLength + 1, length); - } - else if (prefix <= 247) - { - result = (1, prefix - 192); - } - else - { - int lengthOfContentLength = prefix - 247; - int contentLength = DeserializeLength(lengthOfContentLength); - if (contentLength < 56) - { - throw new RlpException($"Expected length greater or equal 56 and got {contentLength}"); - } - - - result = (lengthOfContentLength + 1, contentLength); - } - - return result; - } - - - public (int PrefixLength, int ContentLength) PeekPrefixAndContentLength() - { - int memorizedPosition = Position; - (int PrefixLength, int ContentLength) result = ReadPrefixAndContentLength(); - - Position = memorizedPosition; - return result; - } - - public int ReadSequenceLength() - { - int prefix = ReadByte(); - if (prefix < 192) - { - throw new RlpException($"Expected a sequence prefix to be in the range of <192, 255> and got {prefix} at position {Position} in the message of length {Data.Length} starting with {Data[..Math.Min(DebugMessageContentLength, Data.Length)].ToHexString()}"); - } - - if (prefix <= 247) - { - return prefix - 192; - } - - int lengthOfContentLength = prefix - 247; - int contentLength = DeserializeLength(lengthOfContentLength); - if (contentLength < 56) - { - throw new RlpException($"Expected length greater or equal 56 and got {contentLength}"); - } - - return contentLength; - } - - private int DeserializeLength(int lengthOfLength) - { - int result; - if (Data[Position] == 0) - { - throw new RlpException("Length starts with 0"); - } - - if (lengthOfLength == 1) - { - result = Data[Position]; - } - else if (lengthOfLength == 2) - { - result = Data[Position + 1] | (Data[Position] << 8); - } - else if (lengthOfLength == 3) - { - result = Data[Position + 2] | (Data[Position + 1] << 8) | (Data[Position] << 16); - } - else if (lengthOfLength == 4) - { - result = Data[Position + 3] | (Data[Position + 2] << 8) | (Data[Position + 1] << 16) | - (Data[Position] << 24); - } - else - { - // strange but needed to pass tests - seems that spec gives int64 length and tests int32 length - throw new InvalidOperationException($"Invalid length of length = {lengthOfLength}"); - } - - Position += lengthOfLength; - return result; - } - - public byte ReadByte() - { - return Data[Position++]; - } - - public ReadOnlySpan Read(int length) - { - ReadOnlySpan data = Data.Slice(Position, length); - Position += length; - return data; - } - - public Memory ReadMemory(int length) - { - if (_sliceMemory && Memory.HasValue) return ReadSlicedMemory(length); - return Read(length).ToArray(); - } - - private Memory ReadSlicedMemory(int length) - { - Memory data = Memory.Value.Slice(Position, length); - Position += length; - return data; - } - - public readonly void Check(int nextCheck) - { - if (Position != nextCheck) - { - throw new RlpException($"Data checkpoint failed. Expected {nextCheck} and is {Position}"); - } - } - - // This class was introduce to reduce allocations when deserializing receipts. In order to deserialize receipts we first try to deserialize it in new format and then in old format. - // If someone didn't do migration this will result in excessive allocations and GC of the not needed strings. - private class DecodeKeccakRlpException : RlpException - { - private readonly int _prefix; - private readonly int _position; - private readonly int _dataLength; - private string? _message; - - public DecodeKeccakRlpException(string message, Exception inner) : base(message, inner) - { - } - - public DecodeKeccakRlpException(string message) : base(message) - { - } - - public DecodeKeccakRlpException(in int prefix, in int position, in int dataLength) : this(string.Empty) - { - _prefix = prefix; - _position = position; - _dataLength = dataLength; - } - - public override string Message => _message ??= ConstructMessage(); - - private string ConstructMessage() => $"Unexpected prefix of {_prefix} when decoding {nameof(Hash256)} at position {_position} in the message of length {_dataLength}."; - } - - public Hash256? DecodeKeccak() - { - int prefix = ReadByte(); - if (prefix == 128) - { - return null; - } - - if (prefix != 128 + 32) - { - throw new DecodeKeccakRlpException(prefix, Position, Data.Length); - } - - ReadOnlySpan keccakSpan = Read(32); - if (keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) - { - return Keccak.OfAnEmptyString; - } - - if (keccakSpan.SequenceEqual(Keccak.EmptyTreeHash.Bytes)) - { - return Keccak.EmptyTreeHash; - } - - return new Hash256(keccakSpan); - } - - public ValueHash256? DecodeValueKeccak() - { - int prefix = ReadByte(); - if (prefix == 128) - { - return null; - } - - if (prefix != 128 + 32) - { - throw new DecodeKeccakRlpException(prefix, Position, Data.Length); - } - - ReadOnlySpan keccakSpan = Read(32); - if (keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) - { - return Keccak.OfAnEmptyString.ValueHash256; - } - - if (keccakSpan.SequenceEqual(Keccak.EmptyTreeHash.Bytes)) - { - return Keccak.EmptyTreeHash.ValueHash256; - } - - return new ValueHash256(keccakSpan); - } - - public Hash256? DecodeZeroPrefixKeccak() - { - int prefix = PeekByte(); - if (prefix == 128) - { - ReadByte(); - return null; - } - - ReadOnlySpan theSpan = DecodeByteArraySpan(); - byte[] keccakByte = new byte[32]; - theSpan.CopyTo(keccakByte.AsSpan(32 - theSpan.Length)); - return new Hash256(keccakByte); - } - - public void DecodeKeccakStructRef(out Hash256StructRef keccak) - { - int prefix = ReadByte(); - if (prefix == 128) - { - keccak = new Hash256StructRef(Keccak.Zero.Bytes); - } - else if (prefix != 128 + 32) - { - throw new DecodeKeccakRlpException(prefix, Position, Data.Length); - } - else - { - ReadOnlySpan keccakSpan = Read(32); - if (keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) - { - keccak = new Hash256StructRef(Keccak.OfAnEmptyString.Bytes); - } - else if (keccakSpan.SequenceEqual(Keccak.EmptyTreeHash.Bytes)) - { - keccak = new Hash256StructRef(Keccak.EmptyTreeHash.Bytes); - } - else - { - keccak = new Hash256StructRef(keccakSpan); - } - } - } - - public void DecodeZeroPrefixedKeccakStructRef(out Hash256StructRef keccak, Span buffer) - { - int prefix = PeekByte(); - if (prefix == 128) - { - ReadByte(); - keccak = new Hash256StructRef(Keccak.Zero.Bytes); - } - else if (prefix > 128 + 32) - { - ReadByte(); - throw new DecodeKeccakRlpException(prefix, Position, Data.Length); - } - else if (prefix == 128 + 32) - { - ReadByte(); - ReadOnlySpan keccakSpan = Read(32); - if (keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) - { - keccak = new Hash256StructRef(Keccak.OfAnEmptyString.Bytes); - } - else if (keccakSpan.SequenceEqual(Keccak.EmptyTreeHash.Bytes)) - { - keccak = new Hash256StructRef(Keccak.EmptyTreeHash.Bytes); - } - else - { - keccak = new Hash256StructRef(keccakSpan); - } - } - else - { - ReadOnlySpan theSpan = DecodeByteArraySpan(); - if (theSpan.Length < 32) - { - buffer[..(32 - theSpan.Length)].Clear(); - } - theSpan.CopyTo(buffer[(32 - theSpan.Length)..]); - keccak = new Hash256StructRef(buffer); - } - } - - public Address? DecodeAddress() - { - int prefix = ReadByte(); - if (prefix == 128) - { - return null; - } - - if (prefix != 128 + 20) - { - ThrowInvalidPrefix(ref this, prefix); - } - - byte[] buffer = Read(20).ToArray(); - return new Address(buffer); - - static void ThrowInvalidPrefix(ref ValueDecoderContext ctx, int prefix) - { - throw new RlpException($"Unexpected prefix of {prefix} when decoding {nameof(Hash256)} at position {ctx.Position} in the message of length {ctx.Data.Length} starting with {ctx.Data[..Math.Min(DebugMessageContentLength, ctx.Data.Length)].ToHexString()}"); - } - } - - public void DecodeAddressStructRef(out AddressStructRef address) - { - int prefix = ReadByte(); - if (prefix == 128) - { - address = new AddressStructRef(Address.Zero.Bytes); - return; - } - else if (prefix != 128 + 20) - { - ThrowInvalidPrefix(ref this, prefix); - } - - address = new AddressStructRef(Read(20)); - } - - [DoesNotReturn] - [StackTraceHidden] - private static void ThrowInvalidPrefix(ref ValueDecoderContext ctx, int prefix) - { - throw new RlpException($"Unexpected prefix of {prefix} when decoding {nameof(Hash256)} at position {ctx.Position} in the message of length {ctx.Data.Length} starting with {ctx.Data[..Math.Min(DebugMessageContentLength, ctx.Data.Length)].ToHexString()}"); - } - - public UInt256 DecodeUInt256(int length = -1) - { - ReadOnlySpan byteSpan = DecodeByteArraySpan(); - if (byteSpan.Length > 32) - { - ThrowDataTooLong(); - } - - if (length == -1) - { - if (byteSpan.Length > 1 && byteSpan[0] == 0) - { - ThrowNonCanonicalUInt256(Position); - } - } - else if (byteSpan.Length != length) - { - ThrowInvalidLength(Position); - } - - - return new UInt256(byteSpan, true); - - [DoesNotReturn] - [StackTraceHidden] - static void ThrowDataTooLong() => throw new RlpException("UInt256 cannot be longer than 32 bytes"); - - [DoesNotReturn] - [StackTraceHidden] - static void ThrowNonCanonicalUInt256(int position) => throw new RlpException($"Non-canonical UInt256 (leading zero bytes) at position {position}"); - - [DoesNotReturn] - [StackTraceHidden] - static void ThrowInvalidLength(int position) => throw new RlpException($"Invalid length at position {position}"); - } - - public BigInteger DecodeUBigInt() - { - ReadOnlySpan bytes = DecodeByteArraySpan(); - if (bytes.Length > 1 && bytes[0] == 0) - { - throw new RlpException($"Non-canonical UBigInt (leading zero bytes) at position {Position}"); - } - return bytes.ToUnsignedBigInteger(); - } - - public Bloom? DecodeBloom() - { - ReadOnlySpan bloomBytes; - - // tks: not sure why but some nodes send us Blooms in a sequence form - // https://github.com/NethermindEth/nethermind/issues/113 - if (Data[Position] == 249) - { - Position += 5; // tks: skip 249 1 2 129 127 and read 256 bytes - bloomBytes = Read(256); - } - else - { - bloomBytes = DecodeByteArraySpan(); - if (bloomBytes.Length == 0) - { - return null; - } - } - - if (bloomBytes.Length != 256) - { - throw new InvalidOperationException("Incorrect bloom RLP"); - } - - return bloomBytes.SequenceEqual(Bloom.Empty.Bytes) ? Bloom.Empty : new Bloom(bloomBytes.ToArray()); - } - - public void DecodeBloomStructRef(out BloomStructRef bloom) - { - ReadOnlySpan bloomBytes; - - // tks: not sure why but some nodes send us Blooms in a sequence form - // https://github.com/NethermindEth/nethermind/issues/113 - if (Data[Position] == 249) - { - Position += 5; // tks: skip 249 1 2 129 127 and read 256 bytes - bloomBytes = Read(256); - } - else - { - bloomBytes = DecodeByteArraySpan(); - if (bloomBytes.Length == 0) - { - bloom = new BloomStructRef(Bloom.Empty.Bytes); - return; - } - } - - if (bloomBytes.Length != 256) - { - throw new InvalidOperationException("Incorrect bloom RLP"); - } - - bloom = bloomBytes.SequenceEqual(Bloom.Empty.Bytes) ? new BloomStructRef(Bloom.Empty.Bytes) : new BloomStructRef(bloomBytes); - } - - public ReadOnlySpan PeekNextItem() - { - int length = PeekNextRlpLength(); - ReadOnlySpan item = Read(length); - Position -= item.Length; - return item; - } - - public readonly bool IsNextItemNull() - { - return Data[Position] == 192; - } - - public int DecodeInt() - { - int prefix = ReadByte(); - - switch (prefix) - { - case 0: - throw new RlpException($"Non-canonical integer (leading zero bytes) at position {Position}"); - case < 128: - return prefix; - case 128: - return 0; - } - - int length = prefix - 128; - if (length > 4) - { - throw new RlpException($"Unexpected length of int value: {length}"); - } - - int result = 0; - for (int i = 4; i > 0; i--) - { - result <<= 8; - if (i <= length) - { - result |= Data[Position + length - i]; - if (result == 0) - { - throw new RlpException($"Non-canonical integer (leading zero bytes) at position {Position}"); - } - } - } - - Position += length; - - return result; - } - - public byte[] DecodeByteArray() - { - return ByteSpanToArray(DecodeByteArraySpan()); - } - - public ReadOnlySpan DecodeByteArraySpan() - { - int prefix = ReadByte(); - ReadOnlySpan span = RlpStream.SingleBytes; - if ((uint)prefix < (uint)span.Length) - { - return span.Slice(prefix, 1); - } - - if (prefix == 128) - { - return default; - } - - if (prefix <= 183) - { - int length = prefix - 128; - ReadOnlySpan buffer = Read(length); - if (length == 1 && buffer[0] < 128) - { - ThrowUnexpectedValue(buffer[0]); - } - - return buffer; - } - - return DecodeLargerByteArraySpan(prefix); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private ReadOnlySpan DecodeLargerByteArraySpan(int prefix) - { - if (prefix < 192) - { - int lengthOfLength = prefix - 183; - if (lengthOfLength > 4) - { - // strange but needed to pass tests - seems that spec gives int64 length and tests int32 length - ThrowUnexpectedLengthOfLength(); - } - - int length = DeserializeLength(lengthOfLength); - if (length < 56) - { - ThrowUnexpectedLength(length); - } - - return Read(length); - } - - ThrowUnexpectedPrefix(prefix); - return default; - } - - public Memory? DecodeByteArrayMemory() - { - if (!_sliceMemory) - { - return DecodeByteArraySpan().ToArray(); - } - - if (Memory is null) - { - ThrowNotMemoryBacked(); - } - - int prefix = ReadByte(); - - switch (prefix) - { - case < 128: - return Memory.Value.Slice(Position - 1, 1); - case 128: - return Array.Empty(); - case <= 183: - { - int length = prefix - 128; - Memory buffer = ReadSlicedMemory(length); - Span asSpan = buffer.Span; - if (length == 1 && asSpan[0] < 128) - { - ThrowUnexpectedValue(asSpan[0]); - } - - return buffer; - } - case < 192: - { - int lengthOfLength = prefix - 183; - if (lengthOfLength > 4) - { - // strange but needed to pass tests - seems that spec gives int64 length and tests int32 length - ThrowUnexpectedLengthOfLength(); - } - - int length = DeserializeLength(lengthOfLength); - if (length < 56) - { - ThrowUnexpectedLength(length); - } - - return ReadSlicedMemory(length); - } - } - - ThrowUnexpectedPrefix(prefix); - return default; - - [DoesNotReturn] - [StackTraceHidden] - static void ThrowNotMemoryBacked() - { - throw new RlpException("Rlp not backed by a Memory"); - } - } - - [DoesNotReturn] - [StackTraceHidden] - static void ThrowUnexpectedPrefix(int prefix) - { - throw new RlpException($"Unexpected prefix value of {prefix} when decoding a byte array."); - } - - [DoesNotReturn] - [StackTraceHidden] - static void ThrowUnexpectedLength(int length) - { - throw new RlpException($"Expected length greater or equal 56 and was {length}"); - } - - [DoesNotReturn] - [StackTraceHidden] - static void ThrowUnexpectedValue(int buffer0) - { - throw new RlpException($"Unexpected byte value {buffer0}"); - } - - [DoesNotReturn] - [StackTraceHidden] - static void ThrowUnexpectedLengthOfLength() - { - throw new RlpException("Expected length of length less or equal 4"); - } - - public void SkipItem() - { - (int prefix, int content) = PeekPrefixAndContentLength(); - Position += prefix + content; - } - - public void Reset() - { - Position = 0; - } - - public bool DecodeBool() - { - int prefix = ReadByte(); - if (prefix <= 128) - { - return prefix == 1; - } - - if (prefix <= 183) - { - int length = prefix - 128; - if (length == 1 && PeekByte() < 128) - { - throw new RlpException($"Unexpected byte value {PeekByte()}"); - } - - bool result = PeekByte() == 1; - SkipBytes(length); - return result; - } - - if (prefix < 192) - { - int lengthOfLength = prefix - 183; - if (lengthOfLength > 4) - { - // strange but needed to pass tests - seems that spec gives int64 length and tests int32 length - throw new RlpException("Expected length of length less or equal 4"); - } - - int length = DeserializeLength(lengthOfLength); - if (length < 56) - { - throw new RlpException("Expected length greater or equal 56 and was {length}"); - } - - bool result = PeekByte() == 1; - SkipBytes(length); - return result; - } - - throw new RlpException($"Unexpected prefix of {prefix} when decoding a byte array at position {Position} in the message of length {Length} starting with {Description}"); - } - - private readonly string Description => Data[..Math.Min(DebugMessageContentLength, Length)].ToHexString(); - - public readonly byte PeekByte() - { - return Data[Position]; - } - - private readonly byte PeekByte(int offset) - { - return Data[Position + offset]; - } - - private void SkipBytes(int length) - { - Position += length; - } - - public string DecodeString() - { - ReadOnlySpan bytes = DecodeByteArraySpan(); - return Encoding.UTF8.GetString(bytes); - } - - public long DecodeLong() - { - int prefix = ReadByte(); - - switch (prefix) - { - case 0: - throw new RlpException($"Non-canonical long (leading zero bytes) at position {Position}"); - case < 128: - return prefix; - case 128: - return 0; - } - - int length = prefix - 128; - if (length > 8) - { - throw new RlpException($"Unexpected length of long value: {length}"); - } - - long result = 0; - for (int i = 8; i > 0; i--) - { - result <<= 8; - if (i <= length) - { - result |= PeekByte(length - i); - if (result == 0) - { - throw new RlpException($"Non-canonical long (leading zero bytes) at position {Position}"); - } - } - } - - SkipBytes(length); - - return result; - } - - public ulong DecodeULong() - { - int prefix = ReadByte(); - - switch (prefix) - { - case 0: - throw new RlpException($"Non-canonical ulong (leading zero bytes) at position {Position}"); - case < 128: - return (ulong)prefix; - case 128: - return 0; - } - - int length = prefix - 128; - if (length > 8) - { - throw new RlpException($"Unexpected length of long value: {length}"); - } - - ulong result = 0ul; - for (int i = 8; i > 0; i--) - { - result <<= 8; - if (i <= length) - { - result |= PeekByte(length - i); - if (result == 0) - { - throw new RlpException($"Non-canonical ulong (leading zero bytes) at position {Position}"); - } - } - } - - SkipBytes(length); - - return result; - } - - internal byte[][] DecodeByteArrays() - { - int length = ReadSequenceLength(); - if (length is 0) - { - return []; - } - - int itemsCount = PeekNumberOfItemsRemaining(Position + length); - byte[][] result = new byte[itemsCount][]; - - for (int i = 0; i < itemsCount; i++) - { - result[i] = DecodeByteArray(); - } - - return result; - } - - public byte DecodeByte() - { - byte byteValue = PeekByte(); - if (byteValue < 128) - { - SkipBytes(1); - return byteValue; - } - - if (byteValue == 128) - { - SkipBytes(1); - return 0; - } - - if (byteValue == 129) - { - SkipBytes(1); - return ReadByte(); - } - - throw new RlpException($"Unexpected value while decoding byte {byteValue}"); - } - - public T[] DecodeArray(IRlpValueDecoder? decoder = null, bool checkPositions = true, - T defaultElement = default) - { - if (decoder is null) - { - decoder = GetValueDecoder(); - if (decoder is null) - { - throw new RlpException($"{nameof(Rlp)} does not support length of {nameof(T)}"); - } - } - int positionCheck = ReadSequenceLength() + Position; - int count = PeekNumberOfItemsRemaining(checkPositions ? positionCheck : null); - T[] result = new T[count]; - for (int i = 0; i < result.Length; i++) - { - if (PeekByte() == Rlp.OfEmptySequence[0]) - { - result[i] = defaultElement; - Position++; - } - else - { - result[i] = decoder.Decode(ref this); - } - } - - return result; - } - - public readonly bool IsNextItemEmptyArray() - { - return PeekByte() == EmptyArrayByte; - } - - } - public override bool Equals(object? other) { return Equals(other as Rlp); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/RlpDecoderExtensions.cs b/src/Nethermind/Nethermind.Serialization.Rlp/RlpDecoderExtensions.cs index ecb9539e7cb..afecd8b4d1a 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/RlpDecoderExtensions.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/RlpDecoderExtensions.cs @@ -23,13 +23,13 @@ public static T[] DecodeArray(this IRlpStreamDecoder decoder, RlpStream rl return result; } - public static T[] DecodeArray(this IRlpValueDecoder decoder, ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public static T[] DecodeArray(this IRlpValueDecoder decoder, ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - int checkPosition = decoderContext.ReadSequenceLength() + decoderContext.Position; - T[] result = new T[decoderContext.PeekNumberOfItemsRemaining(checkPosition)]; + int checkPosition = rlpStream.ReadSequenceLength() + rlpStream.Position; + T[] result = new T[rlpStream.PeekNumberOfItemsRemaining(checkPosition)]; for (int i = 0; i < result.Length; i++) { - result[i] = decoder.Decode(ref decoderContext, rlpBehaviors); + result[i] = decoder.Decode(ref rlpStream, rlpBehaviors); } return result; diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs index f541ac3f9dd..0ccc8a79219 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs @@ -19,7 +19,7 @@ namespace Nethermind.Serialization.Rlp { - public class RlpStream + public class RlpStream : IRlpStream { private static readonly HeaderDecoder _headerDecoder = new(); private static readonly BlockDecoder _blockDecoder = new(); @@ -1337,15 +1337,9 @@ public ulong DecodeUlong() return bytes.Length == 0 ? 0L : bytes.ReadEthUInt64(); } - public byte[] DecodeByteArray() - { - return Rlp.ByteSpanToArray(DecodeByteArraySpan()); - } + public byte[] DecodeByteArray() => Rlp.ByteSpanToArray(DecodeByteArraySpan()); - public ArrayPoolList DecodeByteArrayPoolList() - { - return Rlp.ByteSpanToArrayPool(DecodeByteArraySpan()); - } + public ArrayPoolList DecodeByteArrayPoolList() => Rlp.ByteSpanToArrayPool(DecodeByteArraySpan()); public ReadOnlySpan DecodeByteArraySpan() { @@ -1478,7 +1472,7 @@ public byte[][] DecodeByteArrays() return result; } - internal static ReadOnlySpan SingleBytes => new byte[128] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127 }; - internal static byte[][] SingleByteArrays = new byte[128][] { [0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30], [31], [32], [33], [34], [35], [36], [37], [38], [39], [40], [41], [42], [43], [44], [45], [46], [47], [48], [49], [50], [51], [52], [53], [54], [55], [56], [57], [58], [59], [60], [61], [62], [63], [64], [65], [66], [67], [68], [69], [70], [71], [72], [73], [74], [75], [76], [77], [78], [79], [80], [81], [82], [83], [84], [85], [86], [87], [88], [89], [90], [91], [92], [93], [94], [95], [96], [97], [98], [99], [100], [101], [102], [103], [104], [105], [106], [107], [108], [109], [110], [111], [112], [113], [114], [115], [116], [117], [118], [119], [120], [121], [122], [123], [124], [125], [126], [127] }; + internal static ReadOnlySpan SingleBytes => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127]; + internal static byte[][] SingleByteArrays = [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30], [31], [32], [33], [34], [35], [36], [37], [38], [39], [40], [41], [42], [43], [44], [45], [46], [47], [48], [49], [50], [51], [52], [53], [54], [55], [56], [57], [58], [59], [60], [61], [62], [63], [64], [65], [66], [67], [68], [69], [70], [71], [72], [73], [74], [75], [76], [77], [78], [79], [80], [81], [82], [83], [84], [85], [86], [87], [88], [89], [90], [91], [92], [93], [94], [95], [96], [97], [98], [99], [100], [101], [102], [103], [104], [105], [106], [107], [108], [109], [110], [111], [112], [113], [114], [115], [116], [117], [118], [119], [120], [121], [122], [123], [124], [125], [126], [127]]; } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/RlpValueStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/RlpValueStream.cs new file mode 100644 index 00000000000..03fb6c7b9d5 --- /dev/null +++ b/src/Nethermind/Nethermind.Serialization.Rlp/RlpValueStream.cs @@ -0,0 +1,959 @@ +// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Text; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; +using Nethermind.Int256; + +namespace Nethermind.Serialization.Rlp; + +public ref struct RlpValueStream : IRlpStream +{ + public RlpValueStream(scoped in ReadOnlySpan data) + { + Data = data; + Position = 0; + } + + public RlpValueStream(Memory memory, bool sliceMemory = false) + { + Memory = memory; + Data = memory.Span; + Position = 0; + + // Slice memory is turned off by default. Because if you are not careful and being explicit about it, + // you can end up with a memory leak. + _sliceMemory = sliceMemory; + } + + public Memory? Memory { get; } + + private readonly bool _sliceMemory = false; + + public ReadOnlySpan Data { get; } + + public readonly bool IsEmpty => Data.IsEmpty; + + public int Position { get; set; } + + public readonly int Length => Data.Length; + + public readonly bool ShouldSliceMemory => _sliceMemory; + + public readonly bool IsSequenceNext() => Data[Position] >= 192; + + public int PeekNumberOfItemsRemaining(int? beforePosition = null, int maxSearch = int.MaxValue) + { + int positionStored = Position; + int numberOfItems = 0; + while (Position < (beforePosition ?? Data.Length)) + { + int prefix = ReadByte(); + switch (prefix) + { + case <= 128: + break; + case <= 183: + { + int length = prefix - 128; + Position += length; + break; + } + case < 192: + { + int lengthOfLength = prefix - 183; + int length = DeserializeLength(lengthOfLength); + if (length < 56) + { + throw new RlpException("Expected length greater or equal 56 and was {length}"); + } + + Position += length; + break; + } + default: + { + Position--; + int sequenceLength = ReadSequenceLength(); + Position += sequenceLength; + break; + } + } + + numberOfItems++; + if (numberOfItems >= maxSearch) + { + break; + } + } + + Position = positionStored; + return numberOfItems; + } + + public void SkipLength() + { + Position += PeekPrefixAndContentLength().PrefixLength; + } + + public int PeekNextRlpLength() + { + (int a, int b) = PeekPrefixAndContentLength(); + return a + b; + } + + public ReadOnlySpan Peek(int length) + { + ReadOnlySpan item = Read(length); + Position -= item.Length; + return item; + } + + public (int PrefixLength, int ContentLength) ReadPrefixAndContentLength() + { + int prefix = ReadByte(); + switch (prefix) + { + case <= 128: + return (0, 1); + case <= 183: + return (1, prefix - 128); + case < 192: + { + int lengthOfLength = prefix - 183; + if (lengthOfLength > 4) + { + // strange but needed to pass tests - seems that spec gives int64 length and tests int32 length + throw new RlpException("Expected length of length less or equal 4"); + } + + int length = DeserializeLength(lengthOfLength); + if (length < 56) + { + throw new RlpException("Expected length greater or equal 56 and was {length}"); + } + + return (lengthOfLength + 1, length); + } + case <= 247: + return (1, prefix - 192); + default: + { + int lengthOfContentLength = prefix - 247; + int contentLength = DeserializeLength(lengthOfContentLength); + if (contentLength < 56) + { + throw new RlpException($"Expected length greater or equal 56 and got {contentLength}"); + } + + + return (lengthOfContentLength + 1, contentLength); + } + } + } + + + public (int PrefixLength, int ContentLength) PeekPrefixAndContentLength() + { + int memorizedPosition = Position; + (int PrefixLength, int ContentLength) result = ReadPrefixAndContentLength(); + + Position = memorizedPosition; + return result; + } + + public int ReadSequenceLength() + { + int prefix = ReadByte(); + if (prefix < 192) + { + throw new RlpException($"Expected a sequence prefix to be in the range of <192, 255> and got {prefix} at position {Position} in the message of length {Data.Length} starting with {Data[..Math.Min(Rlp.DebugMessageContentLength, Data.Length)].ToHexString()}"); + } + + if (prefix <= 247) + { + return prefix - 192; + } + + int lengthOfContentLength = prefix - 247; + int contentLength = DeserializeLength(lengthOfContentLength); + if (contentLength < 56) + { + throw new RlpException($"Expected length greater or equal 56 and got {contentLength}"); + } + + return contentLength; + } + + private int DeserializeLength(int lengthOfLength) + { + if (Data[Position] == 0) + { + throw new RlpException("Length starts with 0"); + } + + int result = lengthOfLength switch + { + 1 => Data[Position], + 2 => Data[Position + 1] | (Data[Position] << 8), + 3 => Data[Position + 2] | (Data[Position + 1] << 8) | (Data[Position] << 16), + 4 => Data[Position + 3] | (Data[Position + 2] << 8) | (Data[Position + 1] << 16) | (Data[Position] << 24), + _ => throw new InvalidOperationException($"Invalid length of length = {lengthOfLength}") + }; + + Position += lengthOfLength; + return result; + } + + public byte ReadByte() => Data[Position++]; + + public ReadOnlySpan Read(int length) + { + ReadOnlySpan data = Data.Slice(Position, length); + Position += length; + return data; + } + + public Memory ReadMemory(int length) + { + if (_sliceMemory && Memory.HasValue) return ReadSlicedMemory(length); + return Read(length).ToArray(); + } + + private Memory ReadSlicedMemory(int length) + { + Memory data = Memory!.Value.Slice(Position, length); + Position += length; + return data; + } + + public readonly void Check(int nextCheck) + { + if (Position != nextCheck) + { + throw new RlpException($"Data checkpoint failed. Expected {nextCheck} and is {Position}"); + } + } + + // This class was introduce to reduce allocations when deserializing receipts. In order to deserialize receipts we first try to deserialize it in new format and then in old format. + // If someone didn't do migration this will result in excessive allocations and GC of the not needed strings. + private class DecodeKeccakRlpException : RlpException + { + private readonly int _prefix; + private readonly int _position; + private readonly int _dataLength; + private string? _message; + + public DecodeKeccakRlpException(string message, Exception inner) : base(message, inner) + { + } + + public DecodeKeccakRlpException(string message) : base(message) + { + } + + public DecodeKeccakRlpException(in int prefix, in int position, in int dataLength) : this(string.Empty) + { + _prefix = prefix; + _position = position; + _dataLength = dataLength; + } + + public override string Message => _message ??= ConstructMessage(); + + private string ConstructMessage() => $"Unexpected prefix of {_prefix} when decoding {nameof(Hash256)} at position {_position} in the message of length {_dataLength}."; + } + + public Hash256? DecodeKeccak() + { + int prefix = ReadByte(); + if (prefix == 128) + { + return null; + } + + if (prefix != 128 + 32) + { + throw new DecodeKeccakRlpException(prefix, Position, Data.Length); + } + + ReadOnlySpan keccakSpan = Read(32); + return keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes) ? Keccak.OfAnEmptyString + : keccakSpan.SequenceEqual(Keccak.EmptyTreeHash.Bytes) ? Keccak.EmptyTreeHash + : new Hash256(keccakSpan); + } + + public ValueHash256? DecodeValueKeccak() + { + int prefix = ReadByte(); + if (prefix == 128) + { + return null; + } + + if (prefix != 128 + 32) + { + throw new DecodeKeccakRlpException(prefix, Position, Data.Length); + } + + ReadOnlySpan keccakSpan = Read(32); + return keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes) ? Keccak.OfAnEmptyString.ValueHash256 + : keccakSpan.SequenceEqual(Keccak.EmptyTreeHash.Bytes) ? Keccak.EmptyTreeHash.ValueHash256 + : new ValueHash256(keccakSpan); + } + + public Hash256? DecodeZeroPrefixKeccak() + { + int prefix = PeekByte(); + if (prefix == 128) + { + ReadByte(); + return null; + } + + ReadOnlySpan theSpan = DecodeByteArraySpan(); + byte[] keccakByte = new byte[32]; + theSpan.CopyTo(keccakByte.AsSpan(32 - theSpan.Length)); + return new Hash256(keccakByte); + } + + public void DecodeKeccakStructRef(out Hash256StructRef keccak) + { + int prefix = ReadByte(); + if (prefix == 128) + { + keccak = new Hash256StructRef(Keccak.Zero.Bytes); + } + else if (prefix != 128 + 32) + { + throw new DecodeKeccakRlpException(prefix, Position, Data.Length); + } + else + { + ReadOnlySpan keccakSpan = Read(32); + if (keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) + { + keccak = new Hash256StructRef(Keccak.OfAnEmptyString.Bytes); + } + else if (keccakSpan.SequenceEqual(Keccak.EmptyTreeHash.Bytes)) + { + keccak = new Hash256StructRef(Keccak.EmptyTreeHash.Bytes); + } + else + { + keccak = new Hash256StructRef(keccakSpan); + } + } + } + + public void DecodeZeroPrefixedKeccakStructRef(out Hash256StructRef keccak, Span buffer) + { + int prefix = PeekByte(); + if (prefix == 128) + { + ReadByte(); + keccak = new Hash256StructRef(Keccak.Zero.Bytes); + } + else if (prefix > 128 + 32) + { + ReadByte(); + throw new DecodeKeccakRlpException(prefix, Position, Data.Length); + } + else if (prefix == 128 + 32) + { + ReadByte(); + ReadOnlySpan keccakSpan = Read(32); + if (keccakSpan.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) + { + keccak = new Hash256StructRef(Keccak.OfAnEmptyString.Bytes); + } + else if (keccakSpan.SequenceEqual(Keccak.EmptyTreeHash.Bytes)) + { + keccak = new Hash256StructRef(Keccak.EmptyTreeHash.Bytes); + } + else + { + keccak = new Hash256StructRef(keccakSpan); + } + } + else + { + ReadOnlySpan theSpan = DecodeByteArraySpan(); + if (theSpan.Length < 32) + { + buffer[..(32 - theSpan.Length)].Clear(); + } + theSpan.CopyTo(buffer[(32 - theSpan.Length)..]); + keccak = new Hash256StructRef(buffer); + } + } + + public Address? DecodeAddress() + { + int prefix = ReadByte(); + if (prefix == 128) + { + return null; + } + + if (prefix != 128 + 20) + { + ThrowInvalidPrefix(ref this, prefix); + } + + byte[] buffer = Read(20).ToArray(); + return new Address(buffer); + + static void ThrowInvalidPrefix(ref RlpValueStream ctx, int prefix) + { + throw new RlpException($"Unexpected prefix of {prefix} when decoding {nameof(Hash256)} at position {ctx.Position} in the message of length {ctx.Data.Length} starting with {ctx.Data[..Math.Min(Rlp.DebugMessageContentLength, ctx.Data.Length)].ToHexString()}"); + } + } + + public void DecodeAddressStructRef(out AddressStructRef address) + { + int prefix = ReadByte(); + if (prefix == 128) + { + address = new AddressStructRef(Address.Zero.Bytes); + return; + } + else if (prefix != 128 + 20) + { + ThrowInvalidPrefix(ref this, prefix); + } + + address = new AddressStructRef(Read(20)); + } + + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowInvalidPrefix(ref RlpValueStream ctx, int prefix) + { + throw new RlpException($"Unexpected prefix of {prefix} when decoding {nameof(Hash256)} at position {ctx.Position} in the message of length {ctx.Data.Length} starting with {ctx.Data[..Math.Min(Rlp.DebugMessageContentLength, ctx.Data.Length)].ToHexString()}"); + } + + public UInt256 DecodeUInt256(int length = -1) + { + ReadOnlySpan byteSpan = DecodeByteArraySpan(); + if (byteSpan.Length > 32) + { + ThrowDataTooLong(); + } + + if (length == -1) + { + if (byteSpan.Length > 1 && byteSpan[0] == 0) + { + ThrowNonCanonicalUInt256(Position); + } + } + else if (byteSpan.Length != length) + { + ThrowInvalidLength(Position); + } + + + return new UInt256(byteSpan, true); + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowDataTooLong() => throw new RlpException("UInt256 cannot be longer than 32 bytes"); + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowNonCanonicalUInt256(int position) => throw new RlpException($"Non-canonical UInt256 (leading zero bytes) at position {position}"); + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowInvalidLength(int position) => throw new RlpException($"Invalid length at position {position}"); + } + + public BigInteger DecodeUBigInt() + { + ReadOnlySpan bytes = DecodeByteArraySpan(); + if (bytes.Length > 1 && bytes[0] == 0) + { + throw new RlpException($"Non-canonical UBigInt (leading zero bytes) at position {Position}"); + } + return bytes.ToUnsignedBigInteger(); + } + + public Bloom? DecodeBloom() + { + ReadOnlySpan bloomBytes; + + // tks: not sure why but some nodes send us Blooms in a sequence form + // https://github.com/NethermindEth/nethermind/issues/113 + if (Data[Position] == 249) + { + Position += 5; // tks: skip 249 1 2 129 127 and read 256 bytes + bloomBytes = Read(256); + } + else + { + bloomBytes = DecodeByteArraySpan(); + if (bloomBytes.Length == 0) + { + return null; + } + } + + if (bloomBytes.Length != 256) + { + throw new InvalidOperationException("Incorrect bloom RLP"); + } + + return bloomBytes.SequenceEqual(Bloom.Empty.Bytes) ? Bloom.Empty : new Bloom(bloomBytes.ToArray()); + } + + public void DecodeBloomStructRef(out BloomStructRef bloom) + { + ReadOnlySpan bloomBytes; + + // tks: not sure why but some nodes send us Blooms in a sequence form + // https://github.com/NethermindEth/nethermind/issues/113 + if (Data[Position] == 249) + { + Position += 5; // tks: skip 249 1 2 129 127 and read 256 bytes + bloomBytes = Read(256); + } + else + { + bloomBytes = DecodeByteArraySpan(); + if (bloomBytes.Length == 0) + { + bloom = new BloomStructRef(Bloom.Empty.Bytes); + return; + } + } + + if (bloomBytes.Length != 256) + { + throw new InvalidOperationException("Incorrect bloom RLP"); + } + + bloom = bloomBytes.SequenceEqual(Bloom.Empty.Bytes) ? new BloomStructRef(Bloom.Empty.Bytes) : new BloomStructRef(bloomBytes); + } + + public ReadOnlySpan PeekNextItem() + { + int length = PeekNextRlpLength(); + ReadOnlySpan item = Read(length); + Position -= item.Length; + return item; + } + + public readonly bool IsNextItemNull() + { + return Data[Position] == 192; + } + + public int DecodeInt() + { + int prefix = ReadByte(); + + switch (prefix) + { + case 0: + throw new RlpException($"Non-canonical integer (leading zero bytes) at position {Position}"); + case < 128: + return prefix; + case 128: + return 0; + } + + int length = prefix - 128; + if (length > 4) + { + throw new RlpException($"Unexpected length of int value: {length}"); + } + + int result = 0; + for (int i = 4; i > 0; i--) + { + result <<= 8; + if (i <= length) + { + result |= Data[Position + length - i]; + if (result == 0) + { + throw new RlpException($"Non-canonical integer (leading zero bytes) at position {Position}"); + } + } + } + + Position += length; + + return result; + } + + public byte[] DecodeByteArray() + { + return Rlp.ByteSpanToArray(DecodeByteArraySpan()); + } + + public ReadOnlySpan DecodeByteArraySpan() + { + int prefix = ReadByte(); + ReadOnlySpan span = RlpStream.SingleBytes; + if ((uint)prefix < (uint)span.Length) + { + return span.Slice(prefix, 1); + } + + if (prefix == 128) + { + return default; + } + + if (prefix <= 183) + { + int length = prefix - 128; + ReadOnlySpan buffer = Read(length); + if (length == 1 && buffer[0] < 128) + { + ThrowUnexpectedValue(buffer[0]); + } + + return buffer; + } + + return DecodeLargerByteArraySpan(prefix); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private ReadOnlySpan DecodeLargerByteArraySpan(int prefix) + { + if (prefix < 192) + { + int lengthOfLength = prefix - 183; + if (lengthOfLength > 4) + { + // strange but needed to pass tests - seems that spec gives int64 length and tests int32 length + ThrowUnexpectedLengthOfLength(); + } + + int length = DeserializeLength(lengthOfLength); + if (length < 56) + { + ThrowUnexpectedLength(length); + } + + return Read(length); + } + + ThrowUnexpectedPrefix(prefix); + return default; + } + + public Memory? DecodeByteArrayMemory() + { + if (!_sliceMemory) + { + return DecodeByteArraySpan().ToArray(); + } + + if (Memory is null) + { + ThrowNotMemoryBacked(); + } + + int prefix = ReadByte(); + + switch (prefix) + { + case < 128: + return Memory.Value.Slice(Position - 1, 1); + case 128: + return Array.Empty(); + case <= 183: + { + int length = prefix - 128; + Memory buffer = ReadSlicedMemory(length); + Span asSpan = buffer.Span; + if (length == 1 && asSpan[0] < 128) + { + ThrowUnexpectedValue(asSpan[0]); + } + + return buffer; + } + case < 192: + { + int lengthOfLength = prefix - 183; + if (lengthOfLength > 4) + { + // strange but needed to pass tests - seems that spec gives int64 length and tests int32 length + ThrowUnexpectedLengthOfLength(); + } + + int length = DeserializeLength(lengthOfLength); + if (length < 56) + { + ThrowUnexpectedLength(length); + } + + return ReadSlicedMemory(length); + } + } + + ThrowUnexpectedPrefix(prefix); + return default; + + [DoesNotReturn] + [StackTraceHidden] + static void ThrowNotMemoryBacked() => throw new RlpException("Rlp not backed by a Memory"); + } + + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowUnexpectedPrefix(int prefix) => throw new RlpException($"Unexpected prefix value of {prefix} when decoding a byte array."); + + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowUnexpectedLength(int length) + { + throw new RlpException($"Expected length greater or equal 56 and was {length}"); + } + + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowUnexpectedValue(int buffer0) => throw new RlpException($"Unexpected byte value {buffer0}"); + + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowUnexpectedLengthOfLength() => throw new RlpException("Expected length of length less or equal 4"); + + public void SkipItem() + { + (int prefix, int content) = PeekPrefixAndContentLength(); + Position += prefix + content; + } + + public void Reset() + { + Position = 0; + } + + public bool DecodeBool() + { + int prefix = ReadByte(); + if (prefix <= 128) + { + return prefix == 1; + } + + if (prefix <= 183) + { + int length = prefix - 128; + if (length == 1 && PeekByte() < 128) + { + throw new RlpException($"Unexpected byte value {PeekByte()}"); + } + + bool result = PeekByte() == 1; + SkipBytes(length); + return result; + } + + if (prefix < 192) + { + int lengthOfLength = prefix - 183; + if (lengthOfLength > 4) + { + // strange but needed to pass tests - seems that spec gives int64 length and tests int32 length + throw new RlpException("Expected length of length less or equal 4"); + } + + int length = DeserializeLength(lengthOfLength); + if (length < 56) + { + throw new RlpException("Expected length greater or equal 56 and was {length}"); + } + + bool result = PeekByte() == 1; + SkipBytes(length); + return result; + } + + throw new RlpException($"Unexpected prefix of {prefix} when decoding a byte array at position {Position} in the message of length {Length} starting with {Description}"); + } + + private readonly string Description => Data[..Math.Min(Rlp.DebugMessageContentLength, Length)].ToHexString(); + + public readonly byte PeekByte() => Data[Position]; + + private readonly byte PeekByte(int offset) => Data[Position + offset]; + + private void SkipBytes(int length) + { + Position += length; + } + + public string DecodeString() + { + ReadOnlySpan bytes = DecodeByteArraySpan(); + return Encoding.UTF8.GetString(bytes); + } + + public long DecodeLong() + { + int prefix = ReadByte(); + + switch (prefix) + { + case 0: + throw new RlpException($"Non-canonical long (leading zero bytes) at position {Position}"); + case < 128: + return prefix; + case 128: + return 0; + } + + int length = prefix - 128; + if (length > 8) + { + throw new RlpException($"Unexpected length of long value: {length}"); + } + + long result = 0; + for (int i = 8; i > 0; i--) + { + result <<= 8; + if (i <= length) + { + result |= PeekByte(length - i); + if (result == 0) + { + throw new RlpException($"Non-canonical long (leading zero bytes) at position {Position}"); + } + } + } + + SkipBytes(length); + + return result; + } + + public ulong DecodeULong() + { + int prefix = ReadByte(); + + switch (prefix) + { + case 0: + throw new RlpException($"Non-canonical ulong (leading zero bytes) at position {Position}"); + case < 128: + return (ulong)prefix; + case 128: + return 0; + } + + int length = prefix - 128; + if (length > 8) + { + throw new RlpException($"Unexpected length of long value: {length}"); + } + + ulong result = 0ul; + for (int i = 8; i > 0; i--) + { + result <<= 8; + if (i <= length) + { + result |= PeekByte(length - i); + if (result == 0) + { + throw new RlpException($"Non-canonical ulong (leading zero bytes) at position {Position}"); + } + } + } + + SkipBytes(length); + + return result; + } + + internal byte[][] DecodeByteArrays() + { + int length = ReadSequenceLength(); + if (length is 0) + { + return []; + } + + int itemsCount = PeekNumberOfItemsRemaining(Position + length); + byte[][] result = new byte[itemsCount][]; + + for (int i = 0; i < itemsCount; i++) + { + result[i] = DecodeByteArray(); + } + + return result; + } + + public byte DecodeByte() + { + byte byteValue = PeekByte(); + if (byteValue < 128) + { + SkipBytes(1); + return byteValue; + } + + if (byteValue == 128) + { + SkipBytes(1); + return 0; + } + + if (byteValue == 129) + { + SkipBytes(1); + return ReadByte(); + } + + throw new RlpException($"Unexpected value while decoding byte {byteValue}"); + } + + public T[] DecodeArray(IRlpValueDecoder? decoder = null, bool checkPositions = true, + T defaultElement = default) + { + if (decoder is null) + { + decoder = Rlp.GetValueDecoder(); + if (decoder is null) + { + throw new RlpException($"{nameof(Rlp)} does not support length of {nameof(T)}"); + } + } + int positionCheck = ReadSequenceLength() + Position; + int count = PeekNumberOfItemsRemaining(checkPositions ? positionCheck : null); + T[] result = new T[count]; + for (int i = 0; i < result.Length; i++) + { + if (PeekByte() == Rlp.OfEmptySequence[0]) + { + result[i] = defaultElement; + Position++; + } + else + { + result[i] = decoder.Decode(ref this); + } + } + + return result; + } + + public readonly bool IsNextItemEmptyArray() => PeekByte() == Rlp.EmptyArrayByte; +} diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs index 71a11cfee39..faac094d3d3 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs @@ -88,47 +88,47 @@ private ITxDecoder GetDecoder(TxType txType) => ? decoder : throw new RlpException($"Unknown transaction type {txType}") { Data = { { "txType", txType } } }; - public T? Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public T? Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { T transaction = null; - Decode(ref decoderContext, ref transaction, rlpBehaviors); + Decode(ref rlpStream, ref transaction, rlpBehaviors); return transaction; } - public void Decode(ref Rlp.ValueDecoderContext decoderContext, ref T? transaction, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public void Decode(ref RlpValueStream rlpStream, ref T? transaction, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); transaction = null; return; } - int txSequenceStart = decoderContext.Position; - ReadOnlySpan transactionSequence = decoderContext.PeekNextItem(); + int txSequenceStart = rlpStream.Position; + ReadOnlySpan transactionSequence = rlpStream.PeekNextItem(); TxType txType = TxType.Legacy; if (rlpBehaviors.HasFlag(RlpBehaviors.SkipTypedWrapping)) { - if (decoderContext.PeekByte() <= Transaction.MaxTxType) // it is typed transactions + if (rlpStream.PeekByte() <= Transaction.MaxTxType) // it is typed transactions { - txSequenceStart = decoderContext.Position; - transactionSequence = decoderContext.Peek(decoderContext.Length); - txType = (TxType)decoderContext.ReadByte(); + txSequenceStart = rlpStream.Position; + transactionSequence = rlpStream.Peek(rlpStream.Length); + txType = (TxType)rlpStream.ReadByte(); } } else { - if (!decoderContext.IsSequenceNext()) + if (!rlpStream.IsSequenceNext()) { - (_, int contentLength) = decoderContext.ReadPrefixAndContentLength(); - txSequenceStart = decoderContext.Position; - transactionSequence = decoderContext.Peek(contentLength); - txType = (TxType)decoderContext.ReadByte(); + (_, int contentLength) = rlpStream.ReadPrefixAndContentLength(); + txSequenceStart = rlpStream.Position; + transactionSequence = rlpStream.Peek(contentLength); + txType = (TxType)rlpStream.ReadByte(); } } - GetDecoder(txType).Decode(ref Unsafe.As(ref transaction), txSequenceStart, transactionSequence, ref decoderContext, rlpBehaviors); + GetDecoder(txType).Decode(ref Unsafe.As(ref transaction), txSequenceStart, transactionSequence, ref rlpStream, rlpBehaviors); } public Rlp Encode(T item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/AccessListTxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/AccessListTxDecoder.cs index 258f24d4e47..ec72db08295 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/AccessListTxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/AccessListTxDecoder.cs @@ -48,12 +48,12 @@ protected override void DecodePayload(Transaction transaction, RlpStream rlpStre transaction.AccessList = AccessListDecoder.Instance.Decode(rlpStream, rlpBehaviors); } - protected override void DecodePayload(Transaction transaction, ref Rlp.ValueDecoderContext decoderContext, + protected override void DecodePayload(Transaction transaction, ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - transaction.ChainId = decoderContext.DecodeULong(); - base.DecodePayload(transaction, ref decoderContext, rlpBehaviors); - transaction.AccessList = AccessListDecoder.Instance.Decode(ref decoderContext, rlpBehaviors); + transaction.ChainId = rlpStream.DecodeULong(); + base.DecodePayload(transaction, ref rlpStream, rlpBehaviors); + transaction.AccessList = AccessListDecoder.Instance.Decode(ref rlpStream, rlpBehaviors); } protected override void EncodePayload(Transaction transaction, RlpStream stream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/BaseTxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/BaseTxDecoder.cs index a8918382c1d..6b2743d7180 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/BaseTxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/BaseTxDecoder.cs @@ -58,44 +58,44 @@ protected void CalculateHash(Transaction transaction, ReadOnlySpan transac } } - public virtual void Decode(ref Transaction? transaction, int txSequenceStart, ReadOnlySpan transactionSequence, ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public virtual void Decode(ref Transaction? transaction, int txSequenceStart, ReadOnlySpan transactionSequence, ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { transaction ??= _createTransaction(); transaction.Type = txType; - int transactionLength = decoderContext.ReadSequenceLength(); - int lastCheck = decoderContext.Position + transactionLength; + int transactionLength = rlpStream.ReadSequenceLength(); + int lastCheck = rlpStream.Position + transactionLength; - DecodePayload(transaction, ref decoderContext, rlpBehaviors); + DecodePayload(transaction, ref rlpStream, rlpBehaviors); - if (decoderContext.Position < lastCheck) + if (rlpStream.Position < lastCheck) { - transaction.Signature = DecodeSignature(transaction, ref decoderContext, rlpBehaviors); + transaction.Signature = DecodeSignature(transaction, ref rlpStream, rlpBehaviors); } if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) == 0) { - decoderContext.Check(lastCheck); + rlpStream.Check(lastCheck); } if ((rlpBehaviors & RlpBehaviors.ExcludeHashes) == 0) { - CalculateHash(transaction, txSequenceStart, transactionSequence, ref decoderContext); + CalculateHash(transaction, txSequenceStart, transactionSequence, ref rlpStream); } } - protected void CalculateHash(Transaction transaction, int txSequenceStart, ReadOnlySpan transactionSequence, ref Rlp.ValueDecoderContext decoderContext) + protected void CalculateHash(Transaction transaction, int txSequenceStart, ReadOnlySpan transactionSequence, ref RlpValueStream rlpStream) { if (transactionSequence.Length <= MaxDelayedHashTxnSize) { // Delay hash generation, as may be filtered as having too low gas etc - if (decoderContext.ShouldSliceMemory) + if (rlpStream.ShouldSliceMemory) { // Do not copy the memory in this case. - int currentPosition = decoderContext.Position; - decoderContext.Position = txSequenceStart; - transaction.SetPreHashMemoryNoLock(decoderContext.ReadMemory(transactionSequence.Length)); - decoderContext.Position = currentPosition; + int currentPosition = rlpStream.Position; + rlpStream.Position = txSequenceStart; + transaction.SetPreHashMemoryNoLock(rlpStream.ReadMemory(transactionSequence.Length)); + rlpStream.Position = currentPosition; } else { @@ -140,19 +140,19 @@ protected virtual void DecodeGasPrice(Transaction transaction, RlpStream rlpStre transaction.GasPrice = rlpStream.DecodeUInt256(); } - protected virtual void DecodePayload(Transaction transaction, ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + protected virtual void DecodePayload(Transaction transaction, ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - transaction.Nonce = decoderContext.DecodeUInt256(); - DecodeGasPrice(transaction, ref decoderContext); - transaction.GasLimit = decoderContext.DecodeLong(); - transaction.To = decoderContext.DecodeAddress(); - transaction.Value = decoderContext.DecodeUInt256(); - transaction.Data = decoderContext.DecodeByteArrayMemory(); + transaction.Nonce = rlpStream.DecodeUInt256(); + DecodeGasPrice(transaction, ref rlpStream); + transaction.GasLimit = rlpStream.DecodeLong(); + transaction.To = rlpStream.DecodeAddress(); + transaction.Value = rlpStream.DecodeUInt256(); + transaction.Data = rlpStream.DecodeByteArrayMemory(); } - protected virtual void DecodeGasPrice(Transaction transaction, ref Rlp.ValueDecoderContext decoderContext) + protected virtual void DecodeGasPrice(Transaction transaction, ref RlpValueStream rlpStream) { - transaction.GasPrice = decoderContext.DecodeUInt256(); + transaction.GasPrice = rlpStream.DecodeUInt256(); } protected Signature? DecodeSignature(Transaction transaction, RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) @@ -163,11 +163,11 @@ protected virtual void DecodeGasPrice(Transaction transaction, ref Rlp.ValueDeco return DecodeSignature(v, rBytes, sBytes, transaction.Signature, rlpBehaviors); } - protected Signature? DecodeSignature(Transaction transaction, ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + protected Signature? DecodeSignature(Transaction transaction, ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - ulong v = decoderContext.DecodeULong(); - ReadOnlySpan rBytes = decoderContext.DecodeByteArraySpan(); - ReadOnlySpan sBytes = decoderContext.DecodeByteArraySpan(); + ulong v = rlpStream.DecodeULong(); + ReadOnlySpan rBytes = rlpStream.DecodeByteArraySpan(); + ReadOnlySpan sBytes = rlpStream.DecodeByteArraySpan(); return DecodeSignature(v, rBytes, sBytes, transaction.Signature, rlpBehaviors); } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/BlobTxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/BlobTxDecoder.cs index 5fe1688f170..33c4f5460db 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/BlobTxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/BlobTxDecoder.cs @@ -49,29 +49,29 @@ public sealed class BlobTxDecoder(Func? transactionFactory = null) } public override void Decode(ref Transaction? transaction, int txSequenceStart, ReadOnlySpan transactionSequence, - ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { int networkWrapperCheck = 0; if (rlpBehaviors.HasFlag(RlpBehaviors.InMempoolForm)) { - int networkWrapperLength = decoderContext.ReadSequenceLength(); - networkWrapperCheck = decoderContext.Position + networkWrapperLength; - int rlpRength = decoderContext.PeekNextRlpLength(); - txSequenceStart = decoderContext.Position; - transactionSequence = decoderContext.Peek(rlpRength); + int networkWrapperLength = rlpStream.ReadSequenceLength(); + networkWrapperCheck = rlpStream.Position + networkWrapperLength; + int rlpRength = rlpStream.PeekNextRlpLength(); + txSequenceStart = rlpStream.Position; + transactionSequence = rlpStream.Peek(rlpRength); } - base.Decode(ref transaction, txSequenceStart, transactionSequence, ref decoderContext, rlpBehaviors | RlpBehaviors.ExcludeHashes); + base.Decode(ref transaction, txSequenceStart, transactionSequence, ref rlpStream, rlpBehaviors | RlpBehaviors.ExcludeHashes); if (transaction is not null) { if (rlpBehaviors.HasFlag(RlpBehaviors.InMempoolForm)) { - DecodeShardBlobNetworkWrapper(transaction, ref decoderContext); + DecodeShardBlobNetworkWrapper(transaction, ref rlpStream); if ((rlpBehaviors & RlpBehaviors.AllowExtraBytes) == 0) { - decoderContext.Check(networkWrapperCheck); + rlpStream.Check(networkWrapperCheck); } if ((rlpBehaviors & RlpBehaviors.ExcludeHashes) == 0) @@ -81,7 +81,7 @@ public override void Decode(ref Transaction? transaction, int txSequenceStart, R } else if ((rlpBehaviors & RlpBehaviors.ExcludeHashes) == 0) { - CalculateHash(transaction, txSequenceStart, transactionSequence, ref decoderContext); + CalculateHash(transaction, txSequenceStart, transactionSequence, ref rlpStream); } } } @@ -121,12 +121,12 @@ protected override void DecodePayload(Transaction transaction, RlpStream rlpStre transaction.BlobVersionedHashes = rlpStream.DecodeByteArrays(); } - protected override void DecodePayload(Transaction transaction, ref Rlp.ValueDecoderContext decoderContext, + protected override void DecodePayload(Transaction transaction, ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - base.DecodePayload(transaction, ref decoderContext, rlpBehaviors); - transaction.MaxFeePerBlobGas = decoderContext.DecodeUInt256(); - transaction.BlobVersionedHashes = decoderContext.DecodeByteArrays(); + base.DecodePayload(transaction, ref rlpStream, rlpBehaviors); + transaction.MaxFeePerBlobGas = rlpStream.DecodeUInt256(); + transaction.BlobVersionedHashes = rlpStream.DecodeByteArrays(); } protected override void EncodePayload(Transaction transaction, RlpStream stream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) @@ -144,11 +144,11 @@ private static void DecodeShardBlobNetworkWrapper(Transaction transaction, RlpSt transaction.NetworkWrapper = new ShardBlobNetworkWrapper(blobs, commitments, proofs); } - private static void DecodeShardBlobNetworkWrapper(Transaction transaction, ref Rlp.ValueDecoderContext decoderContext) + private static void DecodeShardBlobNetworkWrapper(Transaction transaction, ref RlpValueStream rlpStream) { - byte[][] blobs = decoderContext.DecodeByteArrays(); - byte[][] commitments = decoderContext.DecodeByteArrays(); - byte[][] proofs = decoderContext.DecodeByteArrays(); + byte[][] blobs = rlpStream.DecodeByteArrays(); + byte[][] commitments = rlpStream.DecodeByteArrays(); + byte[][] proofs = rlpStream.DecodeByteArrays(); transaction.NetworkWrapper = new ShardBlobNetworkWrapper(blobs, commitments, proofs); } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/EIP1559TxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/EIP1559TxDecoder.cs index 34d29e1c374..874f184e08b 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/EIP1559TxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/EIP1559TxDecoder.cs @@ -15,10 +15,10 @@ protected override void DecodeGasPrice(Transaction transaction, RlpStream rlpStr transaction.DecodedMaxFeePerGas = rlpStream.DecodeUInt256(); } - protected override void DecodeGasPrice(Transaction transaction, ref Rlp.ValueDecoderContext decoderContext) + protected override void DecodeGasPrice(Transaction transaction, ref RlpValueStream rlpStream) { - base.DecodeGasPrice(transaction, ref decoderContext); - transaction.DecodedMaxFeePerGas = decoderContext.DecodeUInt256(); + base.DecodeGasPrice(transaction, ref rlpStream); + transaction.DecodedMaxFeePerGas = rlpStream.DecodeUInt256(); } protected override void EncodeGasPrice(Transaction transaction, RlpStream stream) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/ITxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/ITxDecoder.cs index 07a16c24951..a6e044f1637 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/ITxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/ITxDecoder.cs @@ -12,7 +12,7 @@ public interface ITxDecoder public Transaction? Decode(Span transactionSequence, RlpStream rlpStream, RlpBehaviors rlpBehaviors); - public void Decode(ref Transaction? transaction, int txSequenceStart, ReadOnlySpan transactionSequence, ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None); + public void Decode(ref Transaction? transaction, int txSequenceStart, ReadOnlySpan transactionSequence, ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None); public void Encode(Transaction transaction, RlpStream stream, RlpBehaviors rlpBehaviors = RlpBehaviors.None, bool forSigning = false, bool isEip155Enabled = false, ulong chainId = 0); diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/SetCodeTxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/SetCodeTxDecoder.cs index 3b121bffcbe..749b564e179 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/SetCodeTxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoders/SetCodeTxDecoder.cs @@ -17,11 +17,11 @@ protected override void DecodePayload(Transaction transaction, RlpStream rlpStre transaction.AuthorizationList = rlpStream.DecodeArray((s) => _authTupleDecoder.Decode(s, rlpBehaviors)); } - protected override void DecodePayload(Transaction transaction, ref Rlp.ValueDecoderContext decoderContext, + protected override void DecodePayload(Transaction transaction, ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - base.DecodePayload(transaction, ref decoderContext, rlpBehaviors); - transaction.AuthorizationList = decoderContext.DecodeArray(_authTupleDecoder); + base.DecodePayload(transaction, ref rlpStream, rlpBehaviors); + transaction.AuthorizationList = rlpStream.DecodeArray(_authTupleDecoder); } protected override void EncodePayload(Transaction transaction, RlpStream stream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/WithdrawalDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/WithdrawalDecoder.cs index 6ddd0e6a600..83f6689adc4 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/WithdrawalDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/WithdrawalDecoder.cs @@ -27,23 +27,23 @@ public class WithdrawalDecoder : IRlpStreamDecoder, IRlpValueDecoder }; } - public Withdrawal? Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public Withdrawal? Decode(ref RlpValueStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - if (decoderContext.IsNextItemNull()) + if (rlpStream.IsNextItemNull()) { - decoderContext.ReadByte(); + rlpStream.ReadByte(); return null; } - decoderContext.ReadSequenceLength(); + rlpStream.ReadSequenceLength(); return new() { - Index = decoderContext.DecodeULong(), - ValidatorIndex = decoderContext.DecodeULong(), - Address = decoderContext.DecodeAddress(), - AmountInGwei = decoderContext.DecodeULong() + Index = rlpStream.DecodeULong(), + ValidatorIndex = rlpStream.DecodeULong(), + Address = rlpStream.DecodeAddress(), + AmountInGwei = rlpStream.DecodeULong() }; } diff --git a/src/Nethermind/Nethermind.State/StateTree.cs b/src/Nethermind/Nethermind.State/StateTree.cs index 19cc6ca2a96..22d2f9b652d 100644 --- a/src/Nethermind/Nethermind.State/StateTree.cs +++ b/src/Nethermind/Nethermind.State/StateTree.cs @@ -50,7 +50,7 @@ public StateTree(ITrieStore? store, ILogManager? logManager) public bool TryGetStruct(Address address, out AccountStruct account, Hash256? rootHash = null) { ReadOnlySpan bytes = Get(KeccakCache.Compute(address.Bytes).BytesAsSpan, rootHash); - Rlp.ValueDecoderContext valueDecoderContext = new Rlp.ValueDecoderContext(bytes); + RlpValueStream valueDecoderContext = new RlpValueStream(bytes); if (bytes.IsEmpty) { account = AccountStruct.TotallyEmpty; diff --git a/src/Nethermind/Nethermind.State/StorageTree.cs b/src/Nethermind/Nethermind.State/StorageTree.cs index ef409101b65..ac7be8af385 100644 --- a/src/Nethermind/Nethermind.State/StorageTree.cs +++ b/src/Nethermind/Nethermind.State/StorageTree.cs @@ -87,7 +87,7 @@ public byte[] GetArray(ReadOnlySpan rawKey, Hash256? rootHash = null) return EmptyBytes; } - Rlp.ValueDecoderContext rlp = value.AsRlpValueContext(); + RlpValueStream rlp = value.AsRlpValueContext(); return rlp.DecodeByteArray(); } diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs index ceaaac37160..01cdf3e19d4 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapServer.cs @@ -280,7 +280,7 @@ public IOwnedReadOnlyList GetByteCodes(IReadOnlyList reque try { ReadOnlySpan bytes = tree.Get(accountPath, rootHash.ToCommitment()); - Rlp.ValueDecoderContext rlpContext = new Rlp.ValueDecoderContext(bytes); + RlpValueStream rlpContext = new RlpValueStream(bytes); return bytes.IsNullOrEmpty() ? null : _decoder.Decode(ref rlpContext); } catch (MissingTrieNodeException) diff --git a/src/Nethermind/Nethermind.Trie/PatriciaTree.cs b/src/Nethermind/Nethermind.Trie/PatriciaTree.cs index dfe0f01319f..e885ac06ce1 100644 --- a/src/Nethermind/Nethermind.Trie/PatriciaTree.cs +++ b/src/Nethermind/Nethermind.Trie/PatriciaTree.cs @@ -1299,7 +1299,7 @@ public void Accept( Hash256 DecodeStorageRoot(Hash256 root, Hash256 address) { ReadOnlySpan bytes = Get(address.Bytes, root); - Rlp.ValueDecoderContext valueContext = bytes.AsRlpValueContext(); + RlpValueStream valueContext = bytes.AsRlpValueContext(); return AccountDecoder.Instance.DecodeStorageRootOnly(ref valueContext); } diff --git a/src/Nethermind/Nethermind.Trie/TreeDumper.cs b/src/Nethermind/Nethermind.Trie/TreeDumper.cs index c2c03cc695e..7992566e17e 100644 --- a/src/Nethermind/Nethermind.Trie/TreeDumper.cs +++ b/src/Nethermind/Nethermind.Trie/TreeDumper.cs @@ -64,7 +64,7 @@ public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnly { string leafDescription = trieVisitContext.IsStorage ? "LEAF " : "ACCOUNT "; _builder.AppendLine($"{GetPrefix(trieVisitContext)}{leafDescription} {Nibbles.FromBytes(node.Key).ToPackedByteArray().ToHexString(false)} -> {KeccakOrRlpStringOfNode(node)}"); - Rlp.ValueDecoderContext valueDecoderContext = new(value); + RlpValueStream valueDecoderContext = new(value); if (!trieVisitContext.IsStorage) { Account account = decoder.Decode(ref valueDecoderContext); diff --git a/src/Nethermind/Nethermind.Trie/TrieNode.cs b/src/Nethermind/Nethermind.Trie/TrieNode.cs index 4dcb530ea89..93a5e58ab90 100644 --- a/src/Nethermind/Nethermind.Trie/TrieNode.cs +++ b/src/Nethermind/Nethermind.Trie/TrieNode.cs @@ -1100,7 +1100,7 @@ private bool TryResolveStorageRoot(ITrieNodeResolver resolver, ref TreePath curr } else if (Value.Length > 64) // if not a storage leaf { - Rlp.ValueDecoderContext valueContext = Value.AsSpan().AsRlpValueContext(); + RlpValueStream valueContext = Value.AsSpan().AsRlpValueContext(); Hash256 storageRootKey = _accountDecoder.DecodeStorageRootOnly(ref valueContext); if (storageRootKey != Nethermind.Core.Crypto.Keccak.EmptyTreeHash) {