Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add RLP encoding and hashing for Blob txs #5593

Merged
merged 17 commits into from
Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Nethermind/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PackageVersion Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="6.0.5" />
<PackageVersion Include="BenchmarkDotNet" Version="0.13.5" />
<PackageVersion Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.13.5" />
<PackageVersion Include="Ckzg.Bindings" Version="0.1.2.402" />
<PackageVersion Include="Ckzg.Bindings" Version="0.1.2.437" />
<PackageVersion Include="Colorful.Console" Version="1.2.15" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="ConcurrentHashSet" Version="1.3.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,6 @@ public void Transaction_with_init_code_above_max_value_is_rejected_when_eip3860E

[Timeout(Timeout.MaxTestTime)]
[TestCase(TxType.EIP1559, false, ExpectedResult = true)]
[TestCase(TxType.Blob, false, ExpectedResult = false)]
[TestCase(TxType.EIP1559, true, ExpectedResult = false)]
[TestCase(TxType.Blob, true, ExpectedResult = true)]
public bool MaxFeePerDataGas_should_be_set_for_blob_tx_only(TxType txType, bool isMaxFeePerDataGasSet)
Expand Down
17 changes: 2 additions & 15 deletions src/Nethermind/Nethermind.Cli/Console/ColorfulCliConsole.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
// Copyright (c) 2022 Demerzel Solutions Limited
// This file is part of the Nethermind library.
//
// The Nethermind library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The Nethermind library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the Nethermind. If not, see <http://www.gnu.org/licenses/>.
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Drawing;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using Nethermind.Core;
using Nethermind.Int256;

namespace Nethermind.Consensus.Transactions
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using Nethermind.Core;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.TxPool;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System.Collections.Generic;
using Nethermind.Core;
using Nethermind.Int256;

namespace Nethermind.Consensus.Transactions
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Collections.Generic;
using System.Linq;
using Nethermind.Core;
using Nethermind.Int256;

namespace Nethermind.Consensus.Transactions
{
Expand Down
45 changes: 26 additions & 19 deletions src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,12 @@ private bool ValidateSignature(Transaction tx, IReleaseSpec spec)

private static bool Validate4844Fields(Transaction transaction)
{
// Execution-payload version part
if (transaction.Type != TxType.Blob)
// Execution-payload version verification
if (!transaction.SupportsBlobs)
{
return transaction.MaxFeePerDataGas is null &&
transaction.BlobVersionedHashes is null &&
transaction.BlobKzgs is null &&
transaction.Blobs is null &&
transaction.BlobProofs is null;
transaction is not { NetworkWrapper: ShardBlobNetworkWrapper };
}

if (transaction.MaxFeePerDataGas is null ||
Expand All @@ -126,7 +124,9 @@ transaction.BlobVersionedHashes is null ||
return false;
}

for (int i = 0; i < transaction.BlobVersionedHashes!.Length; i++)
int blobCount = transaction.BlobVersionedHashes.Length;

for (int i = 0; i < blobCount; i++)
{
if (transaction.BlobVersionedHashes[i] is null ||
transaction.BlobVersionedHashes![i].Length !=
Expand All @@ -137,32 +137,39 @@ transaction.BlobVersionedHashes is null ||
}
}

// And mempool version part if presents
if (transaction.BlobVersionedHashes!.Length > 0 && (transaction.Blobs is not null ||
transaction.BlobKzgs is not null ||
transaction.BlobProofs is not null))
// Mempool version verification if presents
flcl42 marked this conversation as resolved.
Show resolved Hide resolved
if (transaction.NetworkWrapper is ShardBlobNetworkWrapper wrapper)
{
if (transaction.BlobKzgs is null)
if (wrapper.Blobs.Length != blobCount ||
wrapper.Commitments.Length != blobCount ||
wrapper.Proofs.Length != blobCount)
{
return false;
}

for (int i = 0; i < blobCount; i++)
{
if (wrapper.Blobs[i].Length != Ckzg.Ckzg.BytesPerBlob ||
wrapper.Commitments[i].Length != Ckzg.Ckzg.BytesPerCommitment ||
wrapper.Proofs[i].Length != Ckzg.Ckzg.BytesPerProof)
{
return false;
}
}

Span<byte> hash = stackalloc byte[32];
Span<byte> commitements = transaction.BlobKzgs;
for (int i = 0, n = 0;
i < transaction.BlobVersionedHashes!.Length;
i++, n += Ckzg.Ckzg.BytesPerCommitment)
for (int i = 0; i < blobCount; i++)
{
if (!KzgPolynomialCommitments.TryComputeCommitmentHashV1(
commitements[n..(n + Ckzg.Ckzg.BytesPerCommitment)], hash) ||
!hash.SequenceEqual(transaction.BlobVersionedHashes![i]))
wrapper.Commitments[i].AsSpan(), hash) ||
!hash.SequenceEqual(transaction.BlobVersionedHashes[i]))
{
return false;
}
}

return KzgPolynomialCommitments.AreProofsValid(transaction.Blobs!,
transaction.BlobKzgs!, transaction.BlobProofs!);
return KzgPolynomialCommitments.AreProofsValid(wrapper.Blobs,
wrapper.Commitments, wrapper.Proofs);
}

return true;
Expand Down
27 changes: 27 additions & 0 deletions src/Nethermind/Nethermind.Core.Test/AssertionsSetup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using NUnit.Framework;
using NUnit.Framework.Internal;
using FluentAssertions;
using Nethermind.Core.Extensions;

namespace Nethermind;

[SetUpFixture]
public class AssertionsSetup
{
[OneTimeSetUp]
public void RunBeforeAnyTests()
{
AssertionOptions.AssertEquivalencyUsing(options =>
flcl42 marked this conversation as resolved.
Show resolved Hide resolved
{
options
.Using<Memory<byte>>(context =>
context.Subject.AsArray().Should().BeEquivalentTo(context.Expectation.AsArray()))
.WhenTypeIs<Memory<byte>>();
return options;
});
}
}
20 changes: 20 additions & 0 deletions src/Nethermind/Nethermind.Core.Test/Builders/AccessListBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System.Linq;
using Nethermind.Core.Eip2930;

namespace Nethermind.Core.Test.Builders;
public class TestAccessListBuilder : BuilderBase<AccessList>
{
public TestAccessListBuilder()
{
AccessListBuilder accessListBuilder = new();
foreach (Address address in TestItem.Addresses.Take(5))
{
accessListBuilder.AddAddress(address);
}

TestObjectInternal = accessListBuilder.ToAccessList();
}
}
10 changes: 10 additions & 0 deletions src/Nethermind/Nethermind.Core.Test/Builders/Build.AccessList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

namespace Nethermind.Core.Test.Builders
{
public partial class Build
{
public TestAccessListBuilder AccessList => new();
}
}
29 changes: 18 additions & 11 deletions src/Nethermind/Nethermind.Core.Test/Builders/Build.Transaction.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

namespace Nethermind.Core.Test.Builders
using System.Collections.Generic;
using System.Linq;
using Nethermind.Core.Eip2930;
using Nethermind.Core.Extensions;
using Nethermind.Crypto;
using Nethermind.Int256;
using Nethermind.Logging;

namespace Nethermind.Core.Test.Builders;

public partial class Build
{
public partial class Build
{
public TransactionBuilder<Transaction> Transaction => new();
public TransactionBuilder<SystemTransaction> SystemTransaction => new();
public TransactionBuilder<GeneratedTransaction> GeneratedTransaction => new();
public TransactionBuilder<T> TypedTransaction<T>() where T : Transaction, new() => new();
public TransactionBuilder<Transaction> Transaction => new();
public TransactionBuilder<SystemTransaction> SystemTransaction => new();
public TransactionBuilder<GeneratedTransaction> GeneratedTransaction => new();
public TransactionBuilder<T> TypedTransaction<T>() where T : Transaction, new() => new();

public TransactionBuilder<NamedTransaction> NamedTransaction(string name)
{
return new() { TestObjectInternal = { Name = name } };
}
public TransactionBuilder<NamedTransaction> NamedTransaction(string name)
{
return new() { TestObjectInternal = { Name = name } };
}
}
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Core.Test/Builders/TestItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Nethermind.Core.Test.Builders
{
public static partial class TestItem
{
public static Random Random { get; } = new();
public static Random Random { get; } = new(1337); // 1337 - to make tests predictable, reproducible
private static readonly AccountDecoder _accountDecoder = new();

static TestItem()
Expand Down
72 changes: 40 additions & 32 deletions src/Nethermind/Nethermind.Core.Test/Builders/TransactionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,10 @@ public TransactionBuilder<T> WithBlobVersionedHashes(int? count)
return this;
}

public TransactionBuilder<T> WithBlobs(byte[] blobs)
{
TestObjectInternal.Blobs = blobs;

return this;
}
public TransactionBuilder<T> WithShardBlobTxTypeAndFieldsIfBlobTx(int blobCount = 1, bool isMempoolTx = true)
=> TestObjectInternal.Type == TxType.Blob ? WithShardBlobTxTypeAndFields(blobCount, isMempoolTx) : this;

public TransactionBuilder<T> WithShardBlobTxTypeAndFields(int blobCount)
public TransactionBuilder<T> WithShardBlobTxTypeAndFields(int blobCount = 1, bool isMempoolTx = true)
{
if (blobCount is 0)
{
Expand All @@ -179,34 +175,46 @@ public TransactionBuilder<T> WithShardBlobTxTypeAndFields(int blobCount)

TestObjectInternal.Type = TxType.Blob;
TestObjectInternal.MaxFeePerDataGas ??= 1;
TestObjectInternal.Blobs = new byte[Ckzg.Ckzg.BytesPerBlob * blobCount];
TestObjectInternal.BlobKzgs = new byte[Ckzg.Ckzg.BytesPerCommitment * blobCount];
TestObjectInternal.BlobProofs = new byte[Ckzg.Ckzg.BytesPerProof * blobCount];
TestObjectInternal.BlobVersionedHashes = new byte[blobCount][];
for (int i = 0; i < blobCount; i++)

if (isMempoolTx)
{
TestObjectInternal.BlobVersionedHashes[i] = new byte[32];
TestObjectInternal.Blobs[Ckzg.Ckzg.BytesPerBlob * i] = 1;
KzgPolynomialCommitments.KzgifyBlob(
TestObjectInternal.Blobs.AsSpan(Ckzg.Ckzg.BytesPerBlob * i, Ckzg.Ckzg.BytesPerBlob * (i + 1)),
TestObjectInternal.BlobKzgs.AsSpan(Ckzg.Ckzg.BytesPerCommitment * i, Ckzg.Ckzg.BytesPerCommitment * (i + 1)),
TestObjectInternal.BlobProofs.AsSpan(Ckzg.Ckzg.BytesPerProof * i, Ckzg.Ckzg.BytesPerProof * (i + 1)),
TestObjectInternal.BlobVersionedHashes[i].AsSpan());
TestObjectInternal.BlobVersionedHashes = new byte[blobCount][];
ShardBlobNetworkWrapper wrapper = new(
blobs: new byte[blobCount][],
commitments: new byte[blobCount][],
proofs: new byte[blobCount][]
);

for (int i = 0; i < blobCount; i++)
{
TestObjectInternal.BlobVersionedHashes[i] = new byte[32];
wrapper.Blobs[i] = new byte[Ckzg.Ckzg.BytesPerBlob];
wrapper.Blobs[i][0] = (byte)(i % 256);
wrapper.Commitments[i] = new byte[Ckzg.Ckzg.BytesPerCommitment];
wrapper.Proofs[i] = new byte[Ckzg.Ckzg.BytesPerProof];

if (KzgPolynomialCommitments.IsInitialized)
{
KzgPolynomialCommitments.KzgifyBlob(
wrapper.Blobs[i],
wrapper.Commitments[i],
wrapper.Proofs[i],
TestObjectInternal.BlobVersionedHashes[i].AsSpan());
}
else
{
wrapper.Commitments[i][0] = (byte)(i % 256);
wrapper.Proofs[i][0] = (byte)(i % 256);
}
}

TestObjectInternal.NetworkWrapper = wrapper;
}
else
{
return WithBlobVersionedHashes(blobCount);
}


return this;
}

public TransactionBuilder<T> WithBlobKzgs(byte[] blobKzgs)
{
TestObjectInternal.BlobKzgs = blobKzgs;
return this;
}

public TransactionBuilder<T> WithProofs(byte[] proofs)
{
TestObjectInternal.BlobProofs = proofs;
return this;
}

Expand Down

Large diffs are not rendered by default.

Loading