diff --git a/src/Dirichlet b/src/Dirichlet index bce377f3fde..117b71bf29c 160000 --- a/src/Dirichlet +++ b/src/Dirichlet @@ -1 +1 @@ -Subproject commit bce377f3fde0e8b225e8c98030ac439eb1afe5c0 +Subproject commit 117b71bf29c19350beba99bc3ad300606eb4e9b0 diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs index 01384719a6b..1b9f22ee9c0 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs @@ -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); } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip12200Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip12200Tests.cs new file mode 100644 index 00000000000..b6820c1e119 --- /dev/null +++ b/src/Nethermind/Nethermind.Evm.Test/Eip12200Tests.cs @@ -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 . + */ + +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)); + } + } +} \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1283Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1283Tests.cs index ff94308af6d..ab233fe5c49 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1283Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1283Tests.cs @@ -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); + } } } \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1344Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1344Tests.cs index 017af1104ef..912fff3baaf 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1344Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1344Tests.cs @@ -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()); diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip145Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip145Tests.cs index 1779f4513b1..2a6fbd4c758 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip145Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip145Tests.cs @@ -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")] diff --git a/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs b/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs index c536eb42bbf..c118667159b 100644 --- a/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs @@ -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; } } \ No newline at end of file diff --git a/src/Nethermind/Nethermind.Evm/GasCostOf.cs b/src/Nethermind/Nethermind.Evm/GasCostOf.cs index b19b64d4103..b7ada9055b9 100644 --- a/src/Nethermind/Nethermind.Evm/GasCostOf.cs +++ b/src/Nethermind/Nethermind.Evm/GasCostOf.cs @@ -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; diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index e8141a1622c..e6c1ee3895d 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -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(); @@ -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) { @@ -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; @@ -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;