From 4b09d8ad58f6dd514715b3d02919516ae6beb5c1 Mon Sep 17 00:00:00 2001 From: Arun Dhyani Date: Mon, 25 Nov 2024 15:31:46 +0530 Subject: [PATCH] feat: tracing hooks added to stateDB (#10915) - This PR is created to from the [tracing hook implementation PR ](https://github.com/ledgerwatch/erigon/pull/10757) to simplify it's review and merge process. - In this PR, we have plugged tracing hook framework to the statedb. --- core/state/cached_reader.go | 5 + core/state/cached_reader3.go | 17 + core/state/database.go | 1 + core/state/history_reader_v3.go | 6 + core/state/intra_block_state.go | 42 +- core/state/intra_block_state_logger_test.go | 139 ++++++ core/state/rw_v3.go | 28 ++ core/state/state_object.go | 12 + core/tracing/mocks/hooks.go | 525 ++++++++++++++++++++ core/vm/evmtypes/evmtypes.go | 2 + tests/execution-spec-tests | 1 - 11 files changed, 773 insertions(+), 5 deletions(-) create mode 100644 core/state/intra_block_state_logger_test.go create mode 100644 core/tracing/mocks/hooks.go delete mode 160000 tests/execution-spec-tests diff --git a/core/state/cached_reader.go b/core/state/cached_reader.go index 133571a6751..629c1d0da09 100644 --- a/core/state/cached_reader.go +++ b/core/state/cached_reader.go @@ -53,6 +53,11 @@ func (cr *CachedReader) ReadAccountData(address common.Address) (*accounts.Accou return a, nil } +// ReadAccountDataForDebug is called when an account needs to be fetched from the state +func (cr *CachedReader) ReadAccountDataForDebug(address common.Address) (*accounts.Account, error) { + return cr.ReadAccountData(address) +} + // ReadAccountStorage is called when a storage item needs to be fetched from the state func (cr *CachedReader) ReadAccountStorage(address common.Address, incarnation uint64, key *common.Hash) ([]byte, error) { addrBytes := address.Bytes() diff --git a/core/state/cached_reader3.go b/core/state/cached_reader3.go index 192c145bef5..81f2e18a7d6 100644 --- a/core/state/cached_reader3.go +++ b/core/state/cached_reader3.go @@ -54,6 +54,23 @@ func (r *CachedReader3) ReadAccountData(address common.Address) (*accounts.Accou return &a, nil } +// ReadAccountDataForDebug - is like ReadAccountData, but without adding key to `readList`. +// Used to get `prev` account balance +func (r *CachedReader3) ReadAccountDataForDebug(address common.Address) (*accounts.Account, error) { + enc, err := r.cache.Get(address[:]) + if err != nil { + return nil, err + } + if len(enc) == 0 { + return nil, nil + } + a := accounts.Account{} + if err = accounts.DeserialiseV3(&a, enc); err != nil { + return nil, err + } + return &a, nil +} + func (r *CachedReader3) ReadAccountStorage(address common.Address, incarnation uint64, key *common.Hash) ([]byte, error) { compositeKey := append(address[:], key.Bytes()...) enc, err := r.cache.Get(compositeKey) diff --git a/core/state/database.go b/core/state/database.go index b32feaa476d..f99f7516451 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -37,6 +37,7 @@ const ( type StateReader interface { ReadAccountData(address common.Address) (*accounts.Account, error) + ReadAccountDataForDebug(address common.Address) (*accounts.Account, error) ReadAccountStorage(address common.Address, incarnation uint64, key *common.Hash) ([]byte, error) ReadAccountCode(address common.Address, incarnation uint64, codeHash common.Hash) ([]byte, error) ReadAccountCodeSize(address common.Address, incarnation uint64, codeHash common.Hash) (int, error) diff --git a/core/state/history_reader_v3.go b/core/state/history_reader_v3.go index f143cdeb870..d404d1ba82d 100644 --- a/core/state/history_reader_v3.go +++ b/core/state/history_reader_v3.go @@ -72,6 +72,12 @@ func (hr *HistoryReaderV3) ReadAccountData(address common.Address) (*accounts.Ac return &a, nil } +// ReadAccountDataForDebug - is like ReadAccountData, but without adding key to `readList`. +// Used to get `prev` account balance +func (hr *HistoryReaderV3) ReadAccountDataForDebug(address common.Address) (*accounts.Account, error) { + return hr.ReadAccountData(address) +} + func (hr *HistoryReaderV3) ReadAccountStorage(address common.Address, incarnation uint64, key *common.Hash) ([]byte, error) { k := append(address[:], key.Bytes()...) enc, _, err := hr.ttx.GetAsOf(kv.StorageDomain, k, nil, hr.txNum) diff --git a/core/state/intra_block_state.go b/core/state/intra_block_state.go index 6eb224c7bb1..ff09d7ead60 100644 --- a/core/state/intra_block_state.go +++ b/core/state/intra_block_state.go @@ -96,6 +96,7 @@ type IntraBlockState struct { validRevisions []revision nextRevisionID int trace bool + tracingHooks *tracing.Hooks balanceInc map[libcommon.Address]*BalanceIncrease // Map of balance increases (without first reading the account) } @@ -116,6 +117,10 @@ func New(stateReader StateReader) *IntraBlockState { } } +func (sdb *IntraBlockState) SetHooks(hooks *tracing.Hooks) { + sdb.tracingHooks = hooks +} + func (sdb *IntraBlockState) SetTrace(trace bool) { sdb.trace = trace } @@ -167,6 +172,9 @@ func (sdb *IntraBlockState) AddLog(log2 *types.Log) { sdb.journal.append(addLogChange{txIndex: sdb.txIndex}) log2.TxIndex = uint(sdb.txIndex) log2.Index = sdb.logSize + if sdb.tracingHooks != nil && sdb.tracingHooks.OnLog != nil { + sdb.tracingHooks.OnLog(log2) + } sdb.logSize++ for len(sdb.logs) <= sdb.txIndex { sdb.logs = append(sdb.logs, nil) @@ -383,6 +391,7 @@ func (sdb *IntraBlockState) AddBalance(addr libcommon.Address, amount *uint256.I if sdb.trace { fmt.Printf("AddBalance %x, %d\n", addr, amount) } + // If this account has not been read, add to the balance increment map _, needAccount := sdb.stateObjects[addr] if !needAccount && addr == ripemd && amount.IsZero() { @@ -393,11 +402,26 @@ func (sdb *IntraBlockState) AddBalance(addr libcommon.Address, amount *uint256.I account: &addr, increase: *amount, }) + bi, ok := sdb.balanceInc[addr] if !ok { bi = &BalanceIncrease{} sdb.balanceInc[addr] = bi } + + if sdb.tracingHooks != nil && sdb.tracingHooks.OnBalanceChange != nil { + // TODO: discuss if we should ignore error + prev := new(uint256.Int) + account, _ := sdb.stateReader.ReadAccountDataForDebug(addr) + if account != nil { + prev.Add(&account.Balance, &bi.increase) + } else { + prev.Add(prev, &bi.increase) + } + + sdb.tracingHooks.OnBalanceChange(addr, prev, new(uint256.Int).Add(prev, amount), reason) + } + bi.increase.Add(&bi.increase, amount) bi.count++ return @@ -488,11 +512,18 @@ func (sdb *IntraBlockState) Selfdestruct(addr libcommon.Address) bool { if stateObject == nil || stateObject.deleted { return false } + + prevBalance := *stateObject.Balance() sdb.journal.append(selfdestructChange{ account: &addr, prev: stateObject.selfdestructed, - prevbalance: *stateObject.Balance(), + prevbalance: prevBalance, }) + + if sdb.tracingHooks != nil && sdb.tracingHooks.OnBalanceChange != nil && !prevBalance.IsZero() { + sdb.tracingHooks.OnBalanceChange(addr, &prevBalance, uint256.NewInt(0), tracing.BalanceDecreaseSelfdestruct) + } + stateObject.markSelfdestructed() stateObject.createdContract = false stateObject.data.Balance.Clear() @@ -684,9 +715,12 @@ func (sdb *IntraBlockState) GetRefund() uint64 { return sdb.refund } -func updateAccount(EIP161Enabled bool, isAura bool, stateWriter StateWriter, addr libcommon.Address, stateObject *stateObject, isDirty bool) error { +func updateAccount(EIP161Enabled bool, isAura bool, stateWriter StateWriter, addr libcommon.Address, stateObject *stateObject, isDirty bool, tracingHooks *tracing.Hooks) error { emptyRemoval := EIP161Enabled && stateObject.empty() && (!isAura || addr != SystemAddress) if stateObject.selfdestructed || (isDirty && emptyRemoval) { + if tracingHooks != nil && tracingHooks.OnBalanceChange != nil && !stateObject.Balance().IsZero() && stateObject.selfdestructed { + tracingHooks.OnBalanceChange(stateObject.address, stateObject.Balance(), uint256.NewInt(0), tracing.BalanceDecreaseSelfdestructBurn) + } if err := stateWriter.DeleteAccount(addr, &stateObject.original); err != nil { return err } @@ -758,7 +792,7 @@ func (sdb *IntraBlockState) FinalizeTx(chainRules *chain.Rules, stateWriter Stat } //fmt.Printf("FinalizeTx: %x, balance=%d %T\n", addr, so.data.Balance.Uint64(), stateWriter) - if err := updateAccount(chainRules.IsSpuriousDragon, chainRules.IsAura, stateWriter, addr, so, true); err != nil { + if err := updateAccount(chainRules.IsSpuriousDragon, chainRules.IsAura, stateWriter, addr, so, true, sdb.tracingHooks); err != nil { return err } so.newlyCreated = false @@ -814,7 +848,7 @@ func (sdb *IntraBlockState) MakeWriteSet(chainRules *chain.Rules, stateWriter St } for addr, stateObject := range sdb.stateObjects { _, isDirty := sdb.stateObjectsDirty[addr] - if err := updateAccount(chainRules.IsSpuriousDragon, chainRules.IsAura, stateWriter, addr, stateObject, isDirty); err != nil { + if err := updateAccount(chainRules.IsSpuriousDragon, chainRules.IsAura, stateWriter, addr, stateObject, isDirty, sdb.tracingHooks); err != nil { return err } } diff --git a/core/state/intra_block_state_logger_test.go b/core/state/intra_block_state_logger_test.go new file mode 100644 index 00000000000..11c5023c940 --- /dev/null +++ b/core/state/intra_block_state_logger_test.go @@ -0,0 +1,139 @@ +// Copyright 2024 The Erigon Authors +// This file is part of Erigon. +// +// Erigon is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Erigon is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Erigon. If not, see . + +package state + +import ( + "reflect" + "testing" + + libcommon "github.com/erigontech/erigon-lib/common" + "github.com/erigontech/erigon-lib/kv/rawdbv3" + "github.com/erigontech/erigon-lib/log/v3" + stateLib "github.com/erigontech/erigon-lib/state" + + "github.com/erigontech/erigon/core/tracing" + "github.com/erigontech/erigon/core/tracing/mocks" + + "github.com/holiman/uint256" + "github.com/stretchr/testify/require" + gomock "go.uber.org/mock/gomock" +) + +func TestStateLogger(t *testing.T) { + t.Parallel() + + cases := []struct { + name string + prepare func(mockTracer *mocks.Mocktracer) + run func(state *IntraBlockState) + checker func(t *testing.T, state *IntraBlockState) + }{ + { + name: "multiple add balance", + prepare: func(mockTracer *mocks.Mocktracer) { + mockTracer.EXPECT().BalanceChangeHook(libcommon.Address{}, uint256.NewInt(0), uint256.NewInt(2), tracing.BalanceChangeUnspecified) + mockTracer.EXPECT().BalanceChangeHook(libcommon.Address{}, uint256.NewInt(2), uint256.NewInt(3), tracing.BalanceChangeUnspecified) + }, + run: func(state *IntraBlockState) { + state.AddBalance(libcommon.Address{}, uint256.NewInt(2), tracing.BalanceChangeUnspecified) + state.AddBalance(libcommon.Address{}, uint256.NewInt(1), tracing.BalanceChangeUnspecified) + }, + checker: func(t *testing.T, stateDB *IntraBlockState) { + bi, ok := stateDB.balanceInc[libcommon.Address{}] + if !ok { + t.Errorf("%s isn't present in balanceInc", libcommon.Address{}) + } + + if !reflect.DeepEqual(&bi.increase, uint256.NewInt(3)) { + t.Errorf("Incorrect BalanceInc for %s expectedBalance: %s, got:%s", libcommon.Address{}, uint256.NewInt(3), &bi.increase) + } + + if bi.count != 2 { + t.Errorf("Incorrect BalanceInc count for %s expected: %d, got:%d", libcommon.Address{}, 2, bi.count) + } + + if len(stateDB.journal.entries) != 2 { + t.Errorf("Incorrect number of jounal entries expectedBalance: %d, got:%d", 2, len(stateDB.journal.entries)) + } + for i := range stateDB.journal.entries { + switch balanceInc := stateDB.journal.entries[i].(type) { + case balanceIncrease: + var expectedInc *uint256.Int + if i == 0 { + expectedInc = uint256.NewInt(2) + } else { + expectedInc = uint256.NewInt(1) + } + if !reflect.DeepEqual(&balanceInc.increase, expectedInc) { + t.Errorf("Incorrect BalanceInc in jounal for %s expectedBalance: %s, got:%s", libcommon.Address{}, expectedInc, &balanceInc.increase) + } + default: + t.Errorf("Invalid journal entry found: %s", reflect.TypeOf(stateDB.journal.entries[i])) + } + } + + so := stateDB.GetOrNewStateObject(libcommon.Address{}) + if !reflect.DeepEqual(so.Balance(), uint256.NewInt(3)) { + t.Errorf("Incorrect Balance for %s expectedBalance: %s, got:%s", libcommon.Address{}, uint256.NewInt(3), so.Balance()) + } + }, + }, + { + name: "sub balance", + prepare: func(mockTracer *mocks.Mocktracer) { + mockTracer.EXPECT().BalanceChangeHook(libcommon.Address{}, uint256.NewInt(0), uint256.NewInt(2), tracing.BalanceChangeUnspecified) + mockTracer.EXPECT().BalanceChangeHook(libcommon.Address{}, uint256.NewInt(2), uint256.NewInt(1), tracing.BalanceChangeUnspecified) + }, + run: func(state *IntraBlockState) { + state.AddBalance(libcommon.Address{}, uint256.NewInt(2), tracing.BalanceChangeUnspecified) + state.SubBalance(libcommon.Address{}, uint256.NewInt(1), tracing.BalanceChangeUnspecified) + }, + checker: func(t *testing.T, stateDB *IntraBlockState) { + so := stateDB.GetOrNewStateObject(libcommon.Address{}) + if !reflect.DeepEqual(so.Balance(), uint256.NewInt(1)) { + t.Errorf("Incorrect Balance for %s expectedBalance: %s, got:%s", libcommon.Address{}, uint256.NewInt(1), so.Balance()) + } + }, + }, + } + + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + _, tx, _ := NewTestTemporalDb(t) + + domains, err := stateLib.NewSharedDomains(tx, log.New()) + require.NoError(t, err) + defer domains.Close() + + domains.SetTxNum(1) + domains.SetBlockNum(1) + err = rawdbv3.TxNums.Append(tx, 1, 1) + require.NoError(t, err) + + mockCtl := gomock.NewController(t) + defer mockCtl.Finish() + mockTracer := mocks.NewMocktracer(mockCtl) + + state := New(NewReaderV3(domains)) + state.SetHooks(mockTracer.Hooks()) + + tt.prepare(mockTracer) + tt.run(state) + tt.checker(t, state) + }) + } +} diff --git a/core/state/rw_v3.go b/core/state/rw_v3.go index b4d488bfc17..56c438bc975 100644 --- a/core/state/rw_v3.go +++ b/core/state/rw_v3.go @@ -608,6 +608,10 @@ func (r *ReaderV3) ReadAccountData(address common.Address) (*accounts.Account, e return &acc, nil } +func (r *ReaderV3) ReadAccountDataForDebug(address common.Address) (*accounts.Account, error) { + return r.ReadAccountData(address) +} + func (r *ReaderV3) ReadAccountStorage(address common.Address, incarnation uint64, key *common.Hash) ([]byte, error) { r.composite = append(append(r.composite[:0], address[:]...), key.Bytes()...) enc, _, err := r.tx.GetLatest(kv.StorageDomain, r.composite, nil) @@ -706,6 +710,30 @@ func (r *ReaderParallelV3) ReadAccountData(address common.Address) (*accounts.Ac return &acc, nil } +// ReadAccountDataForDebug - is like ReadAccountData, but without adding key to `readList`. +// Used to get `prev` account balance +func (r *ReaderParallelV3) ReadAccountDataForDebug(address common.Address) (*accounts.Account, error) { + enc, _, err := r.sd.GetLatest(kv.AccountsDomain, address[:], nil) + if err != nil { + return nil, err + } + if len(enc) == 0 { + if r.trace { + fmt.Printf("ReadAccountData [%x] => [empty], txNum: %d\n", address, r.txNum) + } + return nil, nil + } + + var acc accounts.Account + if err := accounts.DeserialiseV3(&acc, enc); err != nil { + return nil, err + } + if r.trace { + fmt.Printf("ReadAccountData [%x] => [nonce: %d, balance: %d, codeHash: %x], txNum: %d\n", address, acc.Nonce, &acc.Balance, acc.CodeHash, r.txNum) + } + return &acc, nil +} + func (r *ReaderParallelV3) ReadAccountStorage(address common.Address, incarnation uint64, key *common.Hash) ([]byte, error) { r.composite = append(append(r.composite[:0], address[:]...), key.Bytes()...) enc, _, err := r.sd.GetLatest(kv.StorageDomain, r.composite, nil) diff --git a/core/state/state_object.go b/core/state/state_object.go index 685babb668f..00f52adf149 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -222,6 +222,9 @@ func (so *stateObject) SetState(key *libcommon.Hash, value uint256.Int) { key: *key, prevalue: prev, }) + if so.db.tracingHooks != nil && so.db.tracingHooks.OnStorageChange != nil { + so.db.tracingHooks.OnStorageChange(so.address, key, prev, value) + } so.setState(key, value) } @@ -295,6 +298,9 @@ func (so *stateObject) SetBalance(amount *uint256.Int, reason tracing.BalanceCha account: &so.address, prev: so.data.Balance, }) + if so.db.tracingHooks != nil && so.db.tracingHooks.OnBalanceChange != nil { + so.db.tracingHooks.OnBalanceChange(so.address, so.Balance(), amount, reason) + } so.setBalance(amount) } @@ -342,6 +348,9 @@ func (so *stateObject) SetCode(codeHash libcommon.Hash, code []byte) { prevhash: so.data.CodeHash, prevcode: prevcode, }) + if so.db.tracingHooks != nil && so.db.tracingHooks.OnCodeChange != nil { + so.db.tracingHooks.OnCodeChange(so.address, so.data.CodeHash, prevcode, codeHash, code) + } so.setCode(codeHash, code) } @@ -356,6 +365,9 @@ func (so *stateObject) SetNonce(nonce uint64) { account: &so.address, prev: so.data.Nonce, }) + if so.db.tracingHooks != nil && so.db.tracingHooks.OnNonceChange != nil { + so.db.tracingHooks.OnNonceChange(so.address, so.data.Nonce, nonce) + } so.setNonce(nonce) } diff --git a/core/tracing/mocks/hooks.go b/core/tracing/mocks/hooks.go new file mode 100644 index 00000000000..5927231f097 --- /dev/null +++ b/core/tracing/mocks/hooks.go @@ -0,0 +1,525 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: hooks.go +// +// Generated by this command: +// +// mockgen -source hooks.go -destination mocks/hooks.go +// + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + uint256 "github.com/holiman/uint256" + chain "github.com/erigontech/erigon-lib/chain" + common "github.com/erigontech/erigon-lib/common" + tracing "github.com/erigontech/erigon/core/tracing" + types "github.com/erigontech/erigon/core/types" + gomock "go.uber.org/mock/gomock" +) + +// MockOpContext is a mock of OpContext interface. +type MockOpContext struct { + ctrl *gomock.Controller + recorder *MockOpContextMockRecorder +} + +// MockOpContextMockRecorder is the mock recorder for MockOpContext. +type MockOpContextMockRecorder struct { + mock *MockOpContext +} + +// NewMockOpContext creates a new mock instance. +func NewMockOpContext(ctrl *gomock.Controller) *MockOpContext { + mock := &MockOpContext{ctrl: ctrl} + mock.recorder = &MockOpContextMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockOpContext) EXPECT() *MockOpContextMockRecorder { + return m.recorder +} + +// Address mocks base method. +func (m *MockOpContext) Address() common.Address { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Address") + ret0, _ := ret[0].(common.Address) + return ret0 +} + +// Address indicates an expected call of Address. +func (mr *MockOpContextMockRecorder) Address() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Address", reflect.TypeOf((*MockOpContext)(nil).Address)) +} + +// CallInput mocks base method. +func (m *MockOpContext) CallInput() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CallInput") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// CallInput indicates an expected call of CallInput. +func (mr *MockOpContextMockRecorder) CallInput() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallInput", reflect.TypeOf((*MockOpContext)(nil).CallInput)) +} + +// CallValue mocks base method. +func (m *MockOpContext) CallValue() *uint256.Int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CallValue") + ret0, _ := ret[0].(*uint256.Int) + return ret0 +} + +// CallValue indicates an expected call of CallValue. +func (mr *MockOpContextMockRecorder) CallValue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CallValue", reflect.TypeOf((*MockOpContext)(nil).CallValue)) +} + +// Caller mocks base method. +func (m *MockOpContext) Caller() common.Address { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Caller") + ret0, _ := ret[0].(common.Address) + return ret0 +} + +// Caller indicates an expected call of Caller. +func (mr *MockOpContextMockRecorder) Caller() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Caller", reflect.TypeOf((*MockOpContext)(nil).Caller)) +} + +// Code mocks base method. +func (m *MockOpContext) Code() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Code") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// Code indicates an expected call of Code. +func (mr *MockOpContextMockRecorder) Code() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Code", reflect.TypeOf((*MockOpContext)(nil).Code)) +} + +// CodeHash mocks base method. +func (m *MockOpContext) CodeHash() common.Hash { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CodeHash") + ret0, _ := ret[0].(common.Hash) + return ret0 +} + +// CodeHash indicates an expected call of CodeHash. +func (mr *MockOpContextMockRecorder) CodeHash() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CodeHash", reflect.TypeOf((*MockOpContext)(nil).CodeHash)) +} + +// MemoryData mocks base method. +func (m *MockOpContext) MemoryData() []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MemoryData") + ret0, _ := ret[0].([]byte) + return ret0 +} + +// MemoryData indicates an expected call of MemoryData. +func (mr *MockOpContextMockRecorder) MemoryData() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MemoryData", reflect.TypeOf((*MockOpContext)(nil).MemoryData)) +} + +// StackData mocks base method. +func (m *MockOpContext) StackData() []uint256.Int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StackData") + ret0, _ := ret[0].([]uint256.Int) + return ret0 +} + +// StackData indicates an expected call of StackData. +func (mr *MockOpContextMockRecorder) StackData() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StackData", reflect.TypeOf((*MockOpContext)(nil).StackData)) +} + +// MockIntraBlockState is a mock of IntraBlockState interface. +type MockIntraBlockState struct { + ctrl *gomock.Controller + recorder *MockIntraBlockStateMockRecorder +} + +// MockIntraBlockStateMockRecorder is the mock recorder for MockIntraBlockState. +type MockIntraBlockStateMockRecorder struct { + mock *MockIntraBlockState +} + +// NewMockIntraBlockState creates a new mock instance. +func NewMockIntraBlockState(ctrl *gomock.Controller) *MockIntraBlockState { + mock := &MockIntraBlockState{ctrl: ctrl} + mock.recorder = &MockIntraBlockStateMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockIntraBlockState) EXPECT() *MockIntraBlockStateMockRecorder { + return m.recorder +} + +// Exist mocks base method. +func (m *MockIntraBlockState) Exist(arg0 common.Address) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Exist", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// Exist indicates an expected call of Exist. +func (mr *MockIntraBlockStateMockRecorder) Exist(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exist", reflect.TypeOf((*MockIntraBlockState)(nil).Exist), arg0) +} + +// GetBalance mocks base method. +func (m *MockIntraBlockState) GetBalance(arg0 common.Address) *uint256.Int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBalance", arg0) + ret0, _ := ret[0].(*uint256.Int) + return ret0 +} + +// GetBalance indicates an expected call of GetBalance. +func (mr *MockIntraBlockStateMockRecorder) GetBalance(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalance", reflect.TypeOf((*MockIntraBlockState)(nil).GetBalance), arg0) +} + +// GetCode mocks base method. +func (m *MockIntraBlockState) GetCode(arg0 common.Address) []byte { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCode", arg0) + ret0, _ := ret[0].([]byte) + return ret0 +} + +// GetCode indicates an expected call of GetCode. +func (mr *MockIntraBlockStateMockRecorder) GetCode(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCode", reflect.TypeOf((*MockIntraBlockState)(nil).GetCode), arg0) +} + +// GetNonce mocks base method. +func (m *MockIntraBlockState) GetNonce(arg0 common.Address) uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetNonce", arg0) + ret0, _ := ret[0].(uint64) + return ret0 +} + +// GetNonce indicates an expected call of GetNonce. +func (mr *MockIntraBlockStateMockRecorder) GetNonce(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNonce", reflect.TypeOf((*MockIntraBlockState)(nil).GetNonce), arg0) +} + +// GetRefund mocks base method. +func (m *MockIntraBlockState) GetRefund() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRefund") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// GetRefund indicates an expected call of GetRefund. +func (mr *MockIntraBlockStateMockRecorder) GetRefund() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRefund", reflect.TypeOf((*MockIntraBlockState)(nil).GetRefund)) +} + +// GetState mocks base method. +func (m *MockIntraBlockState) GetState(addr common.Address, key *common.Hash, value *uint256.Int) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "GetState", addr, key, value) +} + +// GetState indicates an expected call of GetState. +func (mr *MockIntraBlockStateMockRecorder) GetState(addr, key, value any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetState", reflect.TypeOf((*MockIntraBlockState)(nil).GetState), addr, key, value) +} + +// Mocktracer is a mock of tracer interface. +type Mocktracer struct { + ctrl *gomock.Controller + recorder *MocktracerMockRecorder +} + +// MocktracerMockRecorder is the mock recorder for Mocktracer. +type MocktracerMockRecorder struct { + mock *Mocktracer +} + +// NewMocktracer creates a new mock instance. +func NewMocktracer(ctrl *gomock.Controller) *Mocktracer { + mock := &Mocktracer{ctrl: ctrl} + mock.recorder = &MocktracerMockRecorder{mock} + return mock +} + +func (m *Mocktracer) Hooks() *tracing.Hooks { + return &tracing.Hooks{ + OnTxStart: m.TxStartHook, + OnTxEnd: m.TxEndHook, + OnEnter: m.EnterHook, + OnExit: m.ExitHook, + OnOpcode: m.OpcodeHook, + OnFault: m.FaultHook, + OnGasChange: m.GasChangeHook, + // Chain events + OnBlockchainInit: m.BlockchainInitHook, + OnBlockStart: m.BlockStartHook, + OnBlockEnd: m.BlockEndHook, + OnGenesisBlock: m.GenesisBlockHook, + OnSystemCallStart: m.OnSystemCallStartHook, + OnSystemCallEnd: m.OnSystemCallEndHook, + // State events + OnBalanceChange: m.BalanceChangeHook, + OnNonceChange: m.NonceChangeHook, + OnCodeChange: m.CodeChangeHook, + OnStorageChange: m.StorageChangeHook, + OnLog: m.LogHook, + } +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *Mocktracer) EXPECT() *MocktracerMockRecorder { + return m.recorder +} + +// BalanceChangeHook mocks base method. +func (m *Mocktracer) BalanceChangeHook(addr common.Address, prev, new *uint256.Int, reason tracing.BalanceChangeReason) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "BalanceChangeHook", addr, prev, new, reason) +} + +// BalanceChangeHook indicates an expected call of BalanceChangeHook. +func (mr *MocktracerMockRecorder) BalanceChangeHook(addr, prev, new, reason any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BalanceChangeHook", reflect.TypeOf((*Mocktracer)(nil).BalanceChangeHook), addr, prev, new, reason) +} + +// BlockEndHook mocks base method. +func (m *Mocktracer) BlockEndHook(err error) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "BlockEndHook", err) +} + +// BlockEndHook indicates an expected call of BlockEndHook. +func (mr *MocktracerMockRecorder) BlockEndHook(err any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockEndHook", reflect.TypeOf((*Mocktracer)(nil).BlockEndHook), err) +} + +// BlockStartHook mocks base method. +func (m *Mocktracer) BlockStartHook(event tracing.BlockEvent) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "BlockStartHook", event) +} + +// BlockStartHook indicates an expected call of BlockStartHook. +func (mr *MocktracerMockRecorder) BlockStartHook(event any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockStartHook", reflect.TypeOf((*Mocktracer)(nil).BlockStartHook), event) +} + +// BlockchainInitHook mocks base method. +func (m *Mocktracer) BlockchainInitHook(chainConfig *chain.Config) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "BlockchainInitHook", chainConfig) +} + +// BlockchainInitHook indicates an expected call of BlockchainInitHook. +func (mr *MocktracerMockRecorder) BlockchainInitHook(chainConfig any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockchainInitHook", reflect.TypeOf((*Mocktracer)(nil).BlockchainInitHook), chainConfig) +} + +// CodeChangeHook mocks base method. +func (m *Mocktracer) CodeChangeHook(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "CodeChangeHook", addr, prevCodeHash, prevCode, codeHash, code) +} + +// CodeChangeHook indicates an expected call of CodeChangeHook. +func (mr *MocktracerMockRecorder) CodeChangeHook(addr, prevCodeHash, prevCode, codeHash, code any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CodeChangeHook", reflect.TypeOf((*Mocktracer)(nil).CodeChangeHook), addr, prevCodeHash, prevCode, codeHash, code) +} + +// EnterHook mocks base method. +func (m *Mocktracer) EnterHook(depth int, typ byte, from, to common.Address, precompile bool, input []byte, gas uint64, value *uint256.Int, code []byte) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "EnterHook", depth, typ, from, to, precompile, input, gas, value, code) +} + +// EnterHook indicates an expected call of EnterHook. +func (mr *MocktracerMockRecorder) EnterHook(depth, typ, from, to, precompile, input, gas, value, code any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnterHook", reflect.TypeOf((*Mocktracer)(nil).EnterHook), depth, typ, from, to, precompile, input, gas, value, code) +} + +// ExitHook mocks base method. +func (m *Mocktracer) ExitHook(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "ExitHook", depth, output, gasUsed, err, reverted) +} + +// ExitHook indicates an expected call of ExitHook. +func (mr *MocktracerMockRecorder) ExitHook(depth, output, gasUsed, err, reverted any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExitHook", reflect.TypeOf((*Mocktracer)(nil).ExitHook), depth, output, gasUsed, err, reverted) +} + +// FaultHook mocks base method. +func (m *Mocktracer) FaultHook(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "FaultHook", pc, op, gas, cost, scope, depth, err) +} + +// FaultHook indicates an expected call of FaultHook. +func (mr *MocktracerMockRecorder) FaultHook(pc, op, gas, cost, scope, depth, err any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FaultHook", reflect.TypeOf((*Mocktracer)(nil).FaultHook), pc, op, gas, cost, scope, depth, err) +} + +// GasChangeHook mocks base method. +func (m *Mocktracer) GasChangeHook(old, new uint64, reason tracing.GasChangeReason) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "GasChangeHook", old, new, reason) +} + +// GasChangeHook indicates an expected call of GasChangeHook. +func (mr *MocktracerMockRecorder) GasChangeHook(old, new, reason any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GasChangeHook", reflect.TypeOf((*Mocktracer)(nil).GasChangeHook), old, new, reason) +} + +// GenesisBlockHook mocks base method. +func (m *Mocktracer) GenesisBlockHook(genesis *types.Block, alloc types.GenesisAlloc) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "GenesisBlockHook", genesis, alloc) +} + +// GenesisBlockHook indicates an expected call of GenesisBlockHook. +func (mr *MocktracerMockRecorder) GenesisBlockHook(genesis, alloc any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenesisBlockHook", reflect.TypeOf((*Mocktracer)(nil).GenesisBlockHook), genesis, alloc) +} + +// LogHook mocks base method. +func (m *Mocktracer) LogHook(log *types.Log) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "LogHook", log) +} + +// LogHook indicates an expected call of LogHook. +func (mr *MocktracerMockRecorder) LogHook(log any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogHook", reflect.TypeOf((*Mocktracer)(nil).LogHook), log) +} + +// NonceChangeHook mocks base method. +func (m *Mocktracer) NonceChangeHook(addr common.Address, prev, new uint64) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "NonceChangeHook", addr, prev, new) +} + +// NonceChangeHook indicates an expected call of NonceChangeHook. +func (mr *MocktracerMockRecorder) NonceChangeHook(addr, prev, new any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NonceChangeHook", reflect.TypeOf((*Mocktracer)(nil).NonceChangeHook), addr, prev, new) +} + +// OnSystemCallEndHook mocks base method. +func (m *Mocktracer) OnSystemCallEndHook() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnSystemCallEndHook") +} + +// OnSystemCallEndHook indicates an expected call of OnSystemCallEndHook. +func (mr *MocktracerMockRecorder) OnSystemCallEndHook() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnSystemCallEndHook", reflect.TypeOf((*Mocktracer)(nil).OnSystemCallEndHook)) +} + +// OnSystemCallStartHook mocks base method. +func (m *Mocktracer) OnSystemCallStartHook() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OnSystemCallStartHook") +} + +// OnSystemCallStartHook indicates an expected call of OnSystemCallStartHook. +func (mr *MocktracerMockRecorder) OnSystemCallStartHook() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnSystemCallStartHook", reflect.TypeOf((*Mocktracer)(nil).OnSystemCallStartHook)) +} + +// OpcodeHook mocks base method. +func (m *Mocktracer) OpcodeHook(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "OpcodeHook", pc, op, gas, cost, scope, rData, depth, err) +} + +// OpcodeHook indicates an expected call of OpcodeHook. +func (mr *MocktracerMockRecorder) OpcodeHook(pc, op, gas, cost, scope, rData, depth, err any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpcodeHook", reflect.TypeOf((*Mocktracer)(nil).OpcodeHook), pc, op, gas, cost, scope, rData, depth, err) +} + +// StorageChangeHook mocks base method. +func (m *Mocktracer) StorageChangeHook(addr common.Address, slot *common.Hash, prev, new uint256.Int) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "StorageChangeHook", addr, slot, prev, new) +} + +// StorageChangeHook indicates an expected call of StorageChangeHook. +func (mr *MocktracerMockRecorder) StorageChangeHook(addr, slot, prev, new any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageChangeHook", reflect.TypeOf((*Mocktracer)(nil).StorageChangeHook), addr, slot, prev, new) +} + +// TxEndHook mocks base method. +func (m *Mocktracer) TxEndHook(receipt *types.Receipt, err error) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "TxEndHook", receipt, err) +} + +// TxEndHook indicates an expected call of TxEndHook. +func (mr *MocktracerMockRecorder) TxEndHook(receipt, err any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxEndHook", reflect.TypeOf((*Mocktracer)(nil).TxEndHook), receipt, err) +} + +// TxStartHook mocks base method. +func (m *Mocktracer) TxStartHook(vm *tracing.VMContext, tx types.Transaction, from common.Address) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "TxStartHook", vm, tx, from) +} + +// TxStartHook indicates an expected call of TxStartHook. +func (mr *MocktracerMockRecorder) TxStartHook(vm, tx, from any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TxStartHook", reflect.TypeOf((*Mocktracer)(nil).TxStartHook), vm, tx, from) +} diff --git a/core/vm/evmtypes/evmtypes.go b/core/vm/evmtypes/evmtypes.go index 734344a6660..775c4600acd 100644 --- a/core/vm/evmtypes/evmtypes.go +++ b/core/vm/evmtypes/evmtypes.go @@ -176,4 +176,6 @@ type IntraBlockState interface { Snapshot() int AddLog(*types.Log) + + SetHooks(hooks *tracing.Hooks) } diff --git a/tests/execution-spec-tests b/tests/execution-spec-tests deleted file mode 160000 index c53c43d7efe..00000000000 --- a/tests/execution-spec-tests +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c53c43d7efe94c5e972252533b1aee3669323fe1