From b74ac0e9ead031b0cd33a23e8a5392158b0c6e21 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Thu, 29 Aug 2019 13:56:14 +0200 Subject: [PATCH 1/3] Unit test for Istanbul SSTORE cost --- test/unittests/evm_state_test.cpp | 44 ++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/test/unittests/evm_state_test.cpp b/test/unittests/evm_state_test.cpp index 5d32ad5609..1bfe576e8a 100644 --- a/test/unittests/evm_state_test.cpp +++ b/test/unittests/evm_state_test.cpp @@ -94,7 +94,7 @@ TEST_F(evm_state, sstore_cost) auto v1 = evmc::bytes32{}; v1.bytes[31] = 1; - auto revs = {EVMC_BYZANTIUM, EVMC_CONSTANTINOPLE, EVMC_PETERSBURG}; + auto revs = {EVMC_BYZANTIUM, EVMC_CONSTANTINOPLE, EVMC_PETERSBURG, EVMC_ISTANBUL}; for (auto r : revs) { rev = r; @@ -130,7 +130,12 @@ TEST_F(evm_state, sstore_cost) storage[v1] = v1; execute(sstore(1, push(1))); EXPECT_EQ(result.status_code, EVMC_SUCCESS); - EXPECT_EQ(gas_used, rev == EVMC_CONSTANTINOPLE ? 206 : 5006); + if (rev >= EVMC_ISTANBUL) + EXPECT_EQ(gas_used, 806); + else if (rev == EVMC_CONSTANTINOPLE) + EXPECT_EQ(gas_used, 206); + else + EXPECT_EQ(gas_used, 5006); execute(205, sstore(1, push(1))); EXPECT_EQ(result.status_code, EVMC_OUT_OF_GAS); @@ -138,34 +143,59 @@ TEST_F(evm_state, sstore_cost) storage.clear(); execute(sstore(1, push(1)) + sstore(1, push(1))); EXPECT_EQ(result.status_code, EVMC_SUCCESS); - EXPECT_EQ(gas_used, rev == EVMC_CONSTANTINOPLE ? 20212 : 25012); + if (rev >= EVMC_ISTANBUL) + EXPECT_EQ(gas_used, 20812); + else if (rev == EVMC_CONSTANTINOPLE) + EXPECT_EQ(gas_used, 20212); + else + EXPECT_EQ(gas_used, 25012); // Modified again: storage.clear(); storage[v1] = {v1, true}; execute(sstore(1, push(2))); EXPECT_EQ(result.status_code, EVMC_SUCCESS); - EXPECT_EQ(gas_used, rev == EVMC_CONSTANTINOPLE ? 206 : 5006); + if (rev >= EVMC_ISTANBUL) + EXPECT_EQ(gas_used, 806); + else if (rev == EVMC_CONSTANTINOPLE) + EXPECT_EQ(gas_used, 206); + else + EXPECT_EQ(gas_used, 5006); // Added & modified again: storage.clear(); execute(sstore(1, push(1)) + sstore(1, push(2))); EXPECT_EQ(result.status_code, EVMC_SUCCESS); - EXPECT_EQ(gas_used, rev == EVMC_CONSTANTINOPLE ? 20212 : 25012); + if (rev >= EVMC_ISTANBUL) + EXPECT_EQ(gas_used, 20812); + else if (rev == EVMC_CONSTANTINOPLE) + EXPECT_EQ(gas_used, 20212); + else + EXPECT_EQ(gas_used, 25012); // Modified & modified again: storage.clear(); storage[v1] = v1; execute(sstore(1, push(2)) + sstore(1, push(3))); EXPECT_EQ(result.status_code, EVMC_SUCCESS); - EXPECT_EQ(gas_used, rev == EVMC_CONSTANTINOPLE ? 5212 : 10012); + if (rev >= EVMC_ISTANBUL) + EXPECT_EQ(gas_used, 5812); + else if (rev == EVMC_CONSTANTINOPLE) + EXPECT_EQ(gas_used, 5212); + else + EXPECT_EQ(gas_used, 10012); // Modified & modified again back to original: storage.clear(); storage[v1] = v1; execute(sstore(1, push(2)) + sstore(1, push(1))); EXPECT_EQ(result.status_code, EVMC_SUCCESS); - EXPECT_EQ(gas_used, rev == EVMC_CONSTANTINOPLE ? 5212 : 10012); + if (rev >= EVMC_ISTANBUL) + EXPECT_EQ(gas_used, 5812); + else if (rev == EVMC_CONSTANTINOPLE) + EXPECT_EQ(gas_used, 5212); + else + EXPECT_EQ(gas_used, 10012); } } From 2f12eecc3ba3fb7fa71601243d6212f625896a38 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Thu, 29 Aug 2019 19:35:02 +0200 Subject: [PATCH 2/3] Implement EIP-2200 SSTORE repricing --- lib/evmone/instructions.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index cffc10d49d..f1fa6d1251 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -506,13 +506,23 @@ const instruction* op_sstore(const instruction* instr, execution_state& state) n switch (status) { case EVMC_STORAGE_UNCHANGED: - cost = state.rev == EVMC_CONSTANTINOPLE ? 200 : 5000; + if (state.rev >= EVMC_ISTANBUL) + cost = 800; + else if (state.rev == EVMC_CONSTANTINOPLE) + cost = 200; + else + cost = 5000; break; case EVMC_STORAGE_MODIFIED: cost = 5000; break; case EVMC_STORAGE_MODIFIED_AGAIN: - cost = state.rev == EVMC_CONSTANTINOPLE ? 200 : 5000; + if (state.rev >= EVMC_ISTANBUL) + cost = 800; + else if (state.rev == EVMC_CONSTANTINOPLE) + cost = 200; + else + cost = 5000; break; case EVMC_STORAGE_ADDED: cost = 20000; From b0fea29afd42ae1a4882f1c0a20dd73a79d5c348 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Wed, 4 Sep 2019 12:04:08 +0200 Subject: [PATCH 3/3] EIP-2200 implementation: throw OOG for SSTORE with gas below stipend --- lib/evmone/analysis.cpp | 1 + lib/evmone/instructions.cpp | 8 ++++++++ test/unittests/evm_state_test.cpp | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/lib/evmone/analysis.cpp b/lib/evmone/analysis.cpp index 763018ab98..6b1d3a21e1 100644 --- a/lib/evmone/analysis.cpp +++ b/lib/evmone/analysis.cpp @@ -131,6 +131,7 @@ code_analysis analyze(evmc_revision rev, const uint8_t* code, size_t code_size) case OP_STATICCALL: case OP_CREATE: case OP_CREATE2: + case OP_SSTORE: instr.arg.number = block.gas_cost; break; diff --git a/lib/evmone/instructions.cpp b/lib/evmone/instructions.cpp index f1fa6d1251..fbf3404538 100644 --- a/lib/evmone/instructions.cpp +++ b/lib/evmone/instructions.cpp @@ -499,6 +499,14 @@ const instruction* op_sstore(const instruction* instr, execution_state& state) n if (state.msg->flags & EVMC_STATIC) return state.exit(EVMC_STATIC_MODE_VIOLATION); + if (state.rev >= EVMC_ISTANBUL) + { + const auto correction = state.current_block_cost - instr->arg.number; + const auto gas_left = state.gas_left + correction; + if (gas_left <= 2300) + return state.exit(EVMC_OUT_OF_GAS); + } + const auto key = intx::be::store(state.stack.pop()); const auto value = intx::be::store(state.stack.pop()); auto status = state.host.set_storage(state.msg->destination, key, value); diff --git a/test/unittests/evm_state_test.cpp b/test/unittests/evm_state_test.cpp index 1bfe576e8a..7e2c87f22d 100644 --- a/test/unittests/evm_state_test.cpp +++ b/test/unittests/evm_state_test.cpp @@ -199,6 +199,26 @@ TEST_F(evm_state, sstore_cost) } } +TEST_F(evm_state, sstore_below_stipend) +{ + const auto code = sstore(0, 0); + + rev = EVMC_HOMESTEAD; + execute(2306, code); + EXPECT_EQ(result.status_code, EVMC_OUT_OF_GAS); + + rev = EVMC_CONSTANTINOPLE; + execute(2306, code); + EXPECT_EQ(result.status_code, EVMC_SUCCESS); + + rev = EVMC_ISTANBUL; + execute(2306, code); + EXPECT_EQ(result.status_code, EVMC_OUT_OF_GAS); + + execute(2307, code); + EXPECT_EQ(result.status_code, EVMC_SUCCESS); +} + TEST_F(evm_state, tx_context) { rev = EVMC_ISTANBUL;