Skip to content

Commit 551bd6e

Browse files
authored
eth/tracers: invoke enter/exit on 0-value calls to inex accounts (#23828)
1 parent c576fa1 commit 551bd6e

File tree

2 files changed

+87
-3
lines changed

2 files changed

+87
-3
lines changed

core/vm/evm.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,14 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
182182
if !evm.StateDB.Exist(addr) {
183183
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
184184
// Calling a non existing account, don't do anything, but ping the tracer
185-
if evm.Config.Debug && evm.depth == 0 {
186-
evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
187-
evm.Config.Tracer.CaptureEnd(ret, 0, 0, nil)
185+
if evm.Config.Debug {
186+
if evm.depth == 0 {
187+
evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
188+
evm.Config.Tracer.CaptureEnd(ret, 0, 0, nil)
189+
} else {
190+
evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
191+
evm.Config.Tracer.CaptureExit(ret, 0, nil)
192+
}
188193
}
189194
return nil, gas, nil
190195
}

eth/tracers/tracers_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,85 @@ type callTracerTest struct {
120120
Result *callTrace `json:"result"`
121121
}
122122

123+
// TestZeroValueToNotExitCall tests the calltracer(s) on the following:
124+
// Tx to A, A calls B with zero value. B does not already exist.
125+
// Expected: that enter/exit is invoked and the inner call is shown in the result
126+
func TestZeroValueToNotExitCall(t *testing.T) {
127+
var to = common.HexToAddress("0x00000000000000000000000000000000deadbeef")
128+
privkey, err := crypto.HexToECDSA("0000000000000000deadbeef00000000000000000000000000000000deadbeef")
129+
if err != nil {
130+
t.Fatalf("err %v", err)
131+
}
132+
signer := types.NewEIP155Signer(big.NewInt(1))
133+
tx, err := types.SignNewTx(privkey, signer, &types.LegacyTx{
134+
GasPrice: big.NewInt(0),
135+
Gas: 50000,
136+
To: &to,
137+
})
138+
if err != nil {
139+
t.Fatalf("err %v", err)
140+
}
141+
origin, _ := signer.Sender(tx)
142+
txContext := vm.TxContext{
143+
Origin: origin,
144+
GasPrice: big.NewInt(1),
145+
}
146+
context := vm.BlockContext{
147+
CanTransfer: core.CanTransfer,
148+
Transfer: core.Transfer,
149+
Coinbase: common.Address{},
150+
BlockNumber: new(big.Int).SetUint64(8000000),
151+
Time: new(big.Int).SetUint64(5),
152+
Difficulty: big.NewInt(0x30000),
153+
GasLimit: uint64(6000000),
154+
}
155+
var code = []byte{
156+
byte(vm.PUSH1), 0x0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), // in and outs zero
157+
byte(vm.DUP1), byte(vm.PUSH1), 0xff, byte(vm.GAS), // value=0,address=0xff, gas=GAS
158+
byte(vm.CALL),
159+
}
160+
var alloc = core.GenesisAlloc{
161+
to: core.GenesisAccount{
162+
Nonce: 1,
163+
Code: code,
164+
},
165+
origin: core.GenesisAccount{
166+
Nonce: 0,
167+
Balance: big.NewInt(500000000000000),
168+
},
169+
}
170+
_, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false)
171+
// Create the tracer, the EVM environment and run it
172+
tracer, err := New("callTracer", new(Context))
173+
if err != nil {
174+
t.Fatalf("failed to create call tracer: %v", err)
175+
}
176+
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
177+
msg, err := tx.AsMessage(signer, nil)
178+
if err != nil {
179+
t.Fatalf("failed to prepare transaction for tracing: %v", err)
180+
}
181+
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
182+
if _, err = st.TransitionDb(); err != nil {
183+
t.Fatalf("failed to execute transaction: %v", err)
184+
}
185+
// Retrieve the trace result and compare against the etalon
186+
res, err := tracer.GetResult()
187+
if err != nil {
188+
t.Fatalf("failed to retrieve trace result: %v", err)
189+
}
190+
have := new(callTrace)
191+
if err := json.Unmarshal(res, have); err != nil {
192+
t.Fatalf("failed to unmarshal trace result: %v", err)
193+
}
194+
wantStr := `{"type":"CALL","from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","to":"0x00000000000000000000000000000000deadbeef","value":"0x0","gas":"0x7148","gasUsed":"0x2d0","input":"0x","output":"0x","calls":[{"type":"CALL","from":"0x00000000000000000000000000000000deadbeef","to":"0x00000000000000000000000000000000000000ff","value":"0x0","gas":"0x6cbf","gasUsed":"0x0","input":"0x","output":"0x"}]}`
195+
want := new(callTrace)
196+
json.Unmarshal([]byte(wantStr), want)
197+
if !jsonEqual(have, want) {
198+
t.Error("have != want")
199+
}
200+
}
201+
123202
func TestPrestateTracerCreate2(t *testing.T) {
124203
unsignedTx := types.NewTransaction(1, common.HexToAddress("0x00000000000000000000000000000000deadbeef"),
125204
new(big.Int), 5000000, big.NewInt(1), []byte{})

0 commit comments

Comments
 (0)