core/vm: disable the value transfer in syscall (#33741)
Some checks are pending
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Keeper Build (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run

In src/ethereum/forks/amsterdam/vm/interpreter.py:299-304, the caller
address is
only tracked for block level accessList when there's a value transfer:

```python
if message.should_transfer_value and message.value != 0:  
    # Track value transfer  
    sender_balance = get_account(state, message.caller).balance  
    recipient_balance = get_account(state, message.current_target).balance  

    track_address(message.state_changes, message.caller)  # Line 304
```

Since system transactions have should_transfer_value=False and value=0, 
this condition is never met, so the caller (SYSTEM_ADDRESS) is not
tracked.

This condition is applied for the syscall in the geth implementation,
aligning with the spec of EIP7928.

---------

Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
rjl493456442 2026-02-18 08:40:23 +08:00 committed by GitHub
parent 3eed0580d4
commit 01fe1d716c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -245,13 +245,14 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
if evm.depth > int(params.CallCreateDepth) {
return nil, gas, ErrDepth
}
// Fail if we're trying to transfer more than the available balance
if !value.IsZero() && !evm.Context.CanTransfer(evm.StateDB, caller, value) {
syscall := isSystemCall(caller)
// Fail if we're trying to transfer more than the available balance.
if !syscall && !value.IsZero() && !evm.Context.CanTransfer(evm.StateDB, caller, value) {
return nil, gas, ErrInsufficientBalance
}
snapshot := evm.StateDB.Snapshot()
p, isPrecompile := evm.precompile(addr)
if !evm.StateDB.Exist(addr) {
if !isPrecompile && evm.chainRules.IsEIP4762 && !isSystemCall(caller) {
// Add proof of absence to witness
@ -275,8 +276,12 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
}
evm.StateDB.CreateAccount(addr)
}
// Perform the value transfer only in non-syscall mode.
// Calling this is required even for zero-value transfers,
// to ensure the state clearing mechanism is applied.
if !syscall {
evm.Context.Transfer(evm.StateDB, caller, addr, value)
}
if isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
} else {
@ -302,7 +307,6 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
}
gas = 0
}
// TODO: consider clearing up unused snapshots: