eth/tracers: fix prestate diff mode bugs for EIP-7702 deauthorization

This commit is contained in:
allen 2026-04-05 23:10:48 -04:00
parent d8cb8a962b
commit 1c6721da97
3 changed files with 118 additions and 13 deletions

View file

@ -29,8 +29,11 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/tests"
"github.com/holiman/uint256"
)
// prestateTrace is the result of a prestateTrace run.
@ -49,6 +52,102 @@ type prestateTracerTest struct {
Result interface{} `json:"result"`
}
func TestPrestateWithDiffMode_7702Deauth(t *testing.T) {
chainConfig := params.AllDevChainProtocolChanges
authorityKey, _ := crypto.GenerateKey()
senderKey, _ := crypto.GenerateKey()
authorityAddr := crypto.PubkeyToAddress(authorityKey.PublicKey)
senderAddr := crypto.PubkeyToAddress(senderKey.PublicKey)
delegateTarget := common.HexToAddress("0x000000000000000000000000000000000000aaaa")
genesis := &core.Genesis{
Config: chainConfig,
BaseFee: big.NewInt(params.InitialBaseFee),
GasLimit: 8000000,
Alloc: types.GenesisAlloc{
authorityAddr: {
Balance: big.NewInt(1e18),
Code: types.AddressToDelegation(delegateTarget),
},
senderAddr: {
Balance: big.NewInt(1e18),
},
},
}
signer := types.LatestSignerForChainID(chainConfig.ChainID)
auth, err := types.SignSetCode(authorityKey, types.SetCodeAuthorization{
ChainID: *uint256.MustFromBig(chainConfig.ChainID),
Address: common.Address{},
Nonce: 0,
})
if err != nil {
t.Fatalf("failed to sign authorization: %v", err)
}
tx := types.MustSignNewTx(senderKey, signer, &types.SetCodeTx{
ChainID: uint256.MustFromBig(chainConfig.ChainID),
Nonce: 0,
GasFeeCap: uint256.NewInt(params.InitialBaseFee * 2),
GasTipCap: uint256.NewInt(1),
Gas: 100000,
To: senderAddr,
AuthList: []types.SetCodeAuthorization{auth},
})
state := tests.MakePreState(rawdb.NewMemoryDatabase(), genesis.Alloc, false, rawdb.HashScheme)
defer state.Close()
tracerCfg := json.RawMessage(`{"diffMode":true}`)
tracer, err := tracers.DefaultDirectory.New("prestateTracer", new(tracers.Context), tracerCfg, chainConfig)
if err != nil {
t.Fatalf("failed to create tracer: %v", err)
}
blockCtx := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
BlockNumber: big.NewInt(1),
Time: 0,
GasLimit: 8000000,
BaseFee: big.NewInt(params.InitialBaseFee),
}
msg, err := core.TransactionToMessage(tx, signer, blockCtx.BaseFee)
if err != nil {
t.Fatalf("failed to convert tx to message: %v", err)
}
evm := vm.NewEVM(blockCtx, state.StateDB, chainConfig, vm.Config{Tracer: tracer.Hooks})
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
vmRet, err := core.ApplyMessage(evm, msg, nil)
if err != nil {
t.Fatalf("failed to apply message: %v", err)
}
tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil)
res, err := tracer.GetResult()
if err != nil {
t.Fatalf("failed to get result: %v", err)
}
var result struct {
Post map[common.Address]json.RawMessage `json:"post"`
}
if err := json.Unmarshal(res, &result); err != nil {
t.Fatalf("failed to unmarshal result: %v", err)
}
postRaw, ok := result.Post[authorityAddr]
if !ok {
t.Fatalf("authority address not found in post state; full result: %s", res)
}
var postAccount struct {
Code string `json:"code"`
CodeHash string `json:"codeHash"`
}
if err := json.Unmarshal(postRaw, &postAccount); err != nil {
t.Fatalf("failed to unmarshal post account: %v", err)
}
if postAccount.Code != "0x" {
t.Errorf("post code: got %q, want %q", postAccount.Code, "0x")
}
wantCodeHash := types.EmptyCodeHash.Hex()
if postAccount.CodeHash != wantCodeHash {
t.Errorf("post codeHash: got %q, want %q", postAccount.CodeHash, wantCodeHash)
}
}
func TestPrestateTracerLegacy(t *testing.T) {
testPrestateTracer("prestateTracerLegacy", "prestate_tracer_legacy", t)
}

View file

@ -16,14 +16,17 @@ var _ = (*accountMarshaling)(nil)
func (a account) MarshalJSON() ([]byte, error) {
type account struct {
Balance *hexutil.Big `json:"balance,omitempty"`
Code hexutil.Bytes `json:"code,omitempty"`
Code *hexutil.Bytes `json:"code,omitempty"`
CodeHash *common.Hash `json:"codeHash,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
}
var enc account
enc.Balance = (*hexutil.Big)(a.Balance)
enc.Code = a.Code
if a.codeChanged || len(a.Code) > 0 {
code := hexutil.Bytes(a.Code)
enc.Code = &code
}
enc.CodeHash = a.CodeHash
enc.Nonce = a.Nonce
enc.Storage = a.Storage

View file

@ -44,12 +44,13 @@ func init() {
type stateMap = map[common.Address]*account
type account struct {
Balance *big.Int `json:"balance,omitempty"`
Code []byte `json:"code,omitempty"`
CodeHash *common.Hash `json:"codeHash,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
empty bool
Balance *big.Int `json:"balance,omitempty"`
Code []byte `json:"code,omitempty"`
CodeHash *common.Hash `json:"codeHash,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
empty bool
codeChanged bool // code was changed in diff post-state
}
func (a *account) exists() bool {
@ -270,12 +271,13 @@ func (t *prestateTracer) processDiffState() {
if t.pre[addr].CodeHash != nil {
prevCodeHash = *t.pre[addr].CodeHash
}
// Empty code hashes are excluded from the prestate. Normalize
// the empty code hash to a zero hash to make it comparable.
if newCodeHash == types.EmptyCodeHash {
newCodeHash = common.Hash{}
// Empty code hashes are excluded from the prestate. Use a normalized
// copy only for comparison; keep the original value for post-state output.
normalizedNewCodeHash := newCodeHash
if normalizedNewCodeHash == types.EmptyCodeHash {
normalizedNewCodeHash = common.Hash{}
}
if newCodeHash != prevCodeHash {
if normalizedNewCodeHash != prevCodeHash {
modified = true
postAccount.CodeHash = &newCodeHash
}
@ -284,6 +286,7 @@ func (t *prestateTracer) processDiffState() {
if !bytes.Equal(newCode, t.pre[addr].Code) {
modified = true
postAccount.Code = newCode
postAccount.codeChanged = true
}
}