Skip to content

Commit 6fa1393

Browse files
asdacapkamilchodola
authored andcommitted
Fix KeccaksIterator not working when some keccak zero prefix is not i… (#5780)
* Fix KeccaksIterator not working when some keccak zero prefix is not included. * Fix whitespace * Fix reset * More tests * One more scenario
1 parent 9b69d7b commit 6fa1393

File tree

3 files changed

+121
-3
lines changed

3 files changed

+121
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
2+
// SPDX-License-Identifier: LGPL-3.0-only
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using FluentAssertions;
7+
using Nethermind.Blockchain.Receipts;
8+
using Nethermind.Core.Crypto;
9+
using Nethermind.Core.Extensions;
10+
using Nethermind.Core.Test.Builders;
11+
using Nethermind.Serialization.Rlp;
12+
using NUnit.Framework;
13+
14+
namespace Nethermind.Blockchain.Test.Receipts;
15+
16+
public class KeccaksIteratorTests
17+
{
18+
[TestCaseSource(nameof(TestKeccaks))]
19+
public void TestKeccakIteratorDecodeCorrectly(Keccak[] keccak)
20+
{
21+
Keccak[] keccaks = new[] { TestItem.KeccakA, Keccak.Zero };
22+
Keccak[] decoded = EncodeDecode(keccaks);
23+
decoded.Should().BeEquivalentTo(keccaks);
24+
}
25+
26+
[TestCaseSource(nameof(TestKeccaks))]
27+
public void TestKeccakIteratorDecodedCorrectlyWithReset(Keccak[] keccak)
28+
{
29+
Keccak[] keccaks = new[] { TestItem.KeccakA, Keccak.Zero };
30+
Keccak[] decoded = EncodeDecodeReDecoded(keccaks);
31+
decoded.Should().BeEquivalentTo(keccaks);
32+
}
33+
34+
public static IEnumerable<Keccak[]> TestKeccaks()
35+
{
36+
yield return Array.Empty<Keccak>();
37+
yield return new[] { TestItem.KeccakA };
38+
yield return new[] { Keccak.Zero };
39+
yield return new[] { TestItem.KeccakA, Keccak.Zero };
40+
yield return new[] { Keccak.Zero, TestItem.KeccakA };
41+
yield return new[] { TestItem.KeccakA, TestItem.KeccakB, TestItem.KeccakC, Keccak.Zero, };
42+
yield return new[] { TestItem.KeccakA, new Keccak("0xffffffffffffffffffffffffffffffff00000000000000000000000000000000") };
43+
yield return new[] { TestItem.KeccakA, new Keccak("0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff") };
44+
yield return new[] { TestItem.KeccakA, new Keccak("0xffffffffffffffffffffffffffffffff00000000000000000000000000000000"), TestItem.KeccakB };
45+
yield return new[] { TestItem.KeccakA, new Keccak("0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff"), TestItem.KeccakB };
46+
yield return new[] { new Keccak("0xffffffffffffffffffffffffffffffff00000000000000000000000000000000"), TestItem.KeccakB };
47+
yield return new[] { new Keccak("0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff"), TestItem.KeccakB };
48+
}
49+
50+
private Keccak[] EncodeDecode(Keccak[] input)
51+
{
52+
int totalLength = 0;
53+
foreach (Keccak keccak in input)
54+
{
55+
totalLength += Rlp.LengthOf(keccak.Bytes.WithoutLeadingZerosOrEmpty());
56+
}
57+
int sequenceLength = Rlp.LengthOfSequence(totalLength);
58+
59+
RlpStream rlpStream = new RlpStream(sequenceLength);
60+
rlpStream.StartSequence(totalLength);
61+
foreach (Keccak keccak in input)
62+
{
63+
rlpStream.Encode(keccak.Bytes.WithoutLeadingZerosOrEmpty());
64+
}
65+
66+
Span<byte> buffer = stackalloc byte[32];
67+
KeccaksIterator iterator = new(rlpStream.Data, buffer);
68+
69+
List<Keccak> decoded = new();
70+
while (iterator.TryGetNext(out KeccakStructRef kec))
71+
{
72+
decoded.Add(kec.ToKeccak());
73+
}
74+
75+
return decoded.ToArray();
76+
}
77+
78+
private Keccak[] EncodeDecodeReDecoded(Keccak[] input)
79+
{
80+
int totalLength = 0;
81+
foreach (Keccak keccak in input)
82+
{
83+
totalLength += Rlp.LengthOf(keccak.Bytes.WithoutLeadingZerosOrEmpty());
84+
}
85+
int sequenceLength = Rlp.LengthOfSequence(totalLength);
86+
87+
RlpStream rlpStream = new RlpStream(sequenceLength);
88+
rlpStream.StartSequence(totalLength);
89+
foreach (Keccak keccak in input)
90+
{
91+
rlpStream.Encode(keccak.Bytes.WithoutLeadingZerosOrEmpty());
92+
}
93+
94+
Span<byte> buffer = stackalloc byte[32];
95+
KeccaksIterator iterator = new(rlpStream.Data, buffer);
96+
97+
List<Keccak> decoded = new();
98+
while (iterator.TryGetNext(out KeccakStructRef kec))
99+
{
100+
decoded.Add(kec.ToKeccak());
101+
}
102+
103+
decoded.Clear();
104+
iterator.Reset();
105+
106+
while (iterator.TryGetNext(out KeccakStructRef kec))
107+
{
108+
decoded.Add(kec.ToKeccak());
109+
}
110+
111+
return decoded.ToArray();
112+
}
113+
}

src/Nethermind/Nethermind.Blockchain/Receipts/KeccaksIterator.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace Nethermind.Blockchain.Receipts
1010
public ref struct KeccaksIterator
1111
{
1212
private readonly int _length;
13+
private readonly int _startPosition;
1314
private Rlp.ValueDecoderContext _decoderContext;
1415
private readonly Span<byte> _buffer;
1516
public long Index { get; private set; }
@@ -19,13 +20,14 @@ public KeccaksIterator(Span<byte> data, Span<byte> buffer)
1920
if (buffer.Length != 32) throw new ArgumentException("Buffer must be 32 bytes long");
2021
_decoderContext = new Rlp.ValueDecoderContext(data);
2122
_length = _decoderContext.ReadSequenceLength();
23+
_startPosition = _decoderContext.Position;
2224
_buffer = buffer;
2325
Index = -1;
2426
}
2527

2628
public bool TryGetNext(out KeccakStructRef current)
2729
{
28-
if (_decoderContext.Position < _length)
30+
if (_decoderContext.Position < _length + _startPosition)
2931
{
3032
_decoderContext.DecodeZeroPrefixedKeccakStructRef(out current, _buffer);
3133
Index++;
@@ -40,8 +42,7 @@ public bool TryGetNext(out KeccakStructRef current)
4042

4143
public void Reset()
4244
{
43-
_decoderContext.Position = 0;
44-
_decoderContext.ReadSequenceLength();
45+
_decoderContext.Position = _startPosition;
4546
}
4647
}
4748
}

src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs

+4
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,10 @@ public void DecodeZeroPrefixedKeccakStructRef(out KeccakStructRef keccak, Span<b
889889
else
890890
{
891891
ReadOnlySpan<byte> theSpan = DecodeByteArraySpan();
892+
if (theSpan.Length < 32)
893+
{
894+
buffer[..(32 - theSpan.Length)].Clear();
895+
}
892896
theSpan.CopyTo(buffer[(32 - theSpan.Length)..]);
893897
keccak = new KeccakStructRef(buffer);
894898
}

0 commit comments

Comments
 (0)