From 3cbde5fa62e148c1fe96a8a33af88d82186183f5 Mon Sep 17 00:00:00 2001 From: Ganesh Vanahalli Date: Thu, 22 Aug 2024 17:16:37 +0530 Subject: [PATCH 1/2] Integrate CaptureArbitrumStorageGet/Set into the prestate tracer --- core/tracing/hooks.go | 4 +- eth/tracers/js/tracer_arbitrum.go | 6 ++- eth/tracers/logger/logger_arbitrum.go | 24 ++++++---- eth/tracers/native/gen_account_json.go | 22 +++++---- eth/tracers/native/mux.go | 8 ++-- eth/tracers/native/prestate.go | 65 ++++++++++++++++++++------ eth/tracers/native/tracer_arbitrum.go | 34 ++++++++++---- 7 files changed, 116 insertions(+), 47 deletions(-) diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 8235f08f85..f75526b057 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -148,8 +148,8 @@ type ( LogHook = func(log *types.Log) CaptureArbitrumTransferHook = func(from, to *common.Address, value *big.Int, before bool, purpose string) - CaptureArbitrumStorageGetHook = func(key common.Hash, depth int, before bool) - CaptureArbitrumStorageSetHook = func(key, value common.Hash, depth int, before bool) + CaptureArbitrumStorageGetHook = func(addr common.Address, key, mappedKey common.Hash, depth int, before bool) + CaptureArbitrumStorageSetHook = func(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) CaptureStylusHostioHook = func(name string, args, outs []byte, startInk, endInk uint64) ) diff --git a/eth/tracers/js/tracer_arbitrum.go b/eth/tracers/js/tracer_arbitrum.go index 01c421e0aa..d185565da6 100644 --- a/eth/tracers/js/tracer_arbitrum.go +++ b/eth/tracers/js/tracer_arbitrum.go @@ -52,8 +52,10 @@ func (jst *jsTracer) CaptureArbitrumTransfer( } } -func (*jsTracer) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {} -func (*jsTracer) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {} +func (*jsTracer) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { +} +func (*jsTracer) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { +} func (jst *jsTracer) CaptureStylusHostio(name string, args, outs []byte, startInk, endInk uint64) { hostio, ok := goja.AssertFunction(jst.obj.Get("hostio")) diff --git a/eth/tracers/logger/logger_arbitrum.go b/eth/tracers/logger/logger_arbitrum.go index 35f56e83eb..3cd7286002 100644 --- a/eth/tracers/logger/logger_arbitrum.go +++ b/eth/tracers/logger/logger_arbitrum.go @@ -31,15 +31,23 @@ func (*StructLogger) CaptureArbitrumTransfer(from, to *common.Address, value *bi func (*mdLogger) CaptureArbitrumTransfer(from, to *common.Address, amount *big.Int, before bool, purpose string) { } -func (*AccessListTracer) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {} -func (*jsonLogger) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {} -func (*StructLogger) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {} -func (*mdLogger) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {} +func (*AccessListTracer) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { +} +func (*jsonLogger) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { +} +func (*StructLogger) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { +} +func (*mdLogger) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { +} -func (*AccessListTracer) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {} -func (*jsonLogger) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {} -func (*StructLogger) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {} -func (*mdLogger) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {} +func (*AccessListTracer) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { +} +func (*jsonLogger) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { +} +func (*StructLogger) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { +} +func (*mdLogger) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { +} func (*AccessListTracer) CaptureStylusHostio(name string, args, outs []byte, startInk, endInk uint64) { } diff --git a/eth/tracers/native/gen_account_json.go b/eth/tracers/native/gen_account_json.go index 4c39cbc38c..f4cd22850e 100644 --- a/eth/tracers/native/gen_account_json.go +++ b/eth/tracers/native/gen_account_json.go @@ -15,26 +15,29 @@ var _ = (*accountMarshaling)(nil) // MarshalJSON marshals as JSON. func (a account) MarshalJSON() ([]byte, error) { type account struct { - Balance *hexutil.Big `json:"balance,omitempty"` - Code hexutil.Bytes `json:"code,omitempty"` - Nonce uint64 `json:"nonce,omitempty"` - Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + Balance *hexutil.Big `json:"balance,omitempty"` + Code hexutil.Bytes `json:"code,omitempty"` + Nonce uint64 `json:"nonce,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + ArbitrumStorage map[common.Hash]common.Hash `json:"arbitrumStorage,omitempty"` } var enc account enc.Balance = (*hexutil.Big)(a.Balance) enc.Code = a.Code enc.Nonce = a.Nonce enc.Storage = a.Storage + enc.ArbitrumStorage = a.ArbitrumStorage return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. func (a *account) UnmarshalJSON(input []byte) error { type account struct { - Balance *hexutil.Big `json:"balance,omitempty"` - Code *hexutil.Bytes `json:"code,omitempty"` - Nonce *uint64 `json:"nonce,omitempty"` - Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + Balance *hexutil.Big `json:"balance,omitempty"` + Code *hexutil.Bytes `json:"code,omitempty"` + Nonce *uint64 `json:"nonce,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + ArbitrumStorage map[common.Hash]common.Hash `json:"arbitrumStorage,omitempty"` } var dec account if err := json.Unmarshal(input, &dec); err != nil { @@ -52,5 +55,8 @@ func (a *account) UnmarshalJSON(input []byte) error { if dec.Storage != nil { a.Storage = dec.Storage } + if dec.ArbitrumStorage != nil { + a.ArbitrumStorage = dec.ArbitrumStorage + } return nil } diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index bfb3795731..d3410ee779 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -177,15 +177,15 @@ func (t *muxTracer) OnLog(log *types.Log) { } } -func (t *muxTracer) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) { +func (t *muxTracer) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { for _, t := range t.tracers { - t.CaptureArbitrumStorageGet(key, depth, before) + t.CaptureArbitrumStorageGet(addr, key, mappedKey, depth, before) } } -func (t *muxTracer) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) { +func (t *muxTracer) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { for _, t := range t.tracers { - t.CaptureArbitrumStorageSet(key, value, depth, before) + t.CaptureArbitrumStorageSet(addr, key, mappedKey, value, depth, before) } } diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index f32990b284..f98ff8445d 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -42,15 +42,18 @@ func init() { type stateMap = map[common.Address]*account type account struct { - Balance *big.Int `json:"balance,omitempty"` - Code []byte `json:"code,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"` + Nonce uint64 `json:"nonce,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + ArbitrumStorage map[common.Hash]common.Hash `json:"arbitrumStorage,omitempty"` + + empty bool + arbStorageKeyMap map[common.Hash]common.Hash } 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 || len(a.Code) > 0 || len(a.Storage) > 0 || (a.Balance != nil && a.Balance.Sign() != 0) || len(a.ArbitrumStorage) > 0 } type accountMarshaling struct { @@ -119,7 +122,7 @@ func (t *prestateTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scop switch { case stackLen >= 1 && (op == vm.SLOAD || op == vm.SSTORE): slot := common.Hash(stackData[stackLen-1].Bytes32()) - t.lookupStorage(caller, slot) + t.lookupStorage(caller, slot, common.Hash{}, false) case stackLen >= 1 && (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT): addr := common.Address(stackData[stackLen-1].Bytes20()) t.lookupAccount(addr) @@ -212,7 +215,10 @@ func (t *prestateTracer) processDiffState() { continue } modified := false - postAccount := &account{Storage: make(map[common.Hash]common.Hash)} + postAccount := &account{ + Storage: make(map[common.Hash]common.Hash), + ArbitrumStorage: make(map[common.Hash]common.Hash), + } newBalance := t.env.StateDB.GetBalance(addr).ToBig() newNonce := t.env.StateDB.GetNonce(addr) newCode := t.env.StateDB.GetCode(addr) @@ -248,6 +254,24 @@ func (t *prestateTracer) processDiffState() { } } + for key, val := range state.ArbitrumStorage { + // don't include the empty slot + if val == (common.Hash{}) { + delete(t.pre[addr].ArbitrumStorage, key) + } + + newVal := t.env.StateDB.GetState(types.ArbosStateAddress, state.arbStorageKeyMap[key]) + if val == newVal { + // Omit unchanged slots + delete(t.pre[addr].ArbitrumStorage, key) + } else { + modified = true + if newVal != (common.Hash{}) { + postAccount.ArbitrumStorage[key] = newVal + } + } + } + if modified { t.post[addr] = postAccount } else { @@ -265,10 +289,12 @@ func (t *prestateTracer) lookupAccount(addr common.Address) { } acc := &account{ - Balance: t.env.StateDB.GetBalance(addr).ToBig(), - Nonce: t.env.StateDB.GetNonce(addr), - Code: t.env.StateDB.GetCode(addr), - Storage: make(map[common.Hash]common.Hash), + Balance: t.env.StateDB.GetBalance(addr).ToBig(), + Nonce: t.env.StateDB.GetNonce(addr), + Code: t.env.StateDB.GetCode(addr), + Storage: make(map[common.Hash]common.Hash), + ArbitrumStorage: make(map[common.Hash]common.Hash), + arbStorageKeyMap: make(map[common.Hash]common.Hash), } if !acc.exists() { acc.empty = true @@ -279,9 +305,22 @@ func (t *prestateTracer) lookupAccount(addr common.Address) { // lookupStorage fetches the requested storage slot and adds // it to the prestate of the given contract. It assumes `lookupAccount` // has been performed on the contract before. -func (t *prestateTracer) lookupStorage(addr common.Address, key common.Hash) { +func (t *prestateTracer) lookupStorage(addr common.Address, key, mappedKey common.Hash, isArbitrumStorage bool) { + if isArbitrumStorage { + if _, ok := t.pre[addr].ArbitrumStorage[key]; ok { + return + } + t.pre[addr].ArbitrumStorage[key] = t.env.StateDB.GetState(types.ArbosStateAddress, mappedKey) + t.pre[addr].arbStorageKeyMap[key] = mappedKey + return + } if _, ok := t.pre[addr].Storage[key]; ok { return } t.pre[addr].Storage[key] = t.env.StateDB.GetState(addr, key) } + +func (t *prestateTracer) captureArbitrumStorageOps(addr common.Address, key, mappedKey common.Hash) { + t.lookupAccount(addr) + t.lookupStorage(addr, key, mappedKey, true) +} diff --git a/eth/tracers/native/tracer_arbitrum.go b/eth/tracers/native/tracer_arbitrum.go index 1616dab323..db6d18d68a 100644 --- a/eth/tracers/native/tracer_arbitrum.go +++ b/eth/tracers/native/tracer_arbitrum.go @@ -80,17 +80,31 @@ func (t *flatCallTracer) CaptureArbitrumTransfer(from, to *common.Address, value } } -func (*callTracer) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {} -func (*fourByteTracer) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {} -func (*noopTracer) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {} -func (*prestateTracer) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {} -func (*flatCallTracer) CaptureArbitrumStorageGet(key common.Hash, depth int, before bool) {} +func (t *prestateTracer) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { + t.captureArbitrumStorageOps(addr, key, mappedKey) +} + +func (t *prestateTracer) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { + t.captureArbitrumStorageOps(addr, key, mappedKey) +} + +func (*callTracer) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { +} +func (*fourByteTracer) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { +} +func (*noopTracer) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { +} +func (*flatCallTracer) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { +} -func (*callTracer) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {} -func (*fourByteTracer) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {} -func (*noopTracer) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {} -func (*prestateTracer) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {} -func (*flatCallTracer) CaptureArbitrumStorageSet(key, value common.Hash, depth int, before bool) {} +func (*callTracer) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { +} +func (*fourByteTracer) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { +} +func (*noopTracer) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { +} +func (*flatCallTracer) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { +} func (*callTracer) CaptureStylusHostio(name string, args, outs []byte, startInk, endInk uint64) {} func (*fourByteTracer) CaptureStylusHostio(name string, args, outs []byte, startInk, endInk uint64) {} From 2a2149bed91a533a140faa1c8cee5ecb0e5b6a70 Mon Sep 17 00:00:00 2001 From: Ganesh Vanahalli Date: Wed, 4 Sep 2024 12:51:53 +0530 Subject: [PATCH 2/2] address PR comments --- eth/tracers/native/prestate.go | 30 ++++++++++++--------------- eth/tracers/native/tracer_arbitrum.go | 6 ++++-- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index f98ff8445d..0305e218f6 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -42,10 +42,11 @@ func init() { type stateMap = map[common.Address]*account type account struct { - Balance *big.Int `json:"balance,omitempty"` - Code []byte `json:"code,omitempty"` - Nonce uint64 `json:"nonce,omitempty"` - Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + Balance *big.Int `json:"balance,omitempty"` + Code []byte `json:"code,omitempty"` + Nonce uint64 `json:"nonce,omitempty"` + Storage map[common.Hash]common.Hash `json:"storage,omitempty"` + ArbitrumStorage map[common.Hash]common.Hash `json:"arbitrumStorage,omitempty"` empty bool @@ -122,7 +123,7 @@ func (t *prestateTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scop switch { case stackLen >= 1 && (op == vm.SLOAD || op == vm.SSTORE): slot := common.Hash(stackData[stackLen-1].Bytes32()) - t.lookupStorage(caller, slot, common.Hash{}, false) + t.lookupStorage(caller, slot) case stackLen >= 1 && (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT): addr := common.Address(stackData[stackLen-1].Bytes20()) t.lookupAccount(addr) @@ -305,22 +306,17 @@ func (t *prestateTracer) lookupAccount(addr common.Address) { // lookupStorage fetches the requested storage slot and adds // it to the prestate of the given contract. It assumes `lookupAccount` // has been performed on the contract before. -func (t *prestateTracer) lookupStorage(addr common.Address, key, mappedKey common.Hash, isArbitrumStorage bool) { - if isArbitrumStorage { - if _, ok := t.pre[addr].ArbitrumStorage[key]; ok { - return - } - t.pre[addr].ArbitrumStorage[key] = t.env.StateDB.GetState(types.ArbosStateAddress, mappedKey) - t.pre[addr].arbStorageKeyMap[key] = mappedKey - return - } +func (t *prestateTracer) lookupStorage(addr common.Address, key common.Hash) { if _, ok := t.pre[addr].Storage[key]; ok { return } t.pre[addr].Storage[key] = t.env.StateDB.GetState(addr, key) } -func (t *prestateTracer) captureArbitrumStorageOps(addr common.Address, key, mappedKey common.Hash) { - t.lookupAccount(addr) - t.lookupStorage(addr, key, mappedKey, true) +func (t *prestateTracer) lookupArbitrumStorage(addr common.Address, key, mappedKey common.Hash) { + if _, ok := t.pre[addr].ArbitrumStorage[key]; ok { + return + } + t.pre[addr].ArbitrumStorage[key] = t.env.StateDB.GetState(types.ArbosStateAddress, mappedKey) + t.pre[addr].arbStorageKeyMap[key] = mappedKey } diff --git a/eth/tracers/native/tracer_arbitrum.go b/eth/tracers/native/tracer_arbitrum.go index db6d18d68a..3ede5682de 100644 --- a/eth/tracers/native/tracer_arbitrum.go +++ b/eth/tracers/native/tracer_arbitrum.go @@ -81,11 +81,13 @@ func (t *flatCallTracer) CaptureArbitrumTransfer(from, to *common.Address, value } func (t *prestateTracer) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) { - t.captureArbitrumStorageOps(addr, key, mappedKey) + t.lookupAccount(addr) + t.lookupArbitrumStorage(addr, key, mappedKey) } func (t *prestateTracer) CaptureArbitrumStorageSet(addr common.Address, key, mappedKey, value common.Hash, depth int, before bool) { - t.captureArbitrumStorageOps(addr, key, mappedKey) + t.lookupAccount(addr) + t.lookupArbitrumStorage(addr, key, mappedKey) } func (*callTracer) CaptureArbitrumStorageGet(addr common.Address, key, mappedKey common.Hash, depth int, before bool) {