Skip to content

Commit 4669cca

Browse files
committed
fix(evm): correct CALL gas and stipend accounting
1 parent da0a113 commit 4669cca

3 files changed

Lines changed: 21 additions & 38 deletions

File tree

src/compiler/evm_frontend/evm_imported.cpp

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -886,27 +886,15 @@ static uint64_t evmHandleCallInternal(zen::runtime::EVMInstance *Instance,
886886

887887
uint64_t CallGas = Gas;
888888
bool HasEnoughBalance = true;
889-
if (HasValueArgs && HasValue) {
890-
const auto CallerBalance = Module->Host->get_balance(CurrentMsg->recipient);
891-
const intx::uint256 CallerValue =
892-
intx::be::load<intx::uint256>(CallerBalance);
893-
HasEnoughBalance = CallerValue >= intx::uint256(Value);
894-
}
895889

896890
if (HasValueArgs) {
897891
std::optional<bool> AccountState;
898892
uint64_t GasCost = HasValue ? zen::evm::CALL_VALUE_COST : 0;
899-
if (HasValue && !HasEnoughBalance) {
900-
GasCost -= zen::evm::CALL_GAS_STIPEND;
901-
}
902893
if (CallKind == EVMC_CALL) {
903894
if (HasValue || Instance->getRevision() < EVMC_SPURIOUS_DRAGON) {
904895
AccountState = Module->Host->account_exists(TargetAddr);
905896
if (!AccountState.value()) {
906897
GasCost += zen::evm::ACCOUNT_CREATION_COST;
907-
if (HasValue && HasEnoughBalance) {
908-
GasCost -= zen::evm::CALL_GAS_STIPEND;
909-
}
910898
}
911899
}
912900
}
@@ -924,11 +912,16 @@ static uint64_t evmHandleCallInternal(zen::runtime::EVMInstance *Instance,
924912
}
925913

926914
if (HasValueArgs && HasValue) {
915+
CallGas += zen::evm::CALL_GAS_STIPEND;
916+
Instance->addGas(zen::evm::CALL_GAS_STIPEND);
917+
const auto CallerBalance = Module->Host->get_balance(CurrentMsg->recipient);
918+
const intx::uint256 CallerValue =
919+
intx::be::load<intx::uint256>(CallerBalance);
920+
HasEnoughBalance = CallerValue >= intx::uint256(Value);
927921
if (!HasEnoughBalance) {
928922
Instance->setReturnData({});
929923
return 0;
930924
}
931-
CallGas += zen::evm::CALL_GAS_STIPEND;
932925
}
933926

934927
uint8_t *MemoryBase = Instance->getMemoryBase();
@@ -972,11 +965,6 @@ static uint64_t evmHandleCallInternal(zen::runtime::EVMInstance *Instance,
972965
GasLeft = 0;
973966
}
974967
uint64_t GasUsed = CallGas > GasLeft ? CallGas - GasLeft : 0;
975-
if (HasValue) {
976-
GasUsed = GasUsed > zen::evm::CALL_GAS_STIPEND
977-
? GasUsed - zen::evm::CALL_GAS_STIPEND
978-
: 0;
979-
}
980968
if (GasUsed > 0) {
981969
Instance->chargeGas(GasUsed);
982970
}

src/evm/opcode_handlers.cpp

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,11 +1332,6 @@ void CallHandler::doExecute() {
13321332

13331333
const bool TransfersValue = NeedValue && Value != 0;
13341334
bool HasEnoughBalance = true;
1335-
if (TransfersValue) {
1336-
const auto CallerBalance = intx::be::load<intx::uint256>(
1337-
Frame->Host->get_balance(Frame->Msg.recipient));
1338-
HasEnoughBalance = CallerBalance >= Value;
1339-
}
13401335

13411336
// Map opcode to evmc_call_kind
13421337
evmc_call_kind CallKind;
@@ -1365,15 +1360,13 @@ void CallHandler::doExecute() {
13651360

13661361
// Charge CALL_VALUE_COST only if actually transferring value (EIP-150)
13671362
int64_t Cost = TransfersValue ? CALL_VALUE_COST : 0;
1368-
if (TransfersValue && !HasEnoughBalance) {
1369-
Cost -= CALL_GAS_STIPEND;
1370-
}
13711363

13721364
if (OpCode == OP_CALL || OpCode == OP_CALLCODE) {
1373-
if (OpCode == OP_CALL && TransfersValue && HasEnoughBalance &&
1374-
!Frame->Host->account_exists(Dest)) {
1375-
Cost += ACCOUNT_CREATION_COST;
1376-
Cost -= CALL_GAS_STIPEND;
1365+
if (OpCode == OP_CALL &&
1366+
(TransfersValue || currentRevision() < EVMC_SPURIOUS_DRAGON)) {
1367+
if (!Frame->Host->account_exists(Dest)) {
1368+
Cost += ACCOUNT_CREATION_COST;
1369+
}
13771370
}
13781371
}
13791372

@@ -1433,6 +1426,10 @@ void CallHandler::doExecute() {
14331426

14341427
if (TransfersValue) {
14351428
NewMsg.gas += CALL_GAS_STIPEND;
1429+
Frame->Msg.gas += CALL_GAS_STIPEND;
1430+
const auto CallerBalance = intx::be::load<intx::uint256>(
1431+
Frame->Host->get_balance(Frame->Msg.recipient));
1432+
HasEnoughBalance = CallerBalance >= Value;
14361433
if (!HasEnoughBalance) {
14371434
Context->setStatus(EVMC_SUCCESS); // "Light" failure
14381435
return;
@@ -1463,9 +1460,6 @@ void CallHandler::doExecute() {
14631460
GasLeft = 0;
14641461
}
14651462
uint64_t GasUsed = CallGas > GasLeft ? CallGas - GasLeft : 0;
1466-
if (TransfersValue) {
1467-
GasUsed = GasUsed > CALL_GAS_STIPEND ? GasUsed - CALL_GAS_STIPEND : 0;
1468-
}
14691463
chargeGas(Frame, GasUsed); // it's safe to charge gas here
14701464

14711465
// Track subcall refund at Instance level

src/tests/evm_test_host.hpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -490,15 +490,16 @@ class ZenMockedEVMHost : public evmc::MockedHost {
490490
if (Msg.kind == EVMC_CALL && !applyCallValueTransfer(Msg)) {
491491
return ParentResult;
492492
}
493-
if (FeesPrepaidInTx && Msg.kind == EVMC_CALL &&
494-
toUint256Bytes(Msg.value) != intx::uint256{0} &&
495-
ParentResult.status_code == EVMC_SUCCESS) {
496-
CallStipendRefund += CALL_GAS_STIPEND;
497-
}
498493
if (ParentResult.status_code == EVMC_SUCCESS &&
499494
ParentResult.gas_left == 0) {
500495
ParentResult.gas_left = Msg.gas;
501496
}
497+
if (FeesPrepaidInTx && Msg.kind == EVMC_CALL &&
498+
toUint256Bytes(Msg.value) != intx::uint256{0} &&
499+
ParentResult.status_code == EVMC_SUCCESS &&
500+
ParentResult.gas_left < Msg.gas) {
501+
CallStipendRefund += CALL_GAS_STIPEND;
502+
}
502503
return ParentResult;
503504
}
504505

0 commit comments

Comments
 (0)