mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 12:16:44 +00:00
core/vm: add access cost check
This commit is contained in:
parent
dd8dd1520f
commit
b0b042e44c
2 changed files with 27 additions and 5 deletions
|
|
@ -21,6 +21,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -235,3 +236,19 @@ func TestEIP8038SelfdestructAccountWrite(t *testing.T) {
|
||||||
t.Fatalf("state gas = %d, want %d", res.UsedStateGas, want)
|
t.Fatalf("state gas = %d, want %d", res.UsedStateGas, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestEIP8038SStoreAccessGuard covers the affordability check that bails out
|
||||||
|
// before the slot is read once the gas left cannot cover the slot's access cost.
|
||||||
|
// The two PUSH1s cost 6, so a 2506 budget leaves 2500 at the SSTORE: above the
|
||||||
|
// reentrancy sentry (2300) yet below COLD_STORAGE_ACCESS (3000). The guard must
|
||||||
|
// fire, distinguishable from the sentry/charge OOG by its "slot access" message.
|
||||||
|
func TestEIP8038SStoreAccessGuard(t *testing.T) {
|
||||||
|
budget := NewGasBudget(6+params.SstoreSentryGasEIP2200+200, 0)
|
||||||
|
_, _, err := run8038(t, sstore(0, 1), budget, new(uint256.Int), nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected failure: gas left cannot cover cold-slot access")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "not enough gas for slot access") {
|
||||||
|
t.Fatalf("got %q, want the slot-access guard error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -696,10 +696,10 @@ func gasSStore8037And8038(evm *EVM, contract *Contract, stack *Stack, mem *Memor
|
||||||
return GasCosts{}, errors.New("not enough gas for reentrancy sentry")
|
return GasCosts{}, errors.New("not enough gas for reentrancy sentry")
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
y, x = stack.back(1), stack.peek()
|
y, x = stack.back(1), stack.peek()
|
||||||
slot = common.Hash(x.Bytes32())
|
slot = common.Hash(x.Bytes32())
|
||||||
current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot)
|
value = common.Hash(y.Bytes32())
|
||||||
value = common.Hash(y.Bytes32())
|
stateSet = params.StorageCreationSize * evm.Context.CostPerStateByte
|
||||||
)
|
)
|
||||||
// Check slot presence in the access list
|
// Check slot presence in the access list
|
||||||
access := params.WarmStorageReadCostEIP2929
|
access := params.WarmStorageReadCostEIP2929
|
||||||
|
|
@ -707,7 +707,12 @@ func gasSStore8037And8038(evm *EVM, contract *Contract, stack *Stack, mem *Memor
|
||||||
access = params.ColdStorageAccessAmsterdam
|
access = params.ColdStorageAccessAmsterdam
|
||||||
evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
|
evm.StateDB.AddSlotToAccessList(contract.Address(), slot)
|
||||||
}
|
}
|
||||||
stateSet := params.StorageCreationSize * evm.Context.CostPerStateByte
|
// Check access cost affordability before reading slot
|
||||||
|
if contract.Gas.RegularGas < access {
|
||||||
|
return GasCosts{}, errors.New("not enough gas for slot access")
|
||||||
|
}
|
||||||
|
// Read the slot value for gas cost measurement
|
||||||
|
current, original := evm.StateDB.GetStateAndCommittedState(contract.Address(), slot)
|
||||||
|
|
||||||
if current == value { // noop (1)
|
if current == value { // noop (1)
|
||||||
return GasCosts{RegularGas: access}, nil
|
return GasCosts{RegularGas: access}, nil
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue