-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merkle Node Keccak #104
Merkle Node Keccak #104
Conversation
|
||
namespace Paprika.RLP; | ||
|
||
public static class Rlp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are multiple "magic numbers" in the class. We should extract them into constants and document the reason for their existence (spec, optimization, etc.)
// TODO: If keccak is a known one like `Keccak.OfAnEmptyString` or `Keccak.OfAnEmptySequenceRlp` | ||
// we can cache those `Rlp`s to be reused | ||
|
||
WriteByte(160); | ||
Write(keccak.BytesAsSpan); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimization opportunity by reusing results on known inputs.
{ | ||
new object[] | ||
{ | ||
Values.Key0, Values.Balance0, Values.Nonce0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be super useful if you could provide a link to a branch in NethermindEth maybe where you calculate these. Once they are merged, it will be fine but for now, keeping any kind of link would make the life much easier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had the tests locally, but I'll create a branch with the actual tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've created a branch with the same tests: https://github.com/NethermindEth/nethermind/tree/feature/paprika_merkle_tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you commit this link to the repository? Otherwise it will get lost. Just add it to the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually did that but I forgot to push the changes. Whoops!
- Inline everything
- Internal renaming
Removed all allocations with a little help of |
|
||
namespace Paprika.RLP; | ||
|
||
public readonly ref struct KeccakOrRlp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also tried a different approach that uses a fixed size array instead of a Keccak
:
public ref struct KeccakOrRlp
{
public enum Type : byte
{
Keccak = 0,
Rlp = 1,
}
private unsafe ref struct Buffer
{
private const int Size = 32;
#pragma warning disable CS0649
// Compiler cannot figure out that the fields is being used
private fixed byte _data[Size];
#pragma warning restore CS0649
public Span<byte> AsSpan()
{
fixed (byte* p = _data)
{
return new Span<byte>(p, Size);
}
}
}
public Type DataType { get; }
private Buffer _buffer;
public Span<byte> AsSpan() => _buffer.AsSpan();
private KeccakOrRlp(Type dataType, Buffer buffer)
{
DataType = dataType;
_buffer = buffer;
}
public static KeccakOrRlp FromSpan(scoped Span<byte> data)
{
var buffer = new Buffer();
var output = buffer.AsSpan();
if (data.Length < 32)
{
output[0] = (byte)data.Length;
data.CopyTo(output[1..]);
return new KeccakOrRlp(Type.Rlp, buffer);
}
else
{
KeccakHash.ComputeHash(data, output);
return new KeccakOrRlp(Type.Keccak, buffer);
}
}
}
On benchmarks, this approach is as performant as the Keccak
implementation, while in my opinion being a bit clearer since we're not using a Keccak
as a backing field (which, when we store an Rlp
is not even a Keccak
).
I don't see any extra copies on IL, but I'm not fully sure about that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should work as you describe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use this approach then? Or would you rather stick with the Keccak approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One remark and good to merge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to go!
Compute the
Keccak
orRLP
of Merkle Nodes (Branches, Leaves and Extensions)