Skip to content

Commit

Permalink
EIP2200 #817
Browse files Browse the repository at this point in the history
  • Loading branch information
tkstanczak committed Aug 23, 2019
1 parent 0ec55d5 commit d20c11c
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/Dirichlet
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public void Non_existing_account_returns_0()

var result = Execute(code);
AssertGas(result,
21000 + GasCostOf.VeryLow * 2 + GasCostOf.SStoreEip1283 + GasCostOf.ExtCodeHash);
21000 + GasCostOf.VeryLow * 2 + GasCostOf.SStoreNetMetered + GasCostOf.ExtCodeHash);
AssertStorage(UInt256.Zero, Keccak.Zero);
}

Expand Down
62 changes: 62 additions & 0 deletions src/Nethermind/Nethermind.Evm.Test/Eip12200Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2018 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/>.
*/

using System;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Store;
using NUnit.Framework;

namespace Nethermind.Evm.Test
{
[TestFixture]
public class Eip2200Tests : VirtualMachineTestsBase
{
protected override long BlockNumber => RopstenSpecProvider.IstanbulBlockNumber;

protected override ISpecProvider SpecProvider => RopstenSpecProvider.Instance;

[TestCase("0x60006000556000600055", 412, 0, 0)]
[TestCase("0x60006000556001600055", 20212, 0, 0)]
[TestCase("0x60016000556000600055", 20212, 19800, 0)]
[TestCase("0x60016000556002600055", 20212, 0, 0)]
[TestCase("0x60016000556001600055", 20212, 0, 0)]
[TestCase("0x60006000556000600055", 5212, 15000, 1)]
[TestCase("0x60006000556001600055", 5212, 4800, 1)]
[TestCase("0x60006000556002600055", 5212, 0, 1)]
[TestCase("0x60026000556000600055", 5212, 15000, 1)]
[TestCase("0x60026000556003600055", 5212, 0, 1)]
[TestCase("0x60026000556001600055", 5212, 4800, 1)]
[TestCase("0x60026000556002600055", 5212, 0, 1)]
[TestCase("0x60016000556000600055", 5212, 15000, 1)]
[TestCase("0x60016000556002600055", 5212, 0, 1)]
[TestCase("0x60016000556001600055", 412, 0, 1)]
[TestCase("0x600160005560006000556001600055", 40218, 19800, 0)]
[TestCase("0x600060005560016000556000600055", 10218, 19800, 1)]
public void Test(string codeHex, long gasUsed, long refund, byte originalValue)
{
TestState.CreateAccount(Recipient, 0);
Storage.Set(new StorageAddress(Recipient, 0), new [] {originalValue});
Storage.Commit();
TestState.Commit(RopstenSpecProvider.Instance.GenesisSpec);

var receipt = Execute(Bytes.FromHexString(codeHex));
AssertGas(receipt, gasUsed + GasCostOf.Transaction - Math.Min((gasUsed + GasCostOf.Transaction) / 2, refund));
}
}
}
54 changes: 54 additions & 0 deletions src/Nethermind/Nethermind.Evm.Test/Eip1283Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,59 @@ public void Test(string codeHex, long gasUsed, long refund, byte originalValue)
var receipt = Execute(Bytes.FromHexString(codeHex));
AssertGas(receipt, gasUsed + GasCostOf.Transaction - Math.Min((gasUsed + GasCostOf.Transaction) / 2, refund));
}

[TestCase("0x60006000556000600055", 412, 0, 0)]
[TestCase("0x60006000556001600055", 20212, 0, 0)]
[TestCase("0x60016000556000600055", 20212, 19800, 0)]
[TestCase("0x60016000556002600055", 20212, 0, 0)]
[TestCase("0x60016000556001600055", 20212, 0, 0)]
[TestCase("0x60006000556000600055", 5212, 15000, 1)]
[TestCase("0x60006000556001600055", 5212, 4800, 1)]
[TestCase("0x60006000556002600055", 5212, 0, 1)]
[TestCase("0x60026000556000600055", 5212, 15000, 1)]
[TestCase("0x60026000556003600055", 5212, 0, 1)]
[TestCase("0x60026000556001600055", 5212, 4800, 1)]
[TestCase("0x60026000556002600055", 5212, 0, 1)]
[TestCase("0x60016000556000600055", 5212, 15000, 1)]
[TestCase("0x60016000556002600055", 5212, 0, 1)]
[TestCase("0x60016000556001600055", 412, 0, 1)]
[TestCase("0x600160005560006000556001600055", 40218, 19800, 0)]
[TestCase("0x600060005560016000556000600055", 10218, 19800, 1)]
public void Test_when_gas_at_stipend(string codeHex, long gasUsed, long refund, byte originalValue)
{
TestState.CreateAccount(Recipient, 0);
Storage.Set(new StorageAddress(Recipient, 0), new [] {originalValue});
Storage.Commit();
TestState.Commit(RopstenSpecProvider.Instance.GenesisSpec);

var receipt = Execute(BlockNumber, 23512, Bytes.FromHexString(codeHex));
Assert.AreEqual(0, receipt.StatusCode);
}

[TestCase("0x60006000556000600055", 412, 0, 0)]
[TestCase("0x60016000556001600055", 412, 0, 1)]
public void Test_when_gas_just_above_stipend(string codeHex, long gasUsed, long refund, byte originalValue)
{
TestState.CreateAccount(Recipient, 0);
Storage.Set(new StorageAddress(Recipient, 0), new [] {originalValue});
Storage.Commit();
TestState.Commit(RopstenSpecProvider.Instance.GenesisSpec);

var receipt = Execute(BlockNumber, 23513, Bytes.FromHexString(codeHex));
Assert.AreEqual(1, receipt.StatusCode);
}

[TestCase("0x60006000556000600055", 412, 0, 0)]
[TestCase("0x60016000556001600055", 412, 0, 1)]
public void Test_when_gas_just_below_stipend(string codeHex, long gasUsed, long refund, byte originalValue)
{
TestState.CreateAccount(Recipient, 0);
Storage.Set(new StorageAddress(Recipient, 0), new [] {originalValue});
Storage.Commit();
TestState.Commit(RopstenSpecProvider.Instance.GenesisSpec);

var receipt = Execute(BlockNumber, 23511, Bytes.FromHexString(codeHex));
Assert.AreEqual(0, receipt.StatusCode);
}
}
}
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Evm.Test/Eip1344Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ private void Test(int chainId)
.Op(Instruction.SSTORE)
.Done;
var result = Execute(code);
var setCost = chainId == 0 ? GasCostOf.SReset : GasCostOf.SSet;
var setCost = chainId == 0 ? GasCostOf.SStoreNetMetered : GasCostOf.SSet;
Assert.AreEqual(StatusCode.Success, result.StatusCode);
AssertGas(result, 21000 + GasCostOf.VeryLow + GasCostOf.Base + setCost);
AssertStorage(0, chainId.ToBigEndianByteArray());
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Evm.Test/Eip145Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ private void AssertEip145(CallOutputTracer receipt, byte[] result)
AssertGas(receipt, result.IsZero() ? ZeroResultGas : NonZeroResultGas);
}

private const long ZeroResultGas = GasCostOf.Transaction + 4 * GasCostOf.VeryLow + GasCostOf.SStoreEip1283;
private const long ZeroResultGas = GasCostOf.Transaction + 4 * GasCostOf.VeryLow + GasCostOf.SStoreNetMetered;
private const long NonZeroResultGas = GasCostOf.Transaction + 4 * GasCostOf.VeryLow + GasCostOf.SSet;

[TestCase("0x0000000000000000000000000000000000000000000000000000000000000001", "0x00", "0x0000000000000000000000000000000000000000000000000000000000000001")]
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Evm.Test/SimdTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ private void AssertSimd(CallOutputTracer receipt, byte[] result)
AssertGas(receipt, result.IsZero() ? ZeroResultGas : NonZeroResultGas);
}

private const long ZeroResultGas = GasCostOf.Transaction + 4 * GasCostOf.VeryLow + GasCostOf.SStoreEip1283;
private const long ZeroResultGas = GasCostOf.Transaction + 4 * GasCostOf.VeryLow + GasCostOf.SStoreNetMetered;
private const long NonZeroResultGas = GasCostOf.Transaction + 4 * GasCostOf.VeryLow + GasCostOf.SSet;
}
}
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Evm/GasCostOf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static class GasCostOf
public const long SLoad = 50;
public const long SLoadEip150 = 200;
public const long JumpDest = 1;
public const long SStoreEip1283 = 200;
public const long SStoreNetMetered = 200;
public const long SSet = 20000;
public const long SReset = 5000;
public const long Create = 32000;
Expand Down
17 changes: 13 additions & 4 deletions src/Nethermind/Nethermind.Evm/VirtualMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1829,12 +1829,21 @@ void UpdateMemoryCost(ref UInt256 position, in UInt256 length)
return CallResult.StaticCallViolationException;
}

bool useNetMetering = spec.IsEip1283Enabled | spec.IsEip2200Enabled;
// fail fast before the first storage read if gas is not enough even for reset
if (!spec.IsEip1283Enabled && !UpdateGas(GasCostOf.SReset, ref gasAvailable))
if (!useNetMetering && !UpdateGas(GasCostOf.SReset, ref gasAvailable))
{
EndInstructionTraceError(OutOfGasErrorText);
return CallResult.OutOfGasException;
}

// fail fast before the first storage read if gas is not enough even for reset
if (!spec.IsEip2200Enabled && gasAvailable <= GasCostOf.CallStipend)
{
Metrics.EvmExceptions++;
EndInstructionTraceError(OutOfGasErrorText);
return CallResult.OutOfGasException;
}

PopUInt256(out UInt256 storageIndex, bytesOnStack);
byte[] newValue = PopBytes(bytesOnStack).WithoutLeadingZeros().ToArray();
Expand All @@ -1846,7 +1855,7 @@ void UpdateMemoryCost(ref UInt256 position, in UInt256 length)

bool newSameAsCurrent = (newIsZero && currentIsZero) || Bytes.AreEqual(currentValue, newValue);

if (!spec.IsEip1283Enabled) // note that for this case we already deducted 5000
if (!useNetMetering) // note that for this case we already deducted 5000
{
if (newIsZero)
{
Expand All @@ -1868,7 +1877,7 @@ void UpdateMemoryCost(ref UInt256 position, in UInt256 length)
{
if (newSameAsCurrent)
{
if(!UpdateGas(GasCostOf.SStoreEip1283, ref gasAvailable))
if(!UpdateGas(GasCostOf.SStoreNetMetered, ref gasAvailable))
{
EndInstructionTraceError(OutOfGasErrorText);
return CallResult.OutOfGasException;
Expand Down Expand Up @@ -1906,7 +1915,7 @@ void UpdateMemoryCost(ref UInt256 position, in UInt256 length)
}
else // eip1283enabled, N != C != O
{
if (!UpdateGas(GasCostOf.SStoreEip1283, ref gasAvailable))
if (!UpdateGas(GasCostOf.SStoreNetMetered, ref gasAvailable))
{
EndInstructionTraceError(OutOfGasErrorText);
return CallResult.OutOfGasException;
Expand Down

0 comments on commit d20c11c

Please sign in to comment.