mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-16 03:41:35 +00:00
eth/tracers: fix prestate diff mode bugs for EIP-7702 deauthorization
This commit is contained in:
parent
d8cb8a962b
commit
c1b800ca29
3 changed files with 120 additions and 13 deletions
|
|
@ -29,8 +29,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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/eth/tracers"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/tests"
|
"github.com/ethereum/go-ethereum/tests"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// prestateTrace is the result of a prestateTrace run.
|
// prestateTrace is the result of a prestateTrace run.
|
||||||
|
|
@ -49,6 +52,102 @@ type prestateTracerTest struct {
|
||||||
Result interface{} `json:"result"`
|
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) {
|
func TestPrestateTracerLegacy(t *testing.T) {
|
||||||
testPrestateTracer("prestateTracerLegacy", "prestate_tracer_legacy", t)
|
testPrestateTracer("prestateTracerLegacy", "prestate_tracer_legacy", t)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ var _ = (*accountMarshaling)(nil)
|
||||||
func (a account) MarshalJSON() ([]byte, error) {
|
func (a account) MarshalJSON() ([]byte, error) {
|
||||||
type account struct {
|
type account struct {
|
||||||
Balance *hexutil.Big `json:"balance,omitempty"`
|
Balance *hexutil.Big `json:"balance,omitempty"`
|
||||||
Code hexutil.Bytes `json:"code,omitempty"`
|
Code *hexutil.Bytes `json:"code,omitempty"`
|
||||||
CodeHash *common.Hash `json:"codeHash,omitempty"`
|
CodeHash *common.Hash `json:"codeHash,omitempty"`
|
||||||
Nonce uint64 `json:"nonce,omitempty"`
|
Nonce uint64 `json:"nonce,omitempty"`
|
||||||
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
||||||
|
|
@ -47,7 +47,7 @@ func (a *account) UnmarshalJSON(input []byte) error {
|
||||||
a.Balance = (*big.Int)(dec.Balance)
|
a.Balance = (*big.Int)(dec.Balance)
|
||||||
}
|
}
|
||||||
if dec.Code != nil {
|
if dec.Code != nil {
|
||||||
a.Code = *dec.Code
|
a.Code = dec.Code
|
||||||
}
|
}
|
||||||
if dec.CodeHash != nil {
|
if dec.CodeHash != nil {
|
||||||
a.CodeHash = dec.CodeHash
|
a.CodeHash = dec.CodeHash
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ type stateMap = map[common.Address]*account
|
||||||
|
|
||||||
type account struct {
|
type account struct {
|
||||||
Balance *big.Int `json:"balance,omitempty"`
|
Balance *big.Int `json:"balance,omitempty"`
|
||||||
Code []byte `json:"code,omitempty"`
|
Code *hexutil.Bytes `json:"code,omitempty"`
|
||||||
CodeHash *common.Hash `json:"codeHash,omitempty"`
|
CodeHash *common.Hash `json:"codeHash,omitempty"`
|
||||||
Nonce uint64 `json:"nonce,omitempty"`
|
Nonce uint64 `json:"nonce,omitempty"`
|
||||||
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
||||||
|
|
@ -53,12 +53,11 @@ type account struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *account) exists() bool {
|
func (a *account) exists() bool {
|
||||||
return a.Nonce > 0 || len(a.Code) > 0 || len(a.Storage) > 0 || (a.Balance != nil && a.Balance.Sign() != 0)
|
return a.Nonce > 0 || (a.Code != nil && len(*a.Code) > 0) || len(a.Storage) > 0 || (a.Balance != nil && a.Balance.Sign() != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
type accountMarshaling struct {
|
type accountMarshaling struct {
|
||||||
Balance *hexutil.Big
|
Balance *hexutil.Big
|
||||||
Code hexutil.Bytes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type prestateTracer struct {
|
type prestateTracer struct {
|
||||||
|
|
@ -270,20 +269,26 @@ func (t *prestateTracer) processDiffState() {
|
||||||
if t.pre[addr].CodeHash != nil {
|
if t.pre[addr].CodeHash != nil {
|
||||||
prevCodeHash = *t.pre[addr].CodeHash
|
prevCodeHash = *t.pre[addr].CodeHash
|
||||||
}
|
}
|
||||||
// Empty code hashes are excluded from the prestate. Normalize
|
// Empty code hashes are excluded from the prestate. Use a normalized
|
||||||
// the empty code hash to a zero hash to make it comparable.
|
// copy only for comparison; keep the original value for post-state output.
|
||||||
if newCodeHash == types.EmptyCodeHash {
|
normalizedNewCodeHash := newCodeHash
|
||||||
newCodeHash = common.Hash{}
|
if normalizedNewCodeHash == types.EmptyCodeHash {
|
||||||
|
normalizedNewCodeHash = common.Hash{}
|
||||||
}
|
}
|
||||||
if newCodeHash != prevCodeHash {
|
if normalizedNewCodeHash != prevCodeHash {
|
||||||
modified = true
|
modified = true
|
||||||
postAccount.CodeHash = &newCodeHash
|
postAccount.CodeHash = &newCodeHash
|
||||||
}
|
}
|
||||||
if !t.config.DisableCode {
|
if !t.config.DisableCode {
|
||||||
newCode := t.env.StateDB.GetCode(addr)
|
newCode := t.env.StateDB.GetCode(addr)
|
||||||
if !bytes.Equal(newCode, t.pre[addr].Code) {
|
var preCode []byte
|
||||||
|
if t.pre[addr].Code != nil {
|
||||||
|
preCode = []byte(*t.pre[addr].Code)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(newCode, preCode) {
|
||||||
modified = true
|
modified = true
|
||||||
postAccount.Code = newCode
|
hcode := hexutil.Bytes(newCode)
|
||||||
|
postAccount.Code = &hcode // non-nil even if empty, so "0x" is output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,7 +331,10 @@ func (t *prestateTracer) lookupAccount(addr common.Address) {
|
||||||
acc := &account{
|
acc := &account{
|
||||||
Balance: t.env.StateDB.GetBalance(addr).ToBig(),
|
Balance: t.env.StateDB.GetBalance(addr).ToBig(),
|
||||||
Nonce: t.env.StateDB.GetNonce(addr),
|
Nonce: t.env.StateDB.GetNonce(addr),
|
||||||
Code: t.env.StateDB.GetCode(addr),
|
}
|
||||||
|
if code := t.env.StateDB.GetCode(addr); len(code) > 0 {
|
||||||
|
hcode := hexutil.Bytes(code)
|
||||||
|
acc.Code = &hcode
|
||||||
}
|
}
|
||||||
codeHash := t.env.StateDB.GetCodeHash(addr)
|
codeHash := t.env.StateDB.GetCodeHash(addr)
|
||||||
// If the code is empty, we don't need to store it in the prestate.
|
// If the code is empty, we don't need to store it in the prestate.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue