ethereum / go-ethereum

Go implementation of the Ethereum protocol
https://geth.ethereum.org
GNU Lesser General Public License v3.0
47.52k stars 20.12k forks source link

Wrong debug_traceCall states diff prestateTracer results #30084

Closed fridary closed 4 months ago

fridary commented 4 months ago

System information

Version: 1.14.3-stable Git Commit: ab48ba42f4f34873d65fd1737fabac5c680baff6 Architecture: amd64 Go Version: go1.22.3 Geth command: /usr/bin/geth --datadir=/disk_sda/geth --syncmode snap --cache 4096 --ws --ws.origins "http://127.0.0.1" --http --port 40311 --authrpc.port 9551 --http.port 9545 --ws.port 9546 --http.api eth,debug,net,txpool,web3 --authrpc.jwtsecret=/disk_sda/geth/jwt.hex

CL client & version: Lighthouse v5.1.3-3058b96 OS & Version: Ubuntu 20.04.6 LTS, CPU E5-2695 v4, 36 cores, 192 Gb RAM Disk: NVMe HPE MT006400KWHAE 6.4 Tb Python: 3.11

behaviour

I am comparing state changes results with etherscan and Erigon, and Geth prints wrong results on all tranactions. Let's take https://etherscan.io/tx/0x760b9dec655dfee2bc06b443091ef257e753736f92a8caf0a14ae7799b5f9dc5#statechange I compare state results on builders addresses. Here is 0.00000422664333 state diff for beaverbuild. But Geth prints 0.000146000760003

Steps to reproduce the behaviour

Code results that compares results on Erigon and Geth nodes, both on same machine (but Erigon runs Caplin client). Erigon shows correct value 0.00000422664333 (comparing etherscan), but Geth shows wrong 0.000146000760003. You can easy test code on other transactions.

hash: 0x760b9dec655dfee2bc06b443091ef257e753736f92a8caf0a14ae7799b5f9dc5
testnet=http://127.0.0.1:8545 (Erigon)
{'id': 1,
 'jsonrpc': '2.0',
 'result': {'post': {'0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5': {'balance': '0xce5d3094ca2200e2'},
                     '0x974caa59e49682cda0ad2bbe82983419a2ecc400': {'balance': '0x5ec913a6e612ba391a'},
                     '0xbe0eb53f46cd790cd13851d5eff43d12404d33e8': {'balance': '0x1a6abd372645d6bdc0dcd',
                                                                    'nonce': 995}},
            'pre': {'0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5': {'balance': '0xce5d2cbcb28efd12',
                                                                   'nonce': 1123973},
                    '0x974caa59e49682cda0ad2bbe82983419a2ecc400': {'balance': '0x5ec7b09311c7fffad2',
                                                                   'nonce': 2758008},
                    '0xbe0eb53f46cd790cd13851d5eff43d12404d33e8': {'balance': '0x1a6abd4d5fcfb2a0625cd',
                                                                   'nonce': 994}}}}
0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5 beaverbuild found builder, diff=4226643330000 (0.00000422664333 ETH), before=14.870090733608434962 ETH, after=14.870094960251764962 ETH
------------------------------
testnet=http://127.0.0.1:9545 (Geth)
{'id': 1,
 'jsonrpc': '2.0',
 'result': {'post': {'0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5': {'balance': '0xce5db18625fed6ca'},
                     '0x974caa59e49682cda0ad2bbe82983419a2ecc400': {'balance': '0x5ec913a6e612ba391a'},
                     '0xbe0eb53f46cd790cd13851d5eff43d12404d33e8': {'balance': '0x1a6abd372645d6bdc0dcd',
                                                                    'nonce': 995}},
            'pre': {'0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5': {'balance': '0xce5d2cbcb28efd12',
                                                                   'nonce': 1123973},
                    '0x974caa59e49682cda0ad2bbe82983419a2ecc400': {'balance': '0x5ec7b09311c7fffad2',
                                                                   'nonce': 2758008},
                    '0xbe0eb53f46cd790cd13851d5eff43d12404d33e8': {'balance': '0x1a6abd4d5fcfb2a0625cd',
                                                                   'nonce': 994}}}}
0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5 beaverbuild found builder, diff=146000760003000 (0.000146000760003 ETH), before=14.870090733608434962 ETH, after=14.870236734368437962 ETH
------------------------------

Code:

import requests
from eth_utils import from_wei
from pprint import pprint

BUILDERS = {
    "0x388C818CA8B9251b393131C08a736A67ccB19297": "Lido: Execution Layer Rewards Vault",
    "0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5": "beaverbuild",
    "0x4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97": "Titan Builder",
    "0xdf99A0839818B3f120EBAC9B73f82B617Dc6A555": "Flashbots: Builder 2",
    "0x1f9090aaE28b8a3dCeaDf281B0F12828e676c326": "rsync-builder.eth"
}

def get_state_change(testnet, tx):
    traces = requests.post(testnet, json={
        'id': 1,
        'method': 'debug_traceCall',
        'jsonrpc': '2.0',
        'params': [
            {'to': tx['to'], 'gas': tx['gas'], 'gasPrice': tx['gasPrice'], 'value': tx['value'], 'data': tx['input'], 'from': tx['from']},
            tx['blockNumber'],
            {
                "tracer": "prestateTracer",
                "tracerConfig": {
                    "diffMode": True,
                    "withLog": True,
                    "onlyTopCall": False,
                },
            },

        ]
    }, headers={"Content-Type": "application/json"}).json()

    pprint(traces)

    if 'result' not in traces:
        exit("result not in traces")

    traces = traces['result']

    for builder_address, label in BUILDERS.items():
        for trace_address, data in traces['pre'].items():
            if trace_address == builder_address.lower():

                diff = int(traces['post'][trace_address]['balance'], 16) - int(traces['pre'][trace_address]['balance'], 16)
                print(f"{trace_address} {label} found builder, diff={diff} ({from_wei(abs(diff), 'ether')} ETH), before={from_wei(int(traces['pre'][trace_address]['balance'], 16), 'ether')} ETH, after={from_wei(int(traces['post'][trace_address]['balance'], 16), 'ether')} ETH")

if __name__ == '__main__':

    hash_ = '0x760b9dec655dfee2bc06b443091ef257e753736f92a8caf0a14ae7799b5f9dc5'
    print(f"hash: {hash_}")

    # http://127.0.0.1:8545 this address has Erigon node
    # http://127.0.0.1:9545 this address has Geth node
    for testnet in ['http://127.0.0.1:8545', 'http://127.0.0.1:9545']:

        print(f"testnet={testnet} ({'Erigon' if testnet == 'http://127.0.0.1:8545' else 'Geth'})")

        tx = requests.post(testnet, json={"method":"eth_getTransactionByHash","params":[hash_],"id":1,"jsonrpc":"2.0"}, headers={"Content-Type": "application/json"}).json()['result'] 
        tx['from'] = '0xBE0eB53F46cd790Cd13851d5EFf43D12404d33E8'.lower() # Binance 7 to be sure ETH balance is enough

        get_state_change(testnet=testnet, tx=tx)
        print('-'*30)
s1na commented 4 months ago

Maybe I'm missing something, but I don't understand why erigon and etherscan are showing the difference in balance to be 0.00000422664333.

It is a simple transfer tx. The builder receives the transaction fees, that's the only way it's balance should be modified. As per etherscan itself the transaction fee is 0.000146000760003 which is the same value geth returns. I confirmed by doing 21000 * 6952417143 since it's a legacy transaction.

Edit: Ok I think I know. We are not reducing the burnt fee.

s1na commented 4 months ago

I have been trying to reproduce this locally with no luck. I tried submitting a legacy transfer on a devnet and doing traceCall like in the example above. The balance is updated as it should be. Base fee of block number 2 is 766024067.

debug.traceCall({ from: eth.accounts[0], to: '0x1111111111111111111111111111111111111111', value: '0x5', gasPrice: '0x342770c1' }, '0x2', { tracer: 'prestateTracer', tracerConfig: { diffMode: true } })
{
  post: {
    0x0000000000000000000000000000000000000000: {
      balance: "0x429a9d17de8"
    },
    0x01d5b4c6722015be2d0b5cc52a7b731dc6d5bc28: {
      balance: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffcddd35f3f7d0",
      nonce: 3
    },
    0x1111111111111111111111111111111111111111: {
      balance: "0xf"
    }
  },
  pre: {
    0x0000000000000000000000000000000000000000: {
      balance: "0x214d4e8e7f8"
    },
    0x01d5b4c6722015be2d0b5cc52a7b731dc6d5bc28: {
      balance: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffde93794d4fdd",
      nonce: 2
    },
    0x1111111111111111111111111111111111111111: {
      balance: "0xa"
    }
  }
}

As we can see:

>>> 875000001 - 766024067
108975934 // effectiveGasPrice
>>> 108975934 * 2100
228849461400 // Total fee

>>> 0x429a9d17de8 - 0x214d4e8e7f8
2288494614000 // miner post - pre balance
fridary commented 4 months ago

@s1na thank you for try. Can you please make a call on transaction that is in etherscan like I did? So I can compare etherscan results, your results and mine results. Your transaction example is different than mine.

fridary commented 4 months ago

Can someone please check my transaction example above? Error is critical

s1na commented 4 months ago

The transaction you linked is a legacy type transaction (type 0). Can you confirm that those transactions return a wrong result? or have you also observed the same issue in type 2 transactions?

fridary commented 4 months ago

@s1na I can confirm those transactions return wrong results, I checked on many other transactions where is Uniswap buy/sell token executes. Type 2 transactions are just simple Transfer()?

s1na commented 4 months ago

I still haven't been able to reproduce this. I don't know how you're saying its wrong for all transactions... Take this tx: https://etherscan.io/tx/0x38fe0db5b641513a3f98f08b9d5ff5e6decf0574de92d1366dcb6d33409590c2#statechange

When I trace it:

> debug.traceCall({ from: '0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5', to: tx.to, gas: web3.toHex(tx.gas), gasPrice: web3.toHex(tx.gasPrice), value: web3.toHex(tx.value) }, web3.toHex(tx.blockNumber), { tracer: 'prestateTracer', tracerConfig: { diffMode: true } })
{
  post: {
    0x1647a050294a5d5a1d42d34234a3bd5533b04e4a: {
      balance: "0x21ecc9447b5e53"
    },
    0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97: {
      balance: "0xb26045a85e1dab63"
    },
    0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5: {
      balance: "0x744accd8983c3f9a",
      nonce: 1143967
    }
  },
  pre: {
    0x1647a050294a5d5a1d42d34234a3bd5533b04e4a: {
      balance: "0x13e87dcfd60853",
      nonce: 5
    },
    0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97: {
      balance: "0xb25e5275cd127d73",
      nonce: 447381
    },
    0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5: {
      balance: "0x745c215a7d23125a",
      nonce: 1143966
    }
  }
}

Here the producer's (0x4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97) balance is increased by 548873484054000 same as etherscan reports.

Re transaction type you can check it on etherscan, it will tell you which type it is at bottom.

jsvisa commented 4 months ago

I compare state results on builders addresses. Here is 0.00000422664333 state diff for beaverbuild. But Geth prints 0.000146000760003

@fridary I think the result is because the burned_fee was not subtracted:

tx_fee = 21000*6.952417143GW = 0.000146000760003ETH
burned_fee = 0.000141774116673ETH

miner's balance = 0.000146000760003ETH - 0.000141774116673ETH = 0.00000422664333ETH
fridary commented 4 months ago

@jsvisa how can I calculate/find/query burned fee? I did not understand your example where you got it. Or burned fee is just a block's base fee? My example transaction has block 20185214 and it's baseFeePerGas is 6751148413 (not 0.000141774116673ETH)

jsvisa commented 4 months ago

@jsvisa how can I calculate/find/query burned fee? I did not understand your example where you got it. Or burned fee is just a block's base fee? My example transaction has block 20185214 and it's baseFeePerGas is 6751148413 (not 0.000141774116673ETH)

6751148413wei*21000

Could you reproduce the result?

fridary commented 4 months ago

@jsvisa 6751148413wei*21000=141774116673000=0,000141774116673ETH now it works, thanks.