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

EIP-7667: Update gas costs #6932

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,11 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec
/// </summary>
bool IsEip6780Enabled { get; }

/// <summary>
/// Raise gas costs of hash functions
/// </summary>
bool IsEip7667Enabled { get; }

/// <summary>
/// Should transactions be validated against chainId.
/// </summary>
Expand Down
223 changes: 223 additions & 0 deletions src/Nethermind/Nethermind.Evm.Test/Eip7667Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
using FluentAssertions;
using Nethermind.Evm.Precompiles;
using Nethermind.Int256;
using Nethermind.Specs;
using NUnit.Framework;

namespace Nethermind.Evm.Test;

public class Eip7667Tests : VirtualMachineTestsBase
{
protected override long BlockNumber => MainnetSpecProvider.ParisBlockNumber;
protected override ulong Timestamp => MainnetSpecProvider.PragueBlockTimestamp;

[Test]
public void Sha3_cost_before_eip_7667()
{
var spec = SpecProvider.GetSpec((BlockNumber, Timestamp - 1));
Assert.That(spec.GetSha3Cost(), Is.EqualTo(30));
}

[Test]
public void Sha3_cost_after_eip_7667()
{
Assert.That(Spec.GetSha3Cost(), Is.EqualTo(300));
}

[Test]
public void Sha3_word_cost_before_eip_7667()
{
var spec = SpecProvider.GetSpec((BlockNumber, Timestamp - 1));
Assert.That(spec.GetSha3WordCost(), Is.EqualTo(6));
}

[Test]
public void Sha3_word_cost_after_eip_7667()
{
Assert.That(Spec.GetSha3WordCost(), Is.EqualTo(60));
}

[Test]
public void Log_data_cost_before_eip_7667()
{
var spec = SpecProvider.GetSpec((BlockNumber, Timestamp - 1));
Assert.That(spec.GetLogDataCost(), Is.EqualTo(8));
}

[Test]
public void Log_data_cost_after_eip_7667()
{
Assert.That(Spec.GetLogDataCost(), Is.EqualTo(10));
}

[Test]
public void Keccak256_op_before_eip_7667()
{
byte[] code = Prepare.EvmCode
.PushData(32)
.PushData(0)
.Op(Instruction.KECCAK256)
.STOP()
.Done;

TestAllTracerWithOutput result = Execute((BlockNumber, Timestamp - 1), code);

long gasSpent = GasCostOf.Transaction + GasCostOf.VeryLow * 2 // for push
+ GasCostOf.VeryLow // memory gas cost
+ GasCostOf.Sha3 + GasCostOf.Sha3Word; // Keccak256

result.StatusCode.Should().Be(1);
Assert.That(result.GasSpent, Is.EqualTo(gasSpent));
}

[Test]
public void Keccak256_op_after_eip_7667()
{
byte[] code = Prepare.EvmCode
.PushData(32)
.PushData(0)
.Op(Instruction.KECCAK256)
.STOP()
.Done;

TestAllTracerWithOutput result = Execute(code);

long gasSpent = GasCostOf.Transaction + GasCostOf.VeryLow * 2 // for push
+ GasCostOf.VeryLow // memory gas cost
+ GasCostOf.Sha3Eip7667 + GasCostOf.Sha3WordEip7667; // Keccak256

result.StatusCode.Should().Be(1);
Assert.That(result.GasSpent, Is.EqualTo(gasSpent));
}

[Test]
public void Create_op_before_eip_7667()
{
byte[] salt = [4, 5, 6];
byte[] deployedCode = [1, 2, 3];
byte[] initCode = Prepare.EvmCode.ForInitOf(deployedCode).Done;
byte[] createCode = Prepare.EvmCode.Create2(initCode, salt, 0).STOP().Done;

TestAllTracerWithOutput result = Execute((BlockNumber, Timestamp - 1), createCode);

long gasSpent = GasCostOf.Sha3Word * EvmPooledMemory.Div32Ceiling((UInt256)initCode.Length) + 53658;

Assert.That(result.GasSpent, Is.EqualTo(gasSpent));
}

[Test]
public void Create_op_after_eip_7667()
{
byte[] salt = [4, 5, 6];
byte[] deployedCode = [1, 2, 3];
byte[] initCode = Prepare.EvmCode.ForInitOf(deployedCode).Done;
byte[] createCode = Prepare.EvmCode.Create2(initCode, salt, 0).STOP().Done;

TestAllTracerWithOutput result = Execute(createCode);

long gasSpent = GasCostOf.Sha3WordEip7667 * EvmPooledMemory.Div32Ceiling((UInt256)initCode.Length) + 53658;

Assert.That(result.GasSpent, Is.EqualTo(gasSpent));
}

[Test]
public void Log_op_before_eip7667()
{
const int length = 32;
byte[] createCode = Prepare.EvmCode
.PushData(length)
.PushData(0)
.Op(Instruction.LOG0)
.STOP()
.Done;

TestAllTracerWithOutput result = Execute((BlockNumber, Timestamp - 1), createCode);

long gasSpent = GasCostOf.LogData * length + 21384;

Assert.That(result.GasSpent, Is.EqualTo(gasSpent));
}

[Test]
public void Log_op_after_eip7667()
{
const int length = 32;
byte[] createCode = Prepare.EvmCode
.PushData(length)
.PushData(0)
.Op(Instruction.LOG0)
.STOP()
.Done;

TestAllTracerWithOutput result = Execute(createCode);

long gasSpent = GasCostOf.LogDataEip7667 * length + 21384;

Assert.That(result.GasSpent, Is.EqualTo(gasSpent));
}

[Test]
public void Sha256_precompile_base_cost_before_eip_7667()
{
var sha256Precompile = Sha256Precompile.Instance;
var spec = SpecProvider.GetSpec((BlockNumber, Timestamp - 1));

Assert.That(sha256Precompile.BaseGasCost(spec), Is.EqualTo(GasCostOf.Sha256PrecompileBaseCost));
Assert.That(GasCostOf.Sha256PrecompileBaseCost, Is.EqualTo(60));
}

[Test]
public void Sha256_precompile_base_cost_after_eip_7667()
{
var sha256Precompile = Sha256Precompile.Instance;

Assert.That(sha256Precompile.BaseGasCost(Spec), Is.EqualTo(GasCostOf.Sha256PrecompileBaseCostEip7667));
Assert.That(GasCostOf.Sha256PrecompileBaseCostEip7667, Is.EqualTo(300));
}

[Test]
public void Sha256_precompile_data_cost_before_eip_7667()
{
var sha256Precompile = Sha256Precompile.Instance;
var bytes = new byte[1];
var spec = SpecProvider.GetSpec((BlockNumber, Timestamp - 1));
var dataCost = GasCostOf.Sha256PrecompileWordCost * EvmPooledMemory.Div32Ceiling((ulong)bytes.Length);

Assert.That(sha256Precompile.DataGasCost(bytes, spec), Is.EqualTo(dataCost));
Assert.That(GasCostOf.Sha256PrecompileWordCost, Is.EqualTo(12));
}

[Test]
public void Sha256_precompile_data_cost_after_eip_7667()
{
var sha256Precompile = Sha256Precompile.Instance;
var bytes = new byte[1];
var dataCost = GasCostOf.Sha256PrecompileWordCostEip7667 * EvmPooledMemory.Div32Ceiling((ulong)bytes.Length);

Assert.That(sha256Precompile.DataGasCost(bytes, Spec), Is.EqualTo(dataCost));
Assert.That(GasCostOf.Sha256PrecompileWordCostEip7667, Is.EqualTo(60));
}

[Test]
public void Blake2F_precompile_data_cost_before_eip_7667()
{
var blake2FPrecompile = Blake2FPrecompile.Instance;
var spec = SpecProvider.GetSpec((BlockNumber, Timestamp - 1));
var bytes = new byte[213];
bytes[3] = 1;

Assert.That(blake2FPrecompile.DataGasCost(bytes, spec), Is.EqualTo(GasCostOf.Blake2GFRound));
Assert.That(GasCostOf.Blake2GFRound, Is.EqualTo(1));
}

[Test]
public void Blake2F_precompile_data_cost_after_eip_7667()
{
var blake2FPrecompile = Blake2FPrecompile.Instance;
var bytes = new byte[213];
bytes[3] = 1;

Assert.That(blake2FPrecompile.DataGasCost(bytes, Spec), Is.EqualTo(GasCostOf.Blake2GFRoundEip7667));
Assert.That(GasCostOf.Blake2GFRoundEip7667, Is.EqualTo(10));
}
}
12 changes: 12 additions & 0 deletions src/Nethermind/Nethermind.Evm/GasCostOf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ public static class GasCostOf
public const long Log = 375;
public const long LogTopic = 375;
public const long LogData = 8;
public const long LogDataEip7667 = 10;
public const long Sha3 = 30;
public const long Sha3Eip7667 = 300;
public const long Sha3Word = 6;
public const long Sha3WordEip7667 = 60;
public const long BlockHash = 20;
public const long SelfDestruct = 0;
public const long SelfDestructEip150 = 5000;
Expand All @@ -62,5 +65,14 @@ public static class GasCostOf
public const long AccessStorageListEntry = 1900; // eip-2930
public const long TLoad = WarmStateRead; // eip-1153
public const long TStore = WarmStateRead; // eip-1153

public const long Blake2GFRoundEip7667 = 10;
public const long Blake2GFRound = 1;

public const long Sha256PrecompileBaseCostEip7667 = 300L;
public const long Sha256PrecompileBaseCost = 60L;

public const long Sha256PrecompileWordCostEip7667 = 60L;
public const long Sha256PrecompileWordCost = 12L;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public long DataGasCost(in ReadOnlyMemory<byte> inputData, IReleaseSpec releaseS

uint rounds = inputData[..4].Span.ReadEthUInt32();

return rounds;
return rounds * releaseSpec.GetBlake2GFRoundDataCost();
}

public (ReadOnlyMemory<byte>, bool) Run(in ReadOnlyMemory<byte> inputData, IReleaseSpec releaseSpec)
Expand Down
4 changes: 2 additions & 2 deletions src/Nethermind/Nethermind.Evm/Precompiles/Sha256Precompile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ private static void InitIfNeeded()

public long BaseGasCost(IReleaseSpec releaseSpec)
{
return 60L;
return releaseSpec.GetSha256PrecompileBaseCost();
}

public long DataGasCost(in ReadOnlyMemory<byte> inputData, IReleaseSpec releaseSpec)
{
return 12L * EvmPooledMemory.Div32Ceiling((ulong)inputData.Length);
return releaseSpec.GetSha256PrecompileWordCost() * EvmPooledMemory.Div32Ceiling((ulong)inputData.Length);
}

public (ReadOnlyMemory<byte>, bool) Run(in ReadOnlyMemory<byte> inputData, IReleaseSpec releaseSpec)
Expand Down
30 changes: 30 additions & 0 deletions src/Nethermind/Nethermind.Evm/ReleaseSpecExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,35 @@ public static long GetExpByteCost(this IReleaseSpec spec) =>
spec.UseExpDDosProtection
? GasCostOf.ExpByteEip160
: GasCostOf.ExpByte;

public static long GetSha3Cost(this IReleaseSpec spec) =>
spec.IsEip7667Enabled
? GasCostOf.Sha3Eip7667
: GasCostOf.Sha3;

public static long GetSha3WordCost(this IReleaseSpec spec) =>
spec.IsEip7667Enabled
? GasCostOf.Sha3WordEip7667
: GasCostOf.Sha3Word;

public static long GetLogDataCost(this IReleaseSpec spec) =>
spec.IsEip7667Enabled
? GasCostOf.LogDataEip7667
: GasCostOf.LogData;

public static long GetSha256PrecompileBaseCost(this IReleaseSpec spec) =>
spec.IsEip7667Enabled
? GasCostOf.Sha256PrecompileBaseCostEip7667
: GasCostOf.Sha256PrecompileBaseCost;

public static long GetSha256PrecompileWordCost(this IReleaseSpec spec) =>
spec.IsEip7667Enabled
? GasCostOf.Sha256PrecompileWordCostEip7667
: GasCostOf.Sha256PrecompileWordCost;

public static long GetBlake2GFRoundDataCost(this IReleaseSpec spec) =>
spec.IsEip7667Enabled
? GasCostOf.Blake2GFRoundEip7667
: GasCostOf.Blake2GFRound;
}
}
10 changes: 5 additions & 5 deletions src/Nethermind/Nethermind.Evm/VirtualMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1225,7 +1225,7 @@ private CallResult ExecuteCode<TTracingInstructions, TTracingRefunds, TTracingSt
{
if (!stack.PopUInt256(out a)) goto StackUnderflow;
if (!stack.PopUInt256(out b)) goto StackUnderflow;
gasAvailable -= GasCostOf.Sha3 + GasCostOf.Sha3Word * EvmPooledMemory.Div32Ceiling(in b);
gasAvailable -= spec.GetSha3Cost() + spec.GetSha3WordCost() * EvmPooledMemory.Div32Ceiling(in b);

if (!UpdateMemoryCost(vmState, ref gasAvailable, in a, b)) goto OutOfGas;

Expand Down Expand Up @@ -1824,7 +1824,7 @@ private CallResult ExecuteCode<TTracingInstructions, TTracingRefunds, TTracingSt
{
if (vmState.IsStatic) goto StaticCallViolation;

exceptionType = InstructionLog(vmState, ref stack, ref gasAvailable, instruction);
exceptionType = InstructionLog(vmState, ref stack, ref gasAvailable, instruction, spec);
if (exceptionType != EvmExceptionType.None) goto ReturnFailure;
break;
}
Expand Down Expand Up @@ -2449,7 +2449,7 @@ private EvmExceptionType InstructionSelfDestruct<TTracing>(EvmState vmState, ref
long gasCost = GasCostOf.Create +
(spec.IsEip3860Enabled ? GasCostOf.InitCodeWord * EvmPooledMemory.Div32Ceiling(initCodeLength) : 0) +
(instruction == Instruction.CREATE2
? GasCostOf.Sha3Word * EvmPooledMemory.Div32Ceiling(initCodeLength)
? spec.GetSha3WordCost() * EvmPooledMemory.Div32Ceiling(initCodeLength)
: 0);

if (!UpdateGas(gasCost, ref gasAvailable)) return (EvmExceptionType.OutOfGas, null);
Expand Down Expand Up @@ -2560,7 +2560,7 @@ private EvmExceptionType InstructionSelfDestruct<TTracing>(EvmState vmState, ref
}

[SkipLocalsInit]
private static EvmExceptionType InstructionLog<TTracing>(EvmState vmState, ref EvmStack<TTracing> stack, ref long gasAvailable, Instruction instruction)
private static EvmExceptionType InstructionLog<TTracing>(EvmState vmState, ref EvmStack<TTracing> stack, ref long gasAvailable, Instruction instruction, IReleaseSpec spec)
where TTracing : struct, IIsTracing
{
if (!stack.PopUInt256(out UInt256 position)) return EvmExceptionType.StackUnderflow;
Expand All @@ -2569,7 +2569,7 @@ private static EvmExceptionType InstructionLog<TTracing>(EvmState vmState, ref E
if (!UpdateMemoryCost(vmState, ref gasAvailable, in position, length)) return EvmExceptionType.OutOfGas;
if (!UpdateGas(
GasCostOf.Log + topicsCount * GasCostOf.LogTopic +
(long)length * GasCostOf.LogData, ref gasAvailable)) return EvmExceptionType.OutOfGas;
(long)length * spec.GetLogDataCost(), ref gasAvailable)) return EvmExceptionType.OutOfGas;

ReadOnlyMemory<byte> data = vmState.Memory.Load(in position, length);
Hash256[] topics = new Hash256[topicsCount];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ public OverridableReleaseSpec(IReleaseSpec spec)
public bool IsEip4844Enabled => _spec.IsEip4844Enabled;
public bool IsEip3607Enabled { get; set; }

public bool IsEip7667Enabled { get; set; }

public bool IsEip158IgnoredAccount(Address address)
{
return _spec.IsEip158IgnoredAccount(address);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public class ChainParameters
public ulong? Eip6780TransitionTimestamp { get; set; }
public ulong? Eip4788TransitionTimestamp { get; set; }
public Address Eip4788ContractAddress { get; set; }
public ulong? Eip7667TransitionTimestamp { get; set; }

#region EIP-4844 parameters
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ private static ReleaseSpec CreateReleaseSpec(ChainSpec chainSpec, long releaseSt
releaseSpec.IsEip6780Enabled = (chainSpec.Parameters.Eip6780TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp;
releaseSpec.IsEip4788Enabled = (chainSpec.Parameters.Eip4788TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp;
releaseSpec.Eip4788ContractAddress = chainSpec.Parameters.Eip4788ContractAddress;
releaseSpec.IsEip7667Enabled = (chainSpec.Parameters.Eip7667TransitionTimestamp ?? ulong.MaxValue) <= releaseStartTimestamp;

return releaseSpec;
}
Expand Down
Loading