diff --git a/src/Nethermind/Chains/eip4844_local.json b/src/Nethermind/Chains/eip4844_local.json
index 5c4844d4f6f..b42da9d106e 100644
--- a/src/Nethermind/Chains/eip4844_local.json
+++ b/src/Nethermind/Chains/eip4844_local.json
@@ -56,7 +56,9 @@
}
},
"timestamp": 0,
- "baseFeePerGas": "0x7"
+ "baseFeePerGas": "0x7",
+ "dataGasUsed": "0x0",
+ "excessDataGas": "0x0"
},
"accounts": {
"0x8A04d14125D0FDCDc742F4A05C051De07232EDa4": {
diff --git a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
index fc6382a4137..fad444b47ce 100644
--- a/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
+++ b/src/Nethermind/Ethereum.Test.Base/GeneralTestBase.cs
@@ -89,8 +89,8 @@ protected EthereumTestResult RunTest(GeneralStateTest test, ITxTracer txTracer)
header.MixHash = test.CurrentRandom;
Stopwatch stopwatch = Stopwatch.StartNew();
- var txValidator = new TxValidator((MainnetSpecProvider.Instance.ChainId));
- var spec = specProvider.GetSpec((ForkActivation)test.CurrentNumber);
+ TxValidator? txValidator = new((MainnetSpecProvider.Instance.ChainId));
+ IReleaseSpec? spec = specProvider.GetSpec((ForkActivation)test.CurrentNumber);
if (test.Transaction.ChainId == null)
test.Transaction.ChainId = MainnetSpecProvider.Instance.ChainId;
bool isValid = txValidator.IsWellFormed(test.Transaction, spec);
diff --git a/src/Nethermind/Nethermind.AuRa.Test/Validators/ContractBasedValidatorTests.cs b/src/Nethermind/Nethermind.AuRa.Test/Validators/ContractBasedValidatorTests.cs
index 5511d9db936..cd20ec0da8a 100644
--- a/src/Nethermind/Nethermind.AuRa.Test/Validators/ContractBasedValidatorTests.cs
+++ b/src/Nethermind/Nethermind.AuRa.Test/Validators/ContractBasedValidatorTests.cs
@@ -7,7 +7,6 @@
using FluentAssertions;
using Nethermind.Abi;
using Nethermind.Blockchain;
-using Nethermind.Blockchain.Find;
using Nethermind.Blockchain.Receipts;
using Nethermind.Consensus;
using Nethermind.Consensus.AuRa;
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs
index 4a3f401c9a8..4b8b6ef14b7 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/BlockProducerBaseTests.cs
@@ -17,7 +17,6 @@
using Nethermind.State;
using NSubstitute;
using NUnit.Framework;
-using NUnit.Framework.Internal.Execution;
namespace Nethermind.Blockchain.Test.Producers
{
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs
index 6d53ca6520d..2bdf521fd74 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs
@@ -151,26 +151,35 @@ public static IEnumerable EnoughShardBlobTransactionsSelectedTestCases
{
get
{
- ProperTransactionsSelectedTestCase maxTransactionsSelected = ProperTransactionsSelectedTestCase.Default;
+ ProperTransactionsSelectedTestCase maxTransactionsSelected = ProperTransactionsSelectedTestCase.Eip1559Default;
+ maxTransactionsSelected.ReleaseSpec = Cancun.Instance;
+ maxTransactionsSelected.BaseFee = 1;
maxTransactionsSelected.Transactions.ForEach(tx =>
{
tx.Type = TxType.Blob;
tx.BlobVersionedHashes = new byte[1][];
+ tx.MaxFeePerDataGas = 1;
});
maxTransactionsSelected.Transactions[1].BlobVersionedHashes =
- new byte[Eip4844Constants.MaxBlobsPerBlock - 1][];
+ new byte[Eip4844Constants.MaxDataGasPerTransaction / Eip4844Constants.DataGasPerBlob - 1][];
maxTransactionsSelected.ExpectedSelectedTransactions.AddRange(
maxTransactionsSelected.Transactions.OrderBy(t => t.Nonce).Take(2));
yield return new TestCaseData(maxTransactionsSelected).SetName("Enough transactions selected");
ProperTransactionsSelectedTestCase enoughTransactionsSelected =
- ProperTransactionsSelectedTestCase.Default;
+ ProperTransactionsSelectedTestCase.Eip1559Default;
+ enoughTransactionsSelected.ReleaseSpec = Cancun.Instance;
+ enoughTransactionsSelected.BaseFee = 1;
+
Transaction[] expectedSelectedTransactions =
enoughTransactionsSelected.Transactions.OrderBy(t => t.Nonce).ToArray();
expectedSelectedTransactions[0].Type = TxType.Blob;
- expectedSelectedTransactions[0].BlobVersionedHashes = new byte[Eip4844Constants.MaxBlobsPerBlock][];
+ expectedSelectedTransactions[0].BlobVersionedHashes =
+ new byte[Eip4844Constants.MaxDataGasPerTransaction / Eip4844Constants.DataGasPerBlob][];
+ expectedSelectedTransactions[0].MaxFeePerDataGas = 1;
expectedSelectedTransactions[1].Type = TxType.Blob;
expectedSelectedTransactions[1].BlobVersionedHashes = new byte[1][];
+ expectedSelectedTransactions[1].MaxFeePerDataGas = 1;
enoughTransactionsSelected.ExpectedSelectedTransactions.AddRange(
expectedSelectedTransactions.Where((tx, index) => index != 1));
yield return new TestCaseData(enoughTransactionsSelected).SetName(
@@ -240,9 +249,13 @@ void SetAccountStates(IEnumerable
missingAddresses)
TxPoolTxSource poolTxSource = new(transactionPool, specProvider,
transactionComparerProvider, LimboLogs.Instance, txFilterPipeline);
-
+ BlockHeaderBuilder parentHeader = Build.A.BlockHeader.WithStateRoot(stateProvider.StateRoot).WithBaseFee(testCase.BaseFee);
+ if (spec.IsEip4844Enabled)
+ {
+ parentHeader = parentHeader.WithExcessDataGas(0);
+ }
IEnumerable selectedTransactions =
- poolTxSource.GetTransactions(Build.A.BlockHeader.WithStateRoot(stateProvider.StateRoot).WithBaseFee(testCase.BaseFee).TestObject,
+ poolTxSource.GetTransactions(parentHeader.TestObject,
testCase.GasLimit);
selectedTransactions.Should()
.BeEquivalentTo(testCase.ExpectedSelectedTransactions, o => o.WithStrictOrdering());
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/ShardBlobBlockValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/ShardBlobBlockValidatorTests.cs
index 7518bf3303c..ad361daadea 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/ShardBlobBlockValidatorTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/ShardBlobBlockValidatorTests.cs
@@ -1,6 +1,9 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System.Collections.Generic;
+using System.Linq;
+using Nethermind.Blockchain.Find;
using Nethermind.Consensus.Validators;
using Nethermind.Core;
using Nethermind.Core.Specs;
@@ -8,50 +11,95 @@
using Nethermind.Logging;
using Nethermind.Specs.Forks;
using Nethermind.Specs.Test;
+using NSubstitute;
using NUnit.Framework;
namespace Nethermind.Blockchain.Test.Validators;
public class ShardBlobBlockValidatorTests
{
- [Test]
- public void Not_null_ExcessDataGas_is_invalid_pre_cancun()
+ [TestCaseSource(nameof(DataGasFieldsPerForkTestCases))]
+ public static bool Data_gas_fields_should_be_set(IReleaseSpec spec, ulong? dataGasUsed, ulong? excessDataGas)
{
- ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, Shanghai.Instance));
- BlockValidator blockValidator = new(Always.Valid, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance);
- bool isValid = blockValidator.ValidateSuggestedBlock(Build.A.Block
- .WithWithdrawalsRoot(TestItem.KeccakA)
- .WithWithdrawals(TestItem.WithdrawalA_1Eth)
- .WithExcessDataGas(1).TestObject);
- Assert.False(isValid);
- }
-
- [Test]
- public void Null_ExcessDataGas_is_invalid_post_cancun()
- {
- ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, Cancun.Instance));
- BlockValidator blockValidator = new(Always.Valid, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance);
- bool isValid = blockValidator.ValidateSuggestedBlock(Build.A.Block
+ ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, spec));
+ HeaderValidator headerValidator = new(Substitute.For(), Always.Valid, specProvider, TestLogManager.Instance);
+ BlockValidator blockValidator = new(Always.Valid, headerValidator, Always.Valid, specProvider, TestLogManager.Instance);
+ return blockValidator.ValidateSuggestedBlock(Build.A.Block
+ .WithDataGasUsed(dataGasUsed)
+ .WithExcessDataGas(excessDataGas)
.WithWithdrawalsRoot(TestItem.KeccakA)
.WithWithdrawals(TestItem.WithdrawalA_1Eth)
+ .WithParent(Build.A.BlockHeader.TestObject)
.TestObject);
- Assert.False(isValid);
}
- [TestCase(0, ExpectedResult = true)]
- [TestCase(Eip4844Constants.MaxBlobsPerBlock - 1, ExpectedResult = true)]
- [TestCase(Eip4844Constants.MaxBlobsPerBlock, ExpectedResult = true)]
- [TestCase(Eip4844Constants.MaxBlobsPerBlock + 1, ExpectedResult = false)]
- public bool Blobs_per_block_count_is_valid(int blobsCount)
+ [TestCase(0ul, ExpectedResult = true)]
+ [TestCase(Eip4844Constants.MaxDataGasPerBlock - Eip4844Constants.DataGasPerBlob, ExpectedResult = true)]
+ [TestCase(Eip4844Constants.MaxDataGasPerBlock, ExpectedResult = true)]
+ [TestCase(Eip4844Constants.MaxDataGasPerBlock + Eip4844Constants.DataGasPerBlob, ExpectedResult = false)]
+ public bool Blobs_per_block_count_is_valid(ulong dataGasUsed)
{
ISpecProvider specProvider = new CustomSpecProvider(((ForkActivation)0, Cancun.Instance));
- BlockValidator blockValidator = new(Always.Valid, Always.Valid, Always.Valid, specProvider, LimboLogs.Instance);
+ BlockValidator blockValidator = new(Always.Valid, Always.Valid, Always.Valid, specProvider, TestLogManager.Instance);
return blockValidator.ValidateSuggestedBlock(
Build.A.Block
.WithWithdrawalsRoot(TestItem.KeccakA)
.WithWithdrawals(TestItem.WithdrawalA_1Eth)
- .WithExcessDataGas(1)
- .WithTransactions(Build.A.Transaction.WithBlobVersionedHashes(blobsCount).TestObject)
+ .WithDataGasUsed(dataGasUsed)
+ .WithExcessDataGas(0)
+ .WithTransactions(Enumerable.Range(0, (int)(dataGasUsed / Eip4844Constants.DataGasPerBlob))
+ .Select(i => Build.A.Transaction.WithType(TxType.Blob)
+ .WithMaxFeePerDataGas(ulong.MaxValue)
+ .WithBlobVersionedHashes(1).TestObject).ToArray())
.TestObject);
}
+
+ public static IEnumerable DataGasFieldsPerForkTestCases
+ {
+ get
+ {
+ yield return new TestCaseData(Shanghai.Instance, null, null)
+ {
+ TestName = "Data gas fields are not set pre-Cancun",
+ ExpectedResult = true
+ };
+ yield return new TestCaseData(Shanghai.Instance, 0ul, null)
+ {
+ TestName = "DataGasUsed is set pre-Cancun",
+ ExpectedResult = false
+ };
+ yield return new TestCaseData(Shanghai.Instance, null, 0ul)
+ {
+ TestName = "ExcessDataGas is set pre-Cancun",
+ ExpectedResult = false
+ };
+ yield return new TestCaseData(Shanghai.Instance, 0ul, 0ul)
+ {
+ TestName = "Data gas fields are set pre-Cancun",
+ ExpectedResult = false
+ };
+
+
+ yield return new TestCaseData(Cancun.Instance, null, null)
+ {
+ TestName = "Data gas fields are not set post-Cancun",
+ ExpectedResult = false
+ };
+ yield return new TestCaseData(Cancun.Instance, 0ul, null)
+ {
+ TestName = "Just DataGasUsed is set post-Cancun",
+ ExpectedResult = false
+ };
+ yield return new TestCaseData(Cancun.Instance, null, 0ul)
+ {
+ TestName = "Just ExcessDataGas is set post-Cancun",
+ ExpectedResult = false
+ };
+ yield return new TestCaseData(Cancun.Instance, 0ul, 0ul)
+ {
+ TestName = "Data gas fields are set post-Cancun",
+ ExpectedResult = true
+ };
+ }
+ }
}
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs
index 4ea1a2998b3..59dca3b99a3 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Validators/TxValidatorTests.cs
@@ -336,7 +336,7 @@ public void ShardBlobTransactions_should_have_destination_set()
.WithChainId(TestBlockchainIds.ChainId)
.SignedAndResolved().TestObject;
- Transaction txtxWithTo = Build.A.Transaction
+ Transaction txWithTo = Build.A.Transaction
.WithType(TxType.Blob)
.WithTimestamp(ulong.MaxValue)
.WithTo(TestItem.AddressA)
@@ -347,7 +347,7 @@ public void ShardBlobTransactions_should_have_destination_set()
.SignedAndResolved().TestObject;
Assert.That(txValidator.IsWellFormed(txWithoutTo, Cancun.Instance), Is.False);
- Assert.That(txValidator.IsWellFormed(txtxWithTo, Cancun.Instance));
+ Assert.That(txValidator.IsWellFormed(txWithTo, Cancun.Instance));
}
[Timeout(Timeout.MaxTestTime)]
@@ -371,7 +371,6 @@ public bool MaxFeePerDataGas_should_be_set_for_blob_tx_only(TxType txType, bool
return txValidator.IsWellFormed(tx, Cancun.Instance);
}
-
[TestCaseSource(nameof(BlobVersionedHashInvalidTestCases))]
[TestCaseSource(nameof(BlobVersionedHashValidTestCases))]
public bool BlobVersionedHash_should_be_correct(byte[] hash)
@@ -407,36 +406,41 @@ private static IEnumerable BlobVersionedHashInvalidTestCases
{
yield return new TestCaseData(null) { TestName = "Null hash", ExpectedResult = false };
yield return new TestCaseData(MakeArray(0)) { TestName = "Empty hash", ExpectedResult = false };
- yield return new TestCaseData(MakeArray(1, 1, 0))
+ yield return new TestCaseData(MakeArray(1, 1))
{
TestName = "Correct version, incorrect length",
ExpectedResult = false
};
- yield return new TestCaseData(MakeArray(31, 1, 0))
+ yield return new TestCaseData(MakeArray(31, 1))
{
TestName = "Correct version, incorrect length",
ExpectedResult = false
};
- yield return new TestCaseData(MakeArray(33, 1, 0))
+ yield return new TestCaseData(MakeArray(33, 1))
{
TestName = "Correct version, incorrect length",
ExpectedResult = false
};
- yield return new TestCaseData(MakeArray(32, 0, 0))
+ yield return new TestCaseData(MakeArray(32, 0))
{
TestName = "Incorrect version, correct length",
ExpectedResult = false
};
- yield return new TestCaseData(MakeArray(32, KzgPolynomialCommitments.KzgBlobHashVersionV1 - 1, 0))
+ yield return new TestCaseData(MakeArray(32, KzgPolynomialCommitments.KzgBlobHashVersionV1 - 1))
{
TestName = "Incorrect version, correct length",
ExpectedResult = false
};
- yield return new TestCaseData(MakeArray(32, KzgPolynomialCommitments.KzgBlobHashVersionV1 + 1, 0))
+ yield return new TestCaseData(MakeArray(32, KzgPolynomialCommitments.KzgBlobHashVersionV1 + 1))
{
TestName = "Incorrect version, correct length",
ExpectedResult = false
};
+ yield return new TestCaseData(MakeArray(32, KzgPolynomialCommitments.KzgBlobHashVersionV1))
+ {
+ TestName = "Correct version, correct length",
+ ExpectedResult = true
+ };
}
}
@@ -494,19 +498,19 @@ static TransactionBuilder MakeTestObject(int blobCount = 1) => Buil
TestName = "More than minimum BlobVersionedHashes",
ExpectedResult = true
};
- yield return new TestCaseData(MakeTestObject(Eip4844Constants.MaxBlobsPerTransaction - 1)
+ yield return new TestCaseData(MakeTestObject((int)(Eip4844Constants.MaxDataGasPerBlock / Eip4844Constants.DataGasPerBlob - 1))
.SignedAndResolved().TestObject)
{
TestName = "Less than maximum BlobVersionedHashes",
ExpectedResult = true
};
- yield return new TestCaseData(MakeTestObject(Eip4844Constants.MaxBlobsPerTransaction)
+ yield return new TestCaseData(MakeTestObject((int)(Eip4844Constants.MaxDataGasPerBlock / Eip4844Constants.DataGasPerBlob))
.SignedAndResolved().TestObject)
{
TestName = "Maximum BlobVersionedHashes",
ExpectedResult = true
};
- yield return new TestCaseData(MakeTestObject(Eip4844Constants.MaxBlobsPerTransaction + 1)
+ yield return new TestCaseData(MakeTestObject((int)(Eip4844Constants.MaxDataGasPerBlock / Eip4844Constants.DataGasPerBlob + 1))
.SignedAndResolved().TestObject)
{
TestName = "Too many BlobVersionedHashes",
diff --git a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs
index 1a8ab589711..b905d8e6a49 100644
--- a/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs
+++ b/src/Nethermind/Nethermind.Clique.Test/CliqueBlockProducerTests.cs
@@ -17,7 +17,6 @@
using Nethermind.Consensus.Rewards;
using Nethermind.Consensus.Transactions;
using Nethermind.Consensus.Validators;
-using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
@@ -37,7 +36,6 @@
using Nethermind.Trie.Pruning;
using Nethermind.TxPool;
using NUnit.Framework;
-using BlockTree = Nethermind.Blockchain.BlockTree;
using Nethermind.Config;
namespace Nethermind.Clique.Test
@@ -123,7 +121,9 @@ public On CreateNode(PrivateKey privateKey, bool withGenesisAlreadyProcessed = f
_genesis.Header.Hash = _genesis.Header.CalculateHash();
_genesis3Validators.Header.Hash = _genesis3Validators.Header.CalculateHash();
- TransactionProcessor transactionProcessor = new(goerliSpecProvider, stateProvider, new VirtualMachine(blockhashProvider, specProvider, nodeLogManager), nodeLogManager);
+ TransactionProcessor transactionProcessor = new(goerliSpecProvider, stateProvider,
+ new VirtualMachine(blockhashProvider, specProvider, nodeLogManager),
+ nodeLogManager);
BlockProcessor blockProcessor = new(
goerliSpecProvider,
Always.Valid,
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionPicker.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionPicker.cs
index f5a2e6bc030..48c14c7c03f 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionPicker.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionPicker.cs
@@ -7,8 +7,6 @@
using Nethermind.Core.Specs;
using Nethermind.Evm;
using Nethermind.Int256;
-using Nethermind.Logging;
-using Nethermind.Specs;
using Nethermind.State;
namespace Nethermind.Consensus.Processing
@@ -92,9 +90,19 @@ private bool HasEnoughFounds(Transaction transaction, in UInt256 senderBalance,
return false;
}
- if (eip1559Enabled && !transaction.IsServiceTransaction && senderBalance < (UInt256)transaction.GasLimit * transaction.MaxFeePerGas + transaction.Value)
+ UInt256 maxFee = 0;
+
+ if (eip1559Enabled && !transaction.IsServiceTransaction && senderBalance < (maxFee = (UInt256)transaction.GasLimit * transaction.MaxFeePerGas + transaction.Value))
+ {
+ e.Set(TxAction.Skip, $"{maxFee} is higher than sender balance ({senderBalance}), MaxFeePerGas: ({transaction.MaxFeePerGas}), GasLimit {transaction.GasLimit}");
+ return false;
+ }
+
+ if (releaseSpec.IsEip4844Enabled && !transaction.IsServiceTransaction && (
+ !DataGasCalculator.TryCalculateDataGasPrice(block.Header, transaction, out UInt256 dataGasPrice) ||
+ senderBalance < (maxFee = (UInt256)transaction.GasLimit * transaction.MaxFeePerGas + dataGasPrice + transaction.Value)))
{
- e.Set(TxAction.Skip, $"MaxFeePerGas ({transaction.MaxFeePerGas}) times GasLimit {transaction.GasLimit} is higher than sender balance ({senderBalance})");
+ e.Set(TxAction.Skip, $"{maxFee} is higher than sender balance ({senderBalance}), MaxFeePerGas: ({transaction.MaxFeePerGas}), GasLimit {transaction.GasLimit}, DataGasPrice: {dataGasPrice}");
return false;
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index dfdecd8f4d0..7ff421dc73c 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Numerics;
using Nethermind.Blockchain;
using Nethermind.Blockchain.Receipts;
@@ -13,11 +14,13 @@
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
using Nethermind.Crypto;
+using Nethermind.Evm;
using Nethermind.Evm.Tracing;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.Specs.Forks;
using Nethermind.State;
+using Metrics = Nethermind.Blockchain.Metrics;
namespace Nethermind.Consensus.Processing;
@@ -221,8 +224,14 @@ protected virtual TxReceipt[] ProcessBlock(
_receiptsTracer.SetOtherTracer(blockTracer);
_receiptsTracer.StartNewBlockTrace(block);
+
TxReceipt[] receipts = _blockTransactionsExecutor.ProcessTransactions(block, options, _receiptsTracer, spec);
+ if (spec.IsEip4844Enabled)
+ {
+ block.Header.DataGasUsed = DataGasCalculator.CalculateDataGas(block.Transactions);
+ }
+
block.Header.ReceiptsRoot = receipts.GetReceiptsRoot(spec, block.ReceiptsRoot);
ApplyMinerRewards(block, blockTracer, spec);
_withdrawalProcessor.ProcessWithdrawals(block, spec);
@@ -258,6 +267,7 @@ private Block PrepareBlockForProcessing(Block suggestedBlock)
bh.GasLimit,
bh.Timestamp,
bh.ExtraData,
+ bh.DataGasUsed,
bh.ExcessDataGas)
{
Bloom = Bloom.Empty,
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs
index f3f54fb7849..d4e5accf15e 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Nethermind.Blockchain;
@@ -12,8 +11,8 @@
using Nethermind.Consensus.Transactions;
using Nethermind.Core;
using Nethermind.Core.Crypto;
-using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
+using Nethermind.Evm;
using Nethermind.Evm.Tracing;
using Nethermind.Int256;
using Nethermind.Logging;
@@ -44,7 +43,7 @@ public abstract class BlockProducerBase : IBlockProducer
private IWorldState StateProvider { get; }
private readonly IGasLimitCalculator _gasLimitCalculator;
private readonly IDifficultyCalculator _difficultyCalculator;
- private readonly ISpecProvider _specProvider;
+ protected readonly ISpecProvider _specProvider;
private readonly ITxSource _txSource;
private readonly IBlockProductionTrigger _trigger;
private bool _isRunning;
@@ -292,7 +291,7 @@ protected virtual BlockHeader PrepareBlockHeader(BlockHeader parent,
_blocksConfig.GetExtraDataBytes())
{
Author = blockAuthor,
- MixHash = payloadAttributes?.PrevRandao
+ MixHash = payloadAttributes?.PrevRandao,
};
UInt256 difficulty = _difficultyCalculator.Calculate(header, parent);
@@ -300,7 +299,9 @@ protected virtual BlockHeader PrepareBlockHeader(BlockHeader parent,
header.TotalDifficulty = parent.TotalDifficulty + difficulty;
if (Logger.IsDebug) Logger.Debug($"Setting total difficulty to {parent.TotalDifficulty} + {difficulty}.");
+
header.BaseFeePerGas = BaseFeeCalculator.Calculate(parent, _specProvider.GetSpec(header));
+
return header;
}
@@ -310,12 +311,6 @@ protected virtual Block PrepareBlock(BlockHeader parent, PayloadAttributes? payl
IEnumerable transactions = GetTransactions(parent);
- if (_specProvider.GetSpec(header).IsEip4844Enabled)
- {
- // TODO: Calculate ExcessDataGas depending on parent ExcessDataGas and number of blobs in txs
- header.ExcessDataGas = 0;
- }
-
return new BlockToProduce(header, transactions, Array.Empty(), payloadAttributes?.Withdrawals);
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/TxPoolTxSource.cs b/src/Nethermind/Nethermind.Consensus/Producers/TxPoolTxSource.cs
index adaccb99e94..ae5ef686772 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/TxPoolTxSource.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/TxPoolTxSource.cs
@@ -11,6 +11,7 @@
using Nethermind.Core.Collections;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
+using Nethermind.Evm;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.TxPool;
@@ -60,6 +61,8 @@ public IEnumerable GetTransactions(BlockHeader parent, long gasLimi
// TODO: removing transactions from TX pool here seems to be a bad practice since they will
// not come back if the block is ignored?
int blobsCounter = 0;
+ UInt256 dataGasPrice = UInt256.Zero;
+
foreach (Transaction tx in transactions)
{
i++;
@@ -74,10 +77,33 @@ public IEnumerable GetTransactions(BlockHeader parent, long gasLimi
bool success = _txFilterPipeline.Execute(tx, parent);
if (!success) continue;
- if (tx.Type == TxType.Blob)
+ if (tx.SupportsBlobs)
{
+ if (dataGasPrice == UInt256.Zero)
+ {
+ ulong? excessDataGas = DataGasCalculator.CalculateExcessDataGas(parent, _specProvider.GetSpec(parent));
+ if (excessDataGas is null)
+ {
+ if (_logger.IsTrace) _logger.Trace($"Declining {tx.ToShortString()}, the specification is not configured to handle shard blob transactions.");
+ continue;
+ }
+ if (!DataGasCalculator.TryCalculateDataGasPricePerUnit(excessDataGas.Value, out dataGasPrice))
+ {
+ if (_logger.IsTrace) _logger.Trace($"Declining {tx.ToShortString()}, failed to calculate data gas price.");
+ continue;
+ }
+ }
+
int txAmountOfBlobs = tx.BlobVersionedHashes?.Length ?? 0;
- if ((blobsCounter + txAmountOfBlobs) > Eip4844Constants.MaxBlobsPerBlock)
+
+ if (dataGasPrice > tx.MaxFeePerDataGas)
+ {
+ if (_logger.IsTrace) _logger.Trace($"Declining {tx.ToShortString()}, data gas fee is too low.");
+ continue;
+ }
+
+ if (DataGasCalculator.CalculateDataGas(blobsCounter + txAmountOfBlobs) >
+ Eip4844Constants.MaxDataGasPerBlock)
{
if (_logger.IsTrace) _logger.Trace($"Declining {tx.ToShortString()}, no more blob space.");
continue;
@@ -97,7 +123,6 @@ public IEnumerable GetTransactions(BlockHeader parent, long gasLimi
}
if (_logger.IsDebug) _logger.Debug($"Potentially selected {selectedTransactions} out of {i} pending transactions checked.");
-
}
protected virtual IEnumerable GetOrderedTransactions(IDictionary pendingTransactions, IComparer comparer) =>
diff --git a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
index 82858e12c3f..5c0bf211ccf 100644
--- a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
+++ b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
@@ -2,11 +2,12 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
-using System.Linq;
using Nethermind.Blockchain;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
+using Nethermind.Evm;
+using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.State.Proofs;
using Nethermind.TxPool;
@@ -54,16 +55,18 @@ public bool Validate(BlockHeader header, bool isUncle)
///
public bool ValidateSuggestedBlock(Block block)
{
- Transaction[] txs = block.Transactions;
IReleaseSpec spec = _specProvider.GetSpec(block.Header);
- for (int i = 0; i < txs.Length; i++)
+ if (!ValidateTransactions(block, spec, out int blobsInBlock, out string error))
{
- if (!_txValidator.IsWellFormed(txs[i], spec))
- {
- if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} Invalid transaction {txs[i].Hash}");
- return false;
- }
+ if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} {error}");
+ return false;
+ }
+
+ if (!ValidateDataGasUsed(block, spec, blobsInBlock, out string dataGasError))
+ {
+ if (_logger.IsDebug) _logger.Debug($"{Invalid(block)} {dataGasError}");
+ return false;
}
if (spec.MaximumUncleCount < block.Uncles.Length)
@@ -100,9 +103,6 @@ public bool ValidateSuggestedBlock(Block block)
if (!ValidateWithdrawals(block, spec, out _))
return false;
- if (!ValidateBlobs(block, spec, out _))
- return false;
-
return true;
}
@@ -142,6 +142,16 @@ public bool ValidateProcessedBlock(Block processedBlock, TxReceipt[] receipts, B
if (_logger.IsError) _logger.Error($"- state root: expected {suggestedBlock.Header.StateRoot}, got {processedBlock.Header.StateRoot}");
}
+ if (processedBlock.Header.DataGasUsed != suggestedBlock.Header.DataGasUsed)
+ {
+ if (_logger.IsError) _logger.Error($"- data gas used: expected {suggestedBlock.Header.DataGasUsed}, got {processedBlock.Header.DataGasUsed}");
+ }
+
+ if (processedBlock.Header.ExcessDataGas != suggestedBlock.Header.ExcessDataGas)
+ {
+ if (_logger.IsError) _logger.Error($"- excess data gas: expected {suggestedBlock.Header.ExcessDataGas}, got {processedBlock.Header.ExcessDataGas}");
+ }
+
for (int i = 0; i < processedBlock.Transactions.Length; i++)
{
if (receipts[i].Error is not null && receipts[i].GasUsed == 0 && receipts[i].Error == "invalid")
@@ -193,32 +203,70 @@ private bool ValidateWithdrawals(Block block, IReleaseSpec spec, out string? err
return true;
}
- private bool ValidateBlobs(Block block, IReleaseSpec spec, out string? error)
+ private bool ValidateTransactions(Block block, IReleaseSpec spec, out int blobsInBlock, out string? error)
{
- if (spec.IsEip4844Enabled && block.ExcessDataGas is null)
+ blobsInBlock = 0;
+
+ UInt256 dataGasPrice = UInt256.Zero;
+
+ Transaction[] transactions = block.Transactions;
+
+ for (int txIndex = 0; txIndex < transactions.Length; txIndex++)
{
- error = "ExcessDataGas field is not set.";
- if (_logger.IsWarn) _logger.Warn(error);
- return false;
+ Transaction transaction = transactions[txIndex];
+
+ if (!_txValidator.IsWellFormed(transaction, spec))
+ {
+ error = $"{Invalid(block)} Invalid transaction {transaction.Hash}";
+ return false;
+ }
+
+ if (!transaction.SupportsBlobs)
+ {
+ continue;
+ }
+
+ if (dataGasPrice == UInt256.Zero)
+ {
+ if (!DataGasCalculator.TryCalculateDataGasPricePerUnit(block.Header, out dataGasPrice))
+ {
+ error = $"{nameof(dataGasPrice)} overflow.";
+ return false;
+ }
+ }
+
+ if (transaction.MaxFeePerDataGas < dataGasPrice)
+ {
+ error = $"A transaction has unsufficient {nameof(transaction.MaxFeePerDataGas)} to cover current data gas fee: {transaction.MaxFeePerDataGas} < {dataGasPrice}.";
+ return false;
+ }
+
+ blobsInBlock += transaction.BlobVersionedHashes!.Length;
}
- if (!spec.IsEip4844Enabled && block.ExcessDataGas is not null)
+ error = null;
+ return true;
+ }
+
+ private bool ValidateDataGasUsed(Block block, IReleaseSpec spec, in int blobsInBlock, out string? error)
+ {
+ if (!spec.IsEip4844Enabled)
{
- error = "ExcessDataGas field should not have value.";
- if (_logger.IsWarn) _logger.Warn(error);
- return false;
+ error = null;
+ return true;
}
- int? blobsInBlock = 0;
- for (int txIndex = block.Transactions.Length - 1; txIndex >= 0; txIndex--)
+ ulong dataGasUsed = DataGasCalculator.CalculateDataGas(blobsInBlock);
+
+ if (dataGasUsed > Eip4844Constants.MaxDataGasPerBlock)
{
- blobsInBlock += block.Transactions[txIndex].BlobVersionedHashes?.Length ?? 0;
+ error = $"A block cannot have more than {Eip4844Constants.MaxDataGasPerBlock} data gas.";
+ return false;
}
- if (spec.IsEip4844Enabled && blobsInBlock > Eip4844Constants.MaxBlobsPerBlock)
+ if (dataGasUsed != block.Header.DataGasUsed)
{
- error = $"A block cannot contain more than {Eip4844Constants.MaxBlobsPerBlock} blobs.";
- if (_logger.IsWarn) _logger.Warn(error);
+ error = $"{nameof(BlockHeader.DataGasUsed)} declared in the block header does not match actual data gas used: {block.Header.DataGasUsed} != {dataGasUsed}.";
return false;
}
diff --git a/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs
index ee708ce6aff..66d77ad4694 100644
--- a/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs
+++ b/src/Nethermind/Nethermind.Consensus/Validators/HeaderValidator.cs
@@ -2,15 +2,13 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
-using System.Collections.Generic;
-using System.Linq;
using Nethermind.Blockchain;
using Nethermind.Blockchain.Find;
using Nethermind.Core;
-using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Crypto;
+using Nethermind.Evm;
using Nethermind.Int256;
using Nethermind.Logging;
@@ -123,6 +121,8 @@ public virtual bool Validate(BlockHeader header, BlockHeader? parent, bool isUnc
}
}
+ bool eip4844Valid = ValidateDataGasFields(header, parent, spec);
+
return
totalDifficultyCorrect &&
gasUsedBelowLimit &&
@@ -133,7 +133,8 @@ public virtual bool Validate(BlockHeader header, BlockHeader? parent, bool isUnc
numberIsParentPlusOne &&
hashAsExpected &&
extraDataValid &&
- eip1559Valid;
+ eip1559Valid &&
+ eip4844Valid;
}
private bool ValidateFieldLimit(BlockHeader blockHeader)
@@ -277,5 +278,46 @@ private bool ValidateGenesis(BlockHeader header)
header.Bloom is not null &&
header.ExtraData.Length <= _specProvider.GenesisSpec.MaximumExtraDataSize;
}
+
+ private bool ValidateDataGasFields(BlockHeader header, BlockHeader parentHeader, IReleaseSpec spec)
+ {
+ if (!spec.IsEip4844Enabled)
+ {
+ if (header.DataGasUsed is not null)
+ {
+ if (_logger.IsWarn) _logger.Warn($"DataGasUsed field should not have value.");
+ return false;
+ }
+
+ if (header.ExcessDataGas is not null)
+ {
+ if (_logger.IsWarn) _logger.Warn($"ExcessDataGas field should not have value.");
+ return false;
+ }
+
+ return true;
+ }
+
+ if (header.DataGasUsed is null)
+ {
+ if (_logger.IsWarn) _logger.Warn($"DataGasUsed field is not set.");
+ return false;
+ }
+
+ if (header.ExcessDataGas is null)
+ {
+ if (_logger.IsWarn) _logger.Warn($"ExcessDataGas field is not set.");
+ return false;
+ }
+
+ UInt256? expectedExcessDataGas = DataGasCalculator.CalculateExcessDataGas(parentHeader, spec);
+
+ if (header.ExcessDataGas != expectedExcessDataGas)
+ {
+ if (_logger.IsWarn) _logger.Warn($"ExcessDataGas field is incorrect: {header.ExcessDataGas}, should be {expectedExcessDataGas}.");
+ return false;
+ }
+ return true;
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs
index 14904972294..21fd0dcc1c0 100644
--- a/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs
+++ b/src/Nethermind/Nethermind.Consensus/Validators/TxValidator.cs
@@ -119,7 +119,7 @@ transaction.BlobVersionedHashes is null &&
if (transaction.To is null ||
transaction.MaxFeePerDataGas is null ||
transaction.BlobVersionedHashes is null ||
- transaction.BlobVersionedHashes!.Length > Eip4844Constants.MaxBlobsPerTransaction ||
+ DataGasCalculator.CalculateDataGas(transaction.BlobVersionedHashes!.Length) > Eip4844Constants.MaxDataGasPerTransaction ||
transaction.BlobVersionedHashes!.Length < Eip4844Constants.MinBlobsPerTransaction)
{
return false;
diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs
index 28ab3ba80fa..59ab6390e1e 100644
--- a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestBlockchain.cs
@@ -293,11 +293,17 @@ protected virtual Block GetGenesisBlock()
}
genesisBlockBuilder.WithStateRoot(State.StateRoot);
- if (SealEngineType == Nethermind.Core.SealEngineType.AuRa)
+ if (SealEngineType == Core.SealEngineType.AuRa)
{
genesisBlockBuilder.WithAura(0, new byte[65]);
}
+ if (SpecProvider.GenesisSpec.IsEip4844Enabled)
+ {
+ genesisBlockBuilder.WithDataGasUsed(0);
+ genesisBlockBuilder.WithExcessDataGas(0);
+ }
+
return genesisBlockBuilder.TestObject;
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
index f25730883f4..c26ac138b54 100644
--- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System;
using System.Collections.Generic;
using System.Linq;
using Nethermind.Core.Crypto;
@@ -56,7 +57,13 @@ public BlockBuilder WithTimestamp(ulong timestamp)
return this;
}
- public BlockBuilder WithExcessDataGas(UInt256 excessDataGas)
+ public BlockBuilder WithDataGasUsed(ulong? dataGasUsed)
+ {
+ TestObjectInternal.Header.DataGasUsed = dataGasUsed;
+ return this;
+ }
+
+ public BlockBuilder WithExcessDataGas(ulong? excessDataGas)
{
TestObjectInternal.Header.ExcessDataGas = excessDataGas;
return this;
@@ -159,6 +166,7 @@ public BlockBuilder WithParent(BlockHeader blockHeader)
TestObjectInternal.Header.Number = blockHeader?.Number + 1 ?? 0;
TestObjectInternal.Header.Timestamp = blockHeader?.Timestamp + 1 ?? 0;
TestObjectInternal.Header.ParentHash = blockHeader is null ? Keccak.Zero : blockHeader.Hash;
+ TestObjectInternal.Header.MaybeParent = blockHeader is null ? null : new WeakReference(blockHeader);
return this;
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockHeaderBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockHeaderBuilder.cs
index 3b301cf9f1a..dfc12b82659 100644
--- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockHeaderBuilder.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockHeaderBuilder.cs
@@ -30,8 +30,7 @@ public BlockHeaderBuilder()
DefaultDifficulty, 0,
4_000_000,
1_000_000,
- new byte[] { 1, 2, 3 },
- null);
+ new byte[] { 1, 2, 3 });
TestObjectInternal.Bloom = Bloom.Empty;
TestObjectInternal.MixHash = Keccak.Compute("mix_hash");
TestObjectInternal.Nonce = 1000;
@@ -179,7 +178,13 @@ public BlockHeaderBuilder WithWithdrawalsRoot(Keccak? root)
return this;
}
- public BlockHeaderBuilder WithExcessDataGas(UInt256? excessDataGas)
+ public BlockHeaderBuilder WithDataGasUsed(ulong? dataGasUsed)
+ {
+ TestObjectInternal.DataGasUsed = dataGasUsed;
+ return this;
+ }
+
+ public BlockHeaderBuilder WithExcessDataGas(ulong? excessDataGas)
{
TestObjectInternal.ExcessDataGas = excessDataGas;
return this;
diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/Build.BlockHeader.cs b/src/Nethermind/Nethermind.Core.Test/Builders/Build.BlockHeader.cs
index 09204ba42a9..2a272f2296c 100644
--- a/src/Nethermind/Nethermind.Core.Test/Builders/Build.BlockHeader.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Builders/Build.BlockHeader.cs
@@ -6,5 +6,6 @@ namespace Nethermind.Core.Test.Builders
public partial class Build
{
public BlockHeaderBuilder BlockHeader => new();
+ public BlockHeader EmptyBlockHeader => BlockHeader.TestObject;
}
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs
index de6326845e3..20ac09f5235 100644
--- a/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs
@@ -56,6 +56,36 @@ public BlockDecoderTests()
.WithUncles(uncles)
.WithWithdrawals(8)
.WithMixHash(Keccak.EmptyTreeHash)
+ .TestObject,
+ Build.A.Block
+ .WithNumber(1)
+ .WithBaseFeePerGas(1)
+ .WithTransactions(transactions)
+ .WithUncles(uncles)
+ .WithWithdrawals(8)
+ .WithDataGasUsed(0)
+ .WithExcessDataGas(0)
+ .WithMixHash(Keccak.EmptyTreeHash)
+ .TestObject,
+ Build.A.Block
+ .WithNumber(1)
+ .WithBaseFeePerGas(1)
+ .WithTransactions(transactions)
+ .WithUncles(uncles)
+ .WithWithdrawals(8)
+ .WithDataGasUsed(0xff)
+ .WithExcessDataGas(0xff)
+ .WithMixHash(Keccak.EmptyTreeHash)
+ .TestObject,
+ Build.A.Block
+ .WithNumber(1)
+ .WithBaseFeePerGas(1)
+ .WithTransactions(transactions)
+ .WithUncles(uncles)
+ .WithWithdrawals(8)
+ .WithDataGasUsed(ulong.MaxValue)
+ .WithExcessDataGas(ulong.MaxValue)
+ .WithMixHash(Keccak.EmptyTreeHash)
.TestObject
};
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs
index efe802ca17a..eb6b1be1130 100644
--- a/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Encoding/HeaderDecoderTests.cs
@@ -128,30 +128,6 @@ public void If_withdrawals_are_null_should_not_encode()
Convert.ToHexString(rlp.Bytes).ToLower().Should().Be("f901f7a0ff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080833d090080830f424083010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e288000000000000000001");
}
- [TestCaseSource(nameof(ExcessDataGasCaseSource))]
- public void Can_encode_decode_with_excessDataGas(UInt256? excessDataGas)
- {
- BlockHeader header = Build.A.BlockHeader
- .WithTimestamp(ulong.MaxValue)
- .WithBaseFee(1)
- .WithWithdrawalsRoot(Keccak.Zero)
- .WithExcessDataGas(excessDataGas).TestObject;
-
- Rlp rlp = Rlp.Encode(header);
- BlockHeader blockHeader = Rlp.Decode(rlp.Bytes.AsSpan());
-
- blockHeader.ExcessDataGas.Should().Be(excessDataGas);
- }
-
- public static IEnumerable ExcessDataGasCaseSource()
- {
- yield return null;
- yield return UInt256.Zero;
- yield return new UInt256(1);
- yield return UInt256.UInt128MaxValue;
- yield return UInt256.MaxValue;
- }
-
[TestCase(-1)]
[TestCase(long.MinValue)]
public void Can_encode_decode_with_negative_long_fields(long negativeLong)
@@ -185,4 +161,30 @@ public void Can_encode_decode_with_negative_long_when_using_span(long negativeLo
blockHeader.Number.Should().Be(negativeLong);
blockHeader.GasLimit.Should().Be(negativeLong);
}
+
+ [TestCaseSource(nameof(ExcessDataGasCaseSource))]
+ public void Can_encode_decode_with_excessDataGas(ulong? dataGasUsed, ulong? excessDataGas)
+ {
+ BlockHeader header = Build.A.BlockHeader
+ .WithTimestamp(ulong.MaxValue)
+ .WithBaseFee(1)
+ .WithWithdrawalsRoot(Keccak.Zero)
+ .WithDataGasUsed(dataGasUsed)
+ .WithExcessDataGas(excessDataGas).TestObject;
+
+ Rlp rlp = Rlp.Encode(header);
+ BlockHeader blockHeader = Rlp.Decode(rlp.Bytes.AsSpan());
+
+ blockHeader.DataGasUsed.Should().Be(dataGasUsed);
+ blockHeader.ExcessDataGas.Should().Be(excessDataGas);
+ }
+
+ public static IEnumerable