diff --git a/src/evm/evm.h b/src/evm/evm.h index deaccfa63..64350be0c 100644 --- a/src/evm/evm.h +++ b/src/evm/evm.h @@ -24,6 +24,9 @@ constexpr auto CALL_VALUE_COST = 9000; constexpr auto ACCOUNT_CREATION_COST = 25000; constexpr auto CALL_GAS_STIPEND = 2300; constexpr uint64_t LegacyModExpBaseGas = 600; +constexpr auto EXP_BYTE_GAS = 50; +constexpr auto EXP_BYTE_GAS_PRE_SPURIOUS_DRAGON = 10; + /// The limit of the size of created contract /// defined by [EIP-170](https://eips.ethereum.org/EIPS/eip-170) constexpr auto MAX_CODE_SIZE = 0x6000; diff --git a/src/evm/opcode_handlers.cpp b/src/evm/opcode_handlers.cpp index 9d6283cbc..23141457f 100644 --- a/src/evm/opcode_handlers.cpp +++ b/src/evm/opcode_handlers.cpp @@ -64,7 +64,6 @@ DEFINE_CALCULATE_GAS(Sub, OP_SUB); DEFINE_CALCULATE_GAS(Mul, OP_MUL); DEFINE_CALCULATE_GAS(Div, OP_DIV); DEFINE_CALCULATE_GAS(Mod, OP_MOD); -DEFINE_CALCULATE_GAS(Exp, OP_EXP); DEFINE_CALCULATE_GAS(SDiv, OP_SDIV); DEFINE_CALCULATE_GAS(SMod, OP_SMOD); @@ -92,6 +91,7 @@ DEFINE_CALCULATE_GAS(Sgt, OP_SGT); DEFINE_NOT_TEMPLATE_CALCULATE_GAS(SignExtend, OP_SIGNEXTEND); DEFINE_NOT_TEMPLATE_CALCULATE_GAS(Byte, OP_BYTE); DEFINE_NOT_TEMPLATE_CALCULATE_GAS(Sar, OP_SAR); +DEFINE_NOT_TEMPLATE_CALCULATE_GAS(Exp, OP_EXP); // Environmental information DEFINE_NOT_TEMPLATE_CALCULATE_GAS(Address, OP_ADDRESS); @@ -348,6 +348,26 @@ void SarHandler::doExecute() { } Frame->push(Res); } + +void ExpHandler::doExecute() { + auto *Frame = getFrame(); + auto *Context = getContext(); + EVM_STACK_CHECK(Frame, 2); + + auto &A = Frame->Stack[Frame->Sp - 1]; + auto &B = Frame->Stack[Frame->Sp - 2]; + uint64_t BytesNum = intx::count_significant_bytes(B); + uint64_t ByteGas = currentRevision() < EVMC_SPURIOUS_DRAGON + ? EXP_BYTE_GAS_PRE_SPURIOUS_DRAGON + : EXP_BYTE_GAS; + if (!chargeGas(Frame, BytesNum * ByteGas)) { + Context->setStatus(EVMC_OUT_OF_GAS); + return; + } + B = intx::exp(A, B); + --Frame->Sp; +} + // environmental information operations void AddressHandler::doExecute() { auto *Frame = getFrame(); diff --git a/src/evm/opcode_handlers.h b/src/evm/opcode_handlers.h index e13ea8791..b03a11aaa 100644 --- a/src/evm/opcode_handlers.h +++ b/src/evm/opcode_handlers.h @@ -170,7 +170,6 @@ DEFINE_BINARY_OP(Sub, (A - B)); DEFINE_BINARY_OP(Mul, (A * B)); DEFINE_BINARY_OP(Div, ((B == 0) ? intx::uint256(0) : (A / B))); DEFINE_BINARY_OP(Mod, ((B == 0) ? intx::uint256(0) : A % B)); -DEFINE_BINARY_OP(Exp, intx::exp(A, B)); DEFINE_BINARY_OP(SDiv, ((B == 0) ? intx::uint256(0) : intx::sdivrem(A, B).quot)); DEFINE_BINARY_OP(SMod, ((B == 0) ? intx::uint256(0) : intx::sdivrem(A, B).rem)); @@ -257,6 +256,7 @@ DEFINE_UNIMPLEMENT_HANDLER(SStore); DEFINE_UNIMPLEMENT_HANDLER(SignExtend); DEFINE_UNIMPLEMENT_HANDLER(Byte); DEFINE_UNIMPLEMENT_HANDLER(Sar); +DEFINE_UNIMPLEMENT_HANDLER(Exp); // Memory operations DEFINE_UNIMPLEMENT_HANDLER(MStore); diff --git a/tests/evmone_unittests/EVMOneInterpreterUnitTestsRunList.txt b/tests/evmone_unittests/EVMOneInterpreterUnitTestsRunList.txt index 44f1819a4..297530314 100644 --- a/tests/evmone_unittests/EVMOneInterpreterUnitTestsRunList.txt +++ b/tests/evmone_unittests/EVMOneInterpreterUnitTestsRunList.txt @@ -200,3 +200,6 @@ multi_vm/evm.sload_cost_pre_tangerine_whistle/external_vm multi_vm/evm.staticcall_then_oog/external_vm multi_vm/evm.staticmode/external_vm multi_vm/evm.storage/external_vm +multi_vm/evm.exp/external_vm +multi_vm/evm.exp_oog/external_vm +multi_vm/evm.exp_pre_spurious_dragon/external_vm