Skip to content

Commit 76bf49e

Browse files
mmsqeyihuang
andauthored
Problem: incorrect spendable balance when debug trace tx (#574)
* Problem: incorrect spendable balance when debug trace tx * fix * Update tests/integration_tests/test_tracers.py Co-authored-by: mmsqe <tqd0800210105@gmail.com> Signed-off-by: yihuang <huang@crypto.com> --------- Signed-off-by: yihuang <huang@crypto.com> Co-authored-by: yihuang <huang@crypto.com>
1 parent b602a26 commit 76bf49e

File tree

7 files changed

+90
-13
lines changed

7 files changed

+90
-13
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ jobs:
120120
- name: 'Tar debug files'
121121
if: failure()
122122
run: tar cfz debug_files.tar.gz -C /tmp/pytest-of-runner .
123-
- uses: actions/upload-artifact@v3
123+
- uses: actions/upload-artifact@v4
124124
if: failure()
125125
with:
126126
name: debug-files

.golangci.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ linters:
2121
- misspell
2222
- nakedret
2323
- prealloc
24-
- exportloopref
2524
- staticcheck
2625
- stylecheck
2726
- typecheck
@@ -30,7 +29,6 @@ linters:
3029
- unused
3130
- nolintlint
3231
- asciicheck
33-
- exportloopref
3432
- gofumpt
3533
- gomodguard
3634
- whitespace

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
8080
* (ante) [#560](https://github.com/crypto-org-chain/ethermint/pull/560) Check gasWanted only in checkTx mode.
8181
* (rpc) [#562](https://github.com/crypto-org-chain/ethermint/pull/562) Fix nil pointer panic with legacy transaction format.
8282
* (evm) [#567](https://github.com/crypto-org-chain/ethermint/pull/567) Fix nonce management in batch transaction.
83+
* (rpc) [#574](https://github.com/crypto-org-chain/ethermint/pull/574) Fix incorrect spendable balance when debug trace tx.
8384

8485
### Improvements
8586

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
contract SelfDestruct {
5+
address payable recipient = payable(0x0F0cb39319129BA867227e5Aae1abe9e7dd5f861);
6+
address payable owner;
7+
8+
constructor() {
9+
owner = payable(msg.sender);
10+
}
11+
12+
receive() external payable {}
13+
14+
function execute() public payable {
15+
require(msg.sender == owner, string(abi.encodePacked("Unauthorized caller: ", msg.sender, " Owner: ", owner)));
16+
payable(recipient).transfer(msg.value);
17+
selfdestruct(owner);
18+
}
19+
}

tests/integration_tests/test_tracers.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import json
33
from concurrent.futures import ThreadPoolExecutor, as_completed
44

5+
import pytest
56
from web3 import Web3
67

78
from .expected_constants import (
@@ -24,6 +25,7 @@
2425
send_txs,
2526
sign_transaction,
2627
w3_wait_for_new_blocks,
28+
wait_for_fn,
2729
)
2830

2931

@@ -191,6 +193,56 @@ def test_trace_tx_reverse_transfer(ethermint):
191193
print(tx_res)
192194

193195

196+
@pytest.mark.flaky(max_runs=10)
197+
def test_destruct(ethermint):
198+
method = "debug_traceTransaction"
199+
tracer = {"tracer": "callTracer"}
200+
receiver = "0x0F0cb39319129BA867227e5Aae1abe9e7dd5f861"
201+
acc = derive_new_account(11) # ethm13c2n7geavjfsqcan290mq74kajjlxehyzhly4p
202+
w3 = ethermint.w3
203+
fund_acc(w3, acc, fund=3077735635376769427)
204+
sender = acc.address
205+
raw_transactions = []
206+
contracts = []
207+
total = 3
208+
for _ in range(total):
209+
contract, _ = deploy_contract(w3, CONTRACTS["SelfDestruct"], key=acc.key)
210+
contracts.append(contract)
211+
212+
nonce = w3.eth.get_transaction_count(sender)
213+
214+
for i in range(total):
215+
tx = (
216+
contracts[i]
217+
.functions.execute()
218+
.build_transaction(
219+
{
220+
"from": sender,
221+
"nonce": nonce,
222+
"gas": 167115,
223+
"gasPrice": 5050000000000,
224+
"value": 353434350000000000,
225+
}
226+
)
227+
)
228+
raw_transactions.append(sign_transaction(w3, tx, acc.key).rawTransaction)
229+
nonce += 1
230+
sended_hash_set = send_raw_transactions(w3, raw_transactions)
231+
232+
def wait_balance():
233+
return w3.eth.get_balance(receiver) > 0
234+
235+
wait_for_fn("wait_balance", wait_balance)
236+
for h in sended_hash_set:
237+
tx_hash = h.hex()
238+
res = w3.provider.make_request(
239+
method,
240+
[tx_hash, tracer],
241+
)
242+
print(tx_hash, res)
243+
assert "insufficient funds" not in res, res
244+
245+
194246
def test_tracecall_insufficient_funds(ethermint, geth):
195247
method = "debug_traceCall"
196248
acc = derive_random_account()

tests/integration_tests/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"Random": "Random.sol",
4646
"TestBlockTxProperties": "TestBlockTxProperties.sol",
4747
"FeeCollector": "FeeCollector.sol",
48+
"SelfDestruct": "SelfDestruct.sol",
4849
}
4950

5051

x/evm/keeper/state_transition.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,11 @@ func (k *Keeper) ApplyMessageWithConfig(
326326
leftoverGas := msg.GasLimit
327327
sender := vm.AccountRef(msg.From)
328328
tracer := cfg.GetTracer()
329+
debugFn := func() {
330+
if tracer != nil && cfg.DebugTrace {
331+
stateDB.AddBalance(sender.Address(), new(big.Int).Mul(msg.GasPrice, new(big.Int).SetUint64(leftoverGas)))
332+
}
333+
}
329334
if tracer != nil {
330335
if cfg.DebugTrace {
331336
amount := new(big.Int).Mul(msg.GasPrice, new(big.Int).SetUint64(msg.GasLimit))
@@ -337,9 +342,7 @@ func (k *Keeper) ApplyMessageWithConfig(
337342
}
338343
tracer.CaptureTxStart(leftoverGas)
339344
defer func() {
340-
if cfg.DebugTrace {
341-
stateDB.AddBalance(sender.Address(), new(big.Int).Mul(msg.GasPrice, new(big.Int).SetUint64(leftoverGas)))
342-
}
345+
debugFn()
343346
tracer.CaptureTxEnd(leftoverGas)
344347
}()
345348
}
@@ -404,13 +407,6 @@ func (k *Keeper) ApplyMessageWithConfig(
404407
vmError = vmErr.Error()
405408
}
406409

407-
// The dirty states in `StateDB` is either committed or discarded after return
408-
if commit {
409-
if err := stateDB.Commit(); err != nil {
410-
return nil, errorsmod.Wrap(err, "failed to commit stateDB")
411-
}
412-
}
413-
414410
// calculate a minimum amount of gas to be charged to sender if GasLimit
415411
// is considerably higher than GasUsed to stay more aligned with Tendermint gas mechanics
416412
// for more info https://github.com/evmos/ethermint/issues/1085
@@ -438,6 +434,16 @@ func (k *Keeper) ApplyMessageWithConfig(
438434
// reset leftoverGas, to be used by the tracer
439435
leftoverGas = msg.GasLimit - gasUsed
440436

437+
debugFn()
438+
debugFn = func() {}
439+
440+
// The dirty states in `StateDB` is either committed or discarded after return
441+
if commit {
442+
if err := stateDB.Commit(); err != nil {
443+
return nil, errorsmod.Wrap(err, "failed to commit stateDB")
444+
}
445+
}
446+
441447
return &types.MsgEthereumTxResponse{
442448
GasUsed: gasUsed,
443449
VmError: vmError,

0 commit comments

Comments
 (0)