Skip to content

Commit

Permalink
Use blob gas instead of count (#6229)
Browse files Browse the repository at this point in the history
* Use blob gas instead of count

* Shuffle 4844 constants, add GetMaxBlobsPerBlock

* Reorder constants again; make 4844 settings testable; add tests
  • Loading branch information
flcl42 committed Oct 31, 2023
1 parent 9c1ca11 commit 3095d01
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 29 deletions.
20 changes: 20 additions & 0 deletions src/Nethermind/Nethermind.Blockchain.Test/TestEip4844Config.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 Nethermind.Core;

namespace Nethermind.Consensus.Producers.Test;

public class TestEip4844Config : IEip4844Config
{
public TestEip4844Config(ulong? maxBlobGasPerBlock = null)
{
MaxBlobGasPerBlock = maxBlobGasPerBlock ?? Eip4844Constants.MaxBlobGasPerBlock;
}

public ulong MaxBlobGasPerBlock { get; }

public ulong GasPerBlob => Eip4844Constants.GasPerBlob;

public int GetMaxBlobsPerBlock() => (int)(MaxBlobGasPerBlock / GasPerBlob);
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ public static IEnumerable Eip1559TestCases
}
}


public static IEnumerable EnoughShardBlobTransactionsSelectedTestCases
{
get
Expand Down
65 changes: 65 additions & 0 deletions src/Nethermind/Nethermind.Blockchain.Test/TxPoolSourceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Consensus.Transactions;
using Nethermind.Logging;
using Nethermind.Specs.Forks;
using Nethermind.TxPool;
using NUnit.Framework;
using Nethermind.Consensus.Comparers;
using Nethermind.Core.Test.Builders;
using Nethermind.Specs;
using Nethermind.Core;
using System.Linq;
using System.Collections.Generic;
using NSubstitute;

namespace Nethermind.Consensus.Producers.Test;

public class TxPoolSourceTests
{
[TestCaseSource(nameof(BlobTransactionsWithBlobGasLimitPerBlock))]
public void GetTransactions_should_respect_customizable_blob_gas_limit(int[] blobCountPerTx, ulong customMaxBlobGasPerBlock)
{
TestSingleReleaseSpecProvider specProvider = new(Cancun.Instance);
TransactionComparerProvider transactionComparerProvider = new(specProvider, Build.A.BlockTree().TestObject);

ITxPool txPool = Substitute.For<ITxPool>();
Dictionary<Address, Transaction[]> transactionsWithBlobs = blobCountPerTx
.Select((blobsCount, index) => (blobCount: blobsCount, index))
.ToDictionary(
pair => new Address((new byte[19]).Concat(new byte[] { (byte)pair.index }).ToArray()),
pair => new Transaction[] { Build.A.Transaction.WithShardBlobTxTypeAndFields(pair.blobCount).TestObject });
txPool.GetPendingTransactions().Returns(new Transaction[0]);
txPool.GetPendingLightBlobTransactionsBySender().Returns(transactionsWithBlobs);

ITxFilterPipeline txFilterPipeline = Substitute.For<ITxFilterPipeline>();
txFilterPipeline.Execute(Arg.Any<Transaction>(), Arg.Any<BlockHeader>()).Returns(true);

TestEip4844Config eip4844Config = new(customMaxBlobGasPerBlock);

TxPoolTxSource transactionSelector = new(txPool, specProvider, transactionComparerProvider, LimboLogs.Instance, txFilterPipeline, eip4844Config);

IEnumerable<Transaction> txs = transactionSelector.GetTransactions(new BlockHeader { }, long.MaxValue);
int blobsCount = txs.Sum(tx => tx.BlobVersionedHashes?.Length ?? 0);

Assert.Multiple(() =>
{
Assert.That((ulong)blobsCount * eip4844Config.GasPerBlob, Is.LessThanOrEqualTo(eip4844Config.MaxBlobGasPerBlock));
Assert.That(blobsCount, Is.LessThanOrEqualTo(eip4844Config.GetMaxBlobsPerBlock()));
});
}

public static IEnumerable<TestCaseData> BlobTransactionsWithBlobGasLimitPerBlock()
{
yield return new TestCaseData(new int[] { 1, 2, 4 }, Eip4844Constants.GasPerBlob * 6);
yield return new TestCaseData(new int[] { 1, 2, 6 }, Eip4844Constants.GasPerBlob * 6);
yield return new TestCaseData(new int[] { 1, 6 }, Eip4844Constants.GasPerBlob * 6);
yield return new TestCaseData(new int[] { 6, 1, 5 }, Eip4844Constants.GasPerBlob * 6);
yield return new TestCaseData(new int[] { 1, 2 }, Eip4844Constants.GasPerBlob * 2);
yield return new TestCaseData(new int[] { 1, 1 }, Eip4844Constants.GasPerBlob * 2);
yield return new TestCaseData(new int[] { 2, 1 }, Eip4844Constants.GasPerBlob * 2);
yield return new TestCaseData(new int[] { 2, 2 }, Eip4844Constants.GasPerBlob * 2);
yield return new TestCaseData(new int[] { 3 }, Eip4844Constants.GasPerBlob * 2);
}
}
22 changes: 12 additions & 10 deletions src/Nethermind/Nethermind.Consensus/Producers/TxPoolTxSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using Nethermind.Consensus.Transactions;
using Nethermind.Core;
using Nethermind.Core.Collections;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Evm;
using Nethermind.Int256;
Expand All @@ -29,19 +28,22 @@ public class TxPoolTxSource : ITxSource
private readonly ITxFilterPipeline _txFilterPipeline;
private readonly ISpecProvider _specProvider;
protected readonly ILogger _logger;
private readonly IEip4844Config _eip4844Config;

public TxPoolTxSource(
ITxPool? transactionPool,
ISpecProvider? specProvider,
ITransactionComparerProvider? transactionComparerProvider,
ILogManager? logManager,
ITxFilterPipeline? txFilterPipeline)
ITxFilterPipeline? txFilterPipeline,
IEip4844Config? eip4844ConstantsProvider = null)
{
_transactionPool = transactionPool ?? throw new ArgumentNullException(nameof(transactionPool));
_transactionComparerProvider = transactionComparerProvider ?? throw new ArgumentNullException(nameof(transactionComparerProvider));
_txFilterPipeline = txFilterPipeline ?? throw new ArgumentNullException(nameof(txFilterPipeline));
_specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider));
_logger = logManager?.GetClassLogger<TxPoolTxSource>() ?? throw new ArgumentNullException(nameof(logManager));
_eip4844Config = eip4844ConstantsProvider ?? ConstantEip4844Config.Instance;
}

public IEnumerable<Transaction> GetTransactions(BlockHeader parent, long gasLimit, PayloadAttributes? payloadAttributes = null)
Expand All @@ -60,7 +62,7 @@ public IEnumerable<Transaction> GetTransactions(BlockHeader parent, long gasLimi

int checkedTransactions = 0;
int selectedTransactions = 0;
using ArrayPoolList<Transaction> selectedBlobTxs = new(Eip4844Constants.MaxBlobsPerBlock);
using ArrayPoolList<Transaction> selectedBlobTxs = new(_eip4844Config.GetMaxBlobsPerBlock());

SelectBlobTransactions(blobTransactions, parent, spec, selectedBlobTxs);

Expand Down Expand Up @@ -121,21 +123,21 @@ private void SelectBlobTransactions(IEnumerable<Transaction> blobTransactions, B
{
int checkedBlobTransactions = 0;
int selectedBlobTransactions = 0;
int blobsCounter = 0;
UInt256 blobGasCounter = 0;
UInt256 blobGasPrice = UInt256.Zero;

foreach (Transaction blobTx in blobTransactions)
{
if (blobsCounter == Eip4844Constants.MaxBlobsPerBlock)
if (blobGasCounter >= _eip4844Config.MaxBlobGasPerBlock)
{
if (_logger.IsTrace) _logger.Trace($"Declining {blobTx.ToShortString()}, no more blob space. Block already have {blobsCounter} which is max value allowed.");
if (_logger.IsTrace) _logger.Trace($"Declining {blobTx.ToShortString()}, no more blob space. Block already have {blobGasCounter} blob gas which is max value allowed.");
break;
}

checkedBlobTransactions++;

int txAmountOfBlobs = blobTx.BlobVersionedHashes?.Length ?? 0;
if (blobsCounter + txAmountOfBlobs > Eip4844Constants.MaxBlobsPerBlock)
ulong txBlobGas = (ulong)(blobTx.BlobVersionedHashes?.Length ?? 0) * _eip4844Config.GasPerBlob;
if (txBlobGas > _eip4844Config.MaxBlobGasPerBlock - blobGasCounter)
{
if (_logger.IsTrace) _logger.Trace($"Declining {blobTx.ToShortString()}, not enough blob space.");
continue;
Expand All @@ -162,8 +164,8 @@ private void SelectBlobTransactions(IEnumerable<Transaction> blobTransactions, B
continue;
}

blobsCounter += txAmountOfBlobs;
if (_logger.IsTrace) _logger.Trace($"Selected shard blob tx {fullBlobTx.ToShortString()} to be potentially included in block, total blobs included: {blobsCounter}.");
blobGasCounter += txBlobGas;
if (_logger.IsTrace) _logger.Trace($"Selected shard blob tx {fullBlobTx.ToShortString()} to be potentially included in block, total blob gas included: {blobGasCounter}.");

selectedBlobTransactions++;
selectedBlobTxs.Add(fullBlobTx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,5 @@ public SinglePendingTxSelector(ITxSource innerSource)
.Take(1);

public override string ToString() => $"{nameof(SinglePendingTxSelector)} [ {_innerSource} ]";

}
}
38 changes: 22 additions & 16 deletions src/Nethermind/Nethermind.Core/Eip4844Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,45 @@ namespace Nethermind.Core;
/// </summary>
public class Eip4844Constants
{
/// <summary>
/// Gets the <c>GAS_PER_BLOB</c> parameter.
/// </summary>
/// <remarks>Defaults to 2e17.</remarks>
public const ulong GasPerBlob = 1 << 17;

public const int MaxBlobsPerBlock = 6;
public const int MinBlobsPerTransaction = 1;

/// <summary>
/// Gets the <c>BLOB_GASPRICE_UPDATE_FRACTION</c> parameter.
/// Gets the <c>GAS_PER_BLOB</c> parameter.
/// </summary>
/// <remarks>Defaults to 3338477.</remarks>
public static UInt256 BlobGasPriceUpdateFraction { get; private set; } = 3338477;
/// <remarks>Defaults to 131072.</remarks>
public const ulong GasPerBlob = 131072;

/// <summary>
/// Gets the <c>MAX_BLOB_GAS_PER_BLOCK</c> parameter.
/// </summary>
/// <remarks>Defaults to 786432.</remarks>
public static ulong MaxBlobGasPerBlock { get; private set; } = GasPerBlob * MaxBlobsPerBlock;

public static ulong MaxBlobGasPerTransaction => MaxBlobGasPerBlock;
public static ulong MaxBlobGasPerBlock { get; private set; } = 786432;

/// <summary>
/// Gets the <c>MIN_BLOB_GASPRICE</c> parameter, in wei.
/// Gets the <c>MAX_BLOB_GAS_PER_BLOCK</c> parameter.
/// </summary>
/// <remarks>Defaults to 1.</remarks>
public static UInt256 MinBlobGasPrice { get; private set; } = 1;
/// <remarks>The same as <see cref="MaxBlobGasPerBlock"/>.</remarks>
public static ulong MaxBlobGasPerTransaction => MaxBlobGasPerBlock;

/// <summary>
/// Gets the <c>TARGET_BLOB_GAS_PER_BLOCK</c> parameter.
/// </summary>
/// <remarks>Defaults to 393216.</remarks>
public static ulong TargetBlobGasPerBlock { get; private set; } = MaxBlobGasPerBlock / 2;

/// <summary>
/// Gets the <c>BLOB_GASPRICE_UPDATE_FRACTION</c> parameter.
/// </summary>
/// <remarks>Defaults to 3338477.</remarks>
public static UInt256 BlobGasPriceUpdateFraction { get; private set; } = 3338477;

/// <summary>
/// Gets the <c>MIN_BLOB_GASPRICE</c> parameter, in wei.
/// </summary>
/// <remarks>Defaults to 1.</remarks>
public static UInt256 MinBlobGasPrice { get; private set; } = 1;


// The parameter mutators are kept separate deliberately to ensure no accidental value changes.
public static void OverrideIfAny(
UInt256? blobGasPriceUpdateFraction = null,
Expand All @@ -64,4 +68,6 @@ public class Eip4844Constants
if (targetBlobGasPerBlock.HasValue)
TargetBlobGasPerBlock = targetBlobGasPerBlock.Value;
}

public static int GetMaxBlobsPerBlock() => (int)(MaxBlobGasPerBlock / GasPerBlob);
}
26 changes: 26 additions & 0 deletions src/Nethermind/Nethermind.Core/IEip4844Config.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

namespace Nethermind.Core;

/// <summary>
/// <see cref="Eip4844Constants" /> wrapper, made for testing convenience.
/// </summary>
public interface IEip4844Config
{
ulong MaxBlobGasPerBlock { get; }
ulong GasPerBlob { get; }
int GetMaxBlobsPerBlock();
}

public class ConstantEip4844Config : IEip4844Config
{
public ulong MaxBlobGasPerBlock => Eip4844Constants.MaxBlobGasPerBlock;
public ulong GasPerBlob => Eip4844Constants.GasPerBlob;
public int GetMaxBlobsPerBlock() => Eip4844Constants.GetMaxBlobsPerBlock();

static ConstantEip4844Config() => Instance = new ConstantEip4844Config();
private ConstantEip4844Config() { }

public static IEip4844Config Instance { get; private set; }
}
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.TxPool/LightTransaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Nethermind.TxPool;
public class LightTransaction : Transaction
{
private static readonly Dictionary<int, byte[][]> _blobVersionedHashesCache =
Enumerable.Range(1, Eip4844Constants.MaxBlobsPerBlock).ToDictionary(i => i, i => new byte[i][]);
Enumerable.Range(1, Eip4844Constants.GetMaxBlobsPerBlock()).ToDictionary(i => i, i => new byte[i][]);


public LightTransaction(Transaction fullTx)
Expand Down

0 comments on commit 3095d01

Please sign in to comment.