Skip to content

Commit 924ab37

Browse files
emlautarom1brbrr
authored andcommitted
OP Holocene - Proper EIP-1559 parameters handling (#7926)
1 parent 2b75a75 commit 924ab37

7 files changed

+78
-62
lines changed

src/Nethermind/Nethermind.Optimism.Test/OptimismHeaderValidatorTests.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ public class OptimismHeaderValidatorTests
2323
private static IEnumerable<(string, bool)> EIP1559ParametersExtraData()
2424
{
2525
// Valid
26-
yield return ("0x000000000000000000", true);
2726
yield return ("0x000000000100000000", true);
2827
yield return ("0x0000000001000001bc", true);
2928
yield return ("0x0000000001ffffffff", true);
@@ -35,7 +34,9 @@ public class OptimismHeaderValidatorTests
3534
yield return ("0xffffaaaa", false);
3635
yield return ("0x01ffffffff00000000", false);
3736
yield return ("0xff0000000100000001", false);
37+
yield return ("0x000000000000000000", false);
3838
yield return ("0x000000000000000001", false);
39+
yield return ("0x00ffffffff000001bc00", false);
3940
}
4041

4142
[TestCaseSource(nameof(EIP1559ParametersExtraData))]
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,54 @@
11
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
22
// SPDX-License-Identifier: LGPL-3.0-only
33

4-
using Nethermind.Core.Test.Builders;
5-
using NUnit.Framework;
6-
using FluentAssertions;
4+
using System.Threading.Tasks;
5+
using System.Collections.Generic;
76
using System;
7+
using NUnit.Framework;
88
using NSubstitute;
9-
using Nethermind.Core.Specs;
9+
using Nethermind.State;
10+
using Nethermind.Optimism.Rpc;
1011
using Nethermind.Merge.Plugin.BlockProduction;
11-
using Nethermind.Core.Timers;
1212
using Nethermind.Logging;
13-
using Nethermind.Optimism.Rpc;
13+
using Nethermind.Int256;
14+
using Nethermind.Evm.Tracing;
15+
using Nethermind.Core.Timers;
16+
using Nethermind.Core.Test.Builders;
17+
using Nethermind.Core.Specs;
18+
using Nethermind.Core.Crypto;
19+
using Nethermind.Core;
1420
using Nethermind.Consensus.Transactions;
1521
using Nethermind.Consensus.Processing;
16-
using Nethermind.Blockchain;
17-
using Nethermind.State;
1822
using Nethermind.Consensus;
19-
using Nethermind.Core;
2023
using Nethermind.Config;
21-
using Nethermind.Core.Crypto;
22-
using Nethermind.Evm.Tracing;
23-
using System.Buffers.Binary;
24-
using System.Threading.Tasks;
24+
using Nethermind.Blockchain;
25+
using FluentAssertions;
26+
using Nethermind.Crypto;
2527

2628
namespace Nethermind.Optimism.Test;
2729

2830
[Parallelizable(ParallelScope.All)]
2931
public class OptimismPayloadPreparationServiceTests
3032
{
31-
[TestCase(8u, 2u)]
32-
[TestCase(2u, 2u)]
33-
[TestCase(2u, 10u)]
34-
public async Task Writes_EIP1559Params_Into_HeaderExtraData(UInt32 denominator, UInt32 elasticity)
33+
private static IEnumerable<(OptimismPayloadAttributes, EIP1559Parameters?)> TestCases()
34+
{
35+
foreach (var noTxPool in (bool[])[true, false])
36+
{
37+
yield return (new OptimismPayloadAttributes { EIP1559Params = [0, 0, 0, 8, 0, 0, 0, 2], NoTxPool = noTxPool }, new EIP1559Parameters(0, 8, 2));
38+
yield return (new OptimismPayloadAttributes { EIP1559Params = [0, 0, 0, 2, 0, 0, 0, 2], NoTxPool = noTxPool }, new EIP1559Parameters(0, 2, 2));
39+
yield return (new OptimismPayloadAttributes { EIP1559Params = [0, 0, 0, 2, 0, 0, 0, 10], NoTxPool = noTxPool }, new EIP1559Parameters(0, 2, 10));
40+
yield return (new OptimismPayloadAttributes { EIP1559Params = [0, 0, 0, 0, 0, 0, 0, 0], NoTxPool = noTxPool }, new EIP1559Parameters(0, 250, 6));
41+
}
42+
}
43+
[TestCaseSource(nameof(TestCases))]
44+
public async Task Writes_EIP1559Params_Into_HeaderExtraData((OptimismPayloadAttributes Attributes, EIP1559Parameters? ExpectedEIP1559Parameters) testCase)
3545
{
3646
var parent = Build.A.BlockHeader.TestObject;
3747

3848
var releaseSpec = Substitute.For<IReleaseSpec>();
3949
releaseSpec.IsOpHoloceneEnabled.Returns(true);
50+
releaseSpec.BaseFeeMaxChangeDenominator.Returns((UInt256)250);
51+
releaseSpec.ElasticityMultiplier.Returns(6);
4052
var specProvider = Substitute.For<ISpecProvider>();
4153
specProvider.GetSpec(parent).Returns(releaseSpec);
4254

@@ -69,23 +81,16 @@ public async Task Writes_EIP1559Params_Into_HeaderExtraData(UInt32 denominator,
6981
logManager: TestLogManager.Instance
7082
);
7183

72-
var eip1559Params = new byte[8];
73-
BinaryPrimitives.WriteUInt32BigEndian(eip1559Params.AsSpan(0, 4), denominator);
74-
BinaryPrimitives.WriteUInt32BigEndian(eip1559Params.AsSpan(4, 4), elasticity);
75-
76-
var attributes = new OptimismPayloadAttributes()
77-
{
78-
PrevRandao = Hash256.Zero,
79-
SuggestedFeeRecipient = TestItem.AddressA,
80-
EIP1559Params = eip1559Params,
81-
};
84+
testCase.Attributes.PrevRandao = Hash256.Zero;
85+
testCase.Attributes.SuggestedFeeRecipient = TestItem.AddressA;
8286

83-
var payloadId = service.StartPreparingPayload(parent, attributes);
87+
var payloadId = service.StartPreparingPayload(parent, testCase.Attributes);
8488
var context = await service.GetPayload(payloadId);
8589
var currentBestBlock = context?.CurrentBestBlock!;
8690

8791
currentBestBlock.Should().Be(block);
8892
currentBestBlock.Header.TryDecodeEIP1559Parameters(out var parameters, out _).Should().BeTrue();
89-
parameters.Should().BeEquivalentTo(new EIP1559Parameters(0, denominator, elasticity));
93+
parameters.Should().BeEquivalentTo(testCase.ExpectedEIP1559Parameters);
94+
currentBestBlock.Header.Hash.Should().BeEquivalentTo(currentBestBlock.Header.CalculateHash());
9095
}
9196
}

src/Nethermind/Nethermind.Optimism/OptimismBaseFeeCalculator.cs

+7-13
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,16 @@ public UInt256 Calculate(BlockHeader parent, IEip1559Spec specFor1559)
2323
if (parent.Timestamp >= holoceneTimestamp)
2424
{
2525
// NOTE: This operation should never fail since headers should be valid at this point.
26-
if (!parent.TryDecodeEIP1559Parameters(out EIP1559Parameters eip1559Params, out _))
26+
if (!parent.TryDecodeEIP1559Parameters(out EIP1559Parameters eip1559Params, out var error))
2727
{
28-
throw new InvalidOperationException($"{nameof(BlockHeader)} was not properly validated: missing {nameof(EIP1559Parameters)}");
28+
throw new InvalidOperationException($"{nameof(BlockHeader)} was not properly validated: {error}");
2929
}
3030

31-
spec = eip1559Params.IsZero()
32-
? new OverridableEip1559Spec(specFor1559)
33-
{
34-
ElasticityMultiplier = Eip1559Constants.DefaultElasticityMultiplier,
35-
BaseFeeMaxChangeDenominator = Eip1559Constants.DefaultBaseFeeMaxChangeDenominator
36-
}
37-
: new OverridableEip1559Spec(specFor1559)
38-
{
39-
ElasticityMultiplier = eip1559Params.Elasticity,
40-
BaseFeeMaxChangeDenominator = eip1559Params.Denominator
41-
};
31+
spec = new OverridableEip1559Spec(specFor1559)
32+
{
33+
ElasticityMultiplier = eip1559Params.Elasticity,
34+
BaseFeeMaxChangeDenominator = eip1559Params.Denominator
35+
};
4236
}
4337

4438
return baseFeeCalculator.Calculate(parent, spec);

src/Nethermind/Nethermind.Optimism/OptimismHeaderValidator.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,17 @@ public override bool Validate(BlockHeader header, BlockHeader? parent, bool isUn
4141
IReleaseSpec spec = _specProvider.GetSpec(header);
4242
if (spec.IsOpHoloceneEnabled)
4343
{
44-
if (!header.TryDecodeEIP1559Parameters(out _, out var decodeError))
44+
if (!header.TryDecodeEIP1559Parameters(out var parameters, out var decodeError))
4545
{
4646
error = decodeError;
4747
return false;
4848
}
49+
50+
if (parameters.IsZero())
51+
{
52+
error = $"{nameof(EIP1559Parameters)} is zero";
53+
return false;
54+
}
4955
}
5056

5157
return base.Validate(header, parent, isUncle, out error);

src/Nethermind/Nethermind.Optimism/OptimismPayloadPreparationService.cs

+25-15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Nethermind.Core;
77
using Nethermind.Core.Specs;
88
using Nethermind.Core.Timers;
9+
using Nethermind.Crypto;
910
using Nethermind.Int256;
1011
using Nethermind.Logging;
1112
using Nethermind.Merge.Plugin.BlockProduction;
@@ -45,6 +46,30 @@ public OptimismPayloadPreparationService(
4546
protected override void ImproveBlock(string payloadId, BlockHeader parentHeader,
4647
PayloadAttributes payloadAttributes, Block currentBestBlock, DateTimeOffset startDateTime)
4748
{
49+
if (payloadAttributes is OptimismPayloadAttributes optimismPayload)
50+
{
51+
var spec = _specProvider.GetSpec(currentBestBlock.Header);
52+
if (spec.IsOpHoloceneEnabled)
53+
{
54+
// NOTE: This operation should never fail since headers should be valid at this point.
55+
if (!optimismPayload.TryDecodeEIP1559Parameters(out EIP1559Parameters eip1559Parameters, out var error))
56+
{
57+
throw new InvalidOperationException($"{nameof(BlockHeader)} was not properly validated: {error}");
58+
}
59+
60+
if (eip1559Parameters.IsZero())
61+
{
62+
eip1559Parameters = new EIP1559Parameters(eip1559Parameters.Version, (UInt32)spec.BaseFeeMaxChangeDenominator, (UInt32)spec.ElasticityMultiplier);
63+
}
64+
65+
currentBestBlock.Header.ExtraData = new byte[EIP1559Parameters.ByteLength];
66+
eip1559Parameters.WriteTo(currentBestBlock.Header.ExtraData);
67+
68+
// NOTE: Since we updated the `Header` we need to recalculate the hash.
69+
currentBestBlock.Header.Hash = currentBestBlock.Header.CalculateHash();
70+
}
71+
}
72+
4873
if (payloadAttributes is OptimismPayloadAttributes { NoTxPool: true })
4974
{
5075
if (_logger.IsDebug)
@@ -56,21 +81,6 @@ protected override void ImproveBlock(string payloadId, BlockHeader parentHeader,
5681
}
5782
else
5883
{
59-
if (payloadAttributes is OptimismPayloadAttributes optimismPayload)
60-
{
61-
var spec = _specProvider.GetSpec(currentBestBlock.Header);
62-
if (spec.IsOpHoloceneEnabled)
63-
{
64-
if (!optimismPayload.TryDecodeEIP1559Parameters(out EIP1559Parameters eip1559Parameters, out var error))
65-
{
66-
throw new InvalidOperationException($"{nameof(OptimismPayloadAttributes)} was not properly validated: invalid {nameof(OptimismPayloadAttributes.EIP1559Params)}");
67-
}
68-
69-
currentBestBlock.Header.ExtraData = new byte[EIP1559Parameters.ByteLength];
70-
eip1559Parameters.WriteTo(currentBestBlock.Header.ExtraData);
71-
}
72-
}
73-
7484
base.ImproveBlock(payloadId, parentHeader, payloadAttributes, currentBestBlock, startDateTime);
7585
}
7686
}

src/Nethermind/Nethermind.Optimism/Rpc/OptimismPayloadAttributes.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ public byte[][]? Transactions
3535
/// See <see href="https://specs.optimism.io/protocol/holocene/exec-engine.html#eip-1559-parameters-in-payloadattributesv3"/>
3636
/// </remarks>
3737
public byte[]? EIP1559Params { get; set; }
38-
private const int EIP1559ParamsLength = 8;
3938

4039
private int TransactionsLength => Transactions?.Length ?? 0;
4140

@@ -121,9 +120,9 @@ public override PayloadAttributesValidationResult Validate(ISpecProvider specPro
121120
error = $"{nameof(EIP1559Params)} should be null before Holocene";
122121
return PayloadAttributesValidationResult.InvalidPayloadAttributes;
123122
}
124-
if (releaseSpec.IsOpHoloceneEnabled && EIP1559Params?.Length != EIP1559ParamsLength)
123+
if (releaseSpec.IsOpHoloceneEnabled && !this.TryDecodeEIP1559Parameters(out _, out var decodeError))
125124
{
126-
error = $"{nameof(EIP1559Params)} should be {EIP1559ParamsLength} bytes long";
125+
error = decodeError;
127126
return PayloadAttributesValidationResult.InvalidPayloadAttributes;
128127
}
129128

src/Nethermind/Nethermind.Specs/ChainSpecStyle/ChainSpecLoader.cs

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ bool GetForInnerPathExistence(KeyValuePair<string, JsonElement> o) =>
142142
Eip6780TransitionTimestamp = chainSpecJson.Params.Eip6780TransitionTimestamp,
143143
Rip7212TransitionTimestamp = chainSpecJson.Params.Rip7212TransitionTimestamp,
144144
OpGraniteTransitionTimestamp = chainSpecJson.Params.OpGraniteTransitionTimestamp,
145+
OpHoloceneTransitionTimestamp = chainSpecJson.Params.OpHoloceneTransitionTimestamp,
145146
Eip4788TransitionTimestamp = chainSpecJson.Params.Eip4788TransitionTimestamp,
146147
Eip7702TransitionTimestamp = chainSpecJson.Params.Eip7702TransitionTimestamp,
147148
Eip4788ContractAddress = chainSpecJson.Params.Eip4788ContractAddress ?? Eip4788Constants.BeaconRootsAddress,

0 commit comments

Comments
 (0)