From 0a0e396ff8faba341600d20747cd9ad0b2a287e3 Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Tue, 30 Jul 2024 10:02:15 +0800 Subject: [PATCH 01/17] WIP: flatten storageproof --- core/state/state_prove.go | 4 ++-- core/state/statedb.go | 47 ++++++++++++++++++++++++++++++++++++++- core/types/l2trace.go | 3 +++ rollup/tracing/tracing.go | 15 ++++++++++--- 4 files changed, 63 insertions(+), 6 deletions(-) diff --git a/core/state/state_prove.go b/core/state/state_prove.go index 95c54988dc18..5fe374c946fd 100644 --- a/core/state/state_prove.go +++ b/core/state/state_prove.go @@ -74,9 +74,9 @@ func (s *StateDB) GetStorageTrieForProof(addr common.Address) (Trie, error) { // GetSecureTrieProof handle any interface with Prove (should be a Trie in most case) and // deliver the proof in bytes -func (s *StateDB) GetSecureTrieProof(trieProve TrieProve, key common.Hash) ([][]byte, error) { +func (s *StateDB) GetSecureTrieProof(trieProve TrieProve, key common.Hash) (FullProofList, error) { - var proof proofList + var proof FullProofList var err error if s.IsZktrie() { key_s, _ := zkt.ToSecureKeyBytes(key.Bytes()) diff --git a/core/state/statedb.go b/core/state/statedb.go index 6629a50eae57..0ce7a662155b 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -54,6 +54,33 @@ func (n *proofList) Delete(key []byte) error { panic("not supported") } +type fullProof struct { + Key []byte + Value []byte +} + +type FullProofList []fullProof + +func (n *FullProofList) Put(key []byte, value []byte) error { + *n = append(*n, fullProof{ + Key: key, + Value: value, + }) + return nil +} + +func (n *FullProofList) Delete(key []byte) error { + panic("not supported") +} + +func (n FullProofList) GetData() (out [][]byte) { + out = make([][]byte, 0, len(n)) + for _, i := range n { + out = append(out, i.Value) + } + return +} + // StateDB structs within the ethereum protocol are used to store anything // within the merkle trie. StateDBs take care of caching and storing // nested states. It's the general query interface to retrieve: @@ -343,6 +370,20 @@ func (s *StateDB) GetProofByHash(addrHash common.Hash) ([][]byte, error) { return proof, err } +// GetFullProof returns the Merkle proof for a given account, with both node data and key +func (s *StateDB) GetFullProof(addr common.Address) (FullProofList, error) { + var hash common.Hash + if s.IsZktrie() { + addr_s, _ := zkt.ToSecureKeyBytes(addr.Bytes()) + hash = common.BytesToHash(addr_s.Bytes()) + } else { + hash = crypto.Keccak256Hash(addr.Bytes()) + } + var proof FullProofList + err := s.trie.Prove(hash[:], 0, &proof) + return proof, err +} + func (s *StateDB) GetLiveStateAccount(addr common.Address) *types.StateAccount { obj, ok := s.stateObjects[addr] if !ok { @@ -361,7 +402,11 @@ func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte, if trie == nil { return nil, errors.New("storage trie for requested address does not exist") } - return s.GetSecureTrieProof(trie, key) + proof, err := s.GetSecureTrieProof(trie, key) + if err != nil { + return nil, err + } + return proof.GetData(), nil } // GetCommittedState retrieves a value from the given account's committed storage trie. diff --git a/core/types/l2trace.go b/core/types/l2trace.go index b5a1ebd8d053..278836f13112 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -45,6 +45,9 @@ type StorageTrace struct { // All storage proofs BEFORE execution StorageProofs map[string]map[string][]hexutil.Bytes `json:"storageProofs,omitempty"` + // The "flatten" db nodes + FlattenProofs map[string]hexutil.Bytes `json:"flattenProofs,omitempty"` + // Node entries for deletion, no need to distinguish what it is from, just read them // into the partial db DeletionProofs []hexutil.Bytes `json:"deletionProofs,omitempty"` diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index 3feea62ba388..f5a9a943f9fe 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -40,6 +40,9 @@ var ( // TracerWrapper implements ScrollTracerWrapper interface type TracerWrapper struct{} +// alias for proof list +type proofList = state.FullProofList + // NewTracerWrapper TracerWrapper creates a new TracerWrapper func NewTracerWrapper() *TracerWrapper { return &TracerWrapper{} @@ -464,7 +467,7 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B } env.sMu.Unlock() - var proof [][]byte + var proof proofList var err error if zktrieTracer.Available() { proof, err = state.GetSecureTrieProof(zktrieTracer, key) @@ -475,7 +478,7 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B log.Error("Storage proof not available", "error", err, "address", addrStr, "key", keyStr) // but we still mark the proofs map with nil array } - wrappedProof := types.WrapProof(proof) + wrappedProof := types.WrapProof(proof.GetData()) env.sMu.Lock() txm[keyStr] = wrappedProof m[keyStr] = wrappedProof @@ -514,6 +517,12 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B return nil } +func (env *TraceEnv) fillFlattenStorageProof(proof proofList) { + for _, i := range proof { + env.FlattenProofs[&hexutil.Bytes{}] + } +} + // fillBlockTrace content after all the txs are finished running. func (env *TraceEnv) fillBlockTrace(block *types.Block) (*types.BlockTrace, error) { defer func(t time.Time) { @@ -560,7 +569,7 @@ func (env *TraceEnv) fillBlockTrace(block *types.Block) (*types.BlockTrace, erro } else if proof, err := statedb.GetSecureTrieProof(trie, slot); err != nil { log.Error("Get storage proof for intrinstic address failed", "error", err, "address", addr, "slot", slot) } else { - env.StorageProofs[addr.String()][slot.String()] = types.WrapProof(proof) + env.StorageProofs[addr.String()][slot.String()] = types.WrapProof(proof.GetData()) } } } From 330ad978e29d36bcefb2efbe63e606b10afd2c3f Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Tue, 30 Jul 2024 15:10:54 +0800 Subject: [PATCH 02/17] WIP: for testing --- rollup/tracing/tracing.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index f5a9a943f9fe..e35203629f99 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -409,13 +409,15 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B if existed { continue } - proof, err := state.GetProof(addr) + proof, err := state.GetFullProof(addr) if err != nil { log.Error("Proof not available", "address", addrStr, "error", err) // but we still mark the proofs map with nil array } - wrappedProof := types.WrapProof(proof) + wrappedProof := types.WrapProof(proof.GetData()) env.pMu.Lock() + // TODO: + env.fillFlattenStorageProof(txStorageTrace, proof) env.Proofs[addrStr] = wrappedProof txStorageTrace.Proofs[addrStr] = wrappedProof env.pMu.Unlock() @@ -480,6 +482,8 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B } wrappedProof := types.WrapProof(proof.GetData()) env.sMu.Lock() + // TODO: + env.fillFlattenStorageProof(txStorageTrace, proof) txm[keyStr] = wrappedProof m[keyStr] = wrappedProof if zktrieTracer.Available() { @@ -517,9 +521,13 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B return nil } -func (env *TraceEnv) fillFlattenStorageProof(proof proofList) { +func (env *TraceEnv) fillFlattenStorageProof(trace *types.StorageTrace, proof proofList) { for _, i := range proof { - env.FlattenProofs[&hexutil.Bytes{}] + keyStr := hexutil.Encode(i.Key) + env.FlattenProofs[keyStr] = i.Value + if trace != nil { + trace.FlattenProofs[keyStr] = i.Value + } } } @@ -551,10 +559,12 @@ func (env *TraceEnv) fillBlockTrace(block *types.Block) (*types.BlockTrace, erro for addr, storages := range intrinsicStorageProofs { if _, existed := env.Proofs[addr.String()]; !existed { - if proof, err := statedb.GetProof(addr); err != nil { + if proof, err := statedb.GetFullProof(addr); err != nil { log.Error("Proof for intrinstic address not available", "error", err, "address", addr) } else { - env.Proofs[addr.String()] = types.WrapProof(proof) + // TODO: + env.fillFlattenStorageProof(nil, proof) + env.Proofs[addr.String()] = types.WrapProof(proof.GetData()) } } @@ -569,6 +579,8 @@ func (env *TraceEnv) fillBlockTrace(block *types.Block) (*types.BlockTrace, erro } else if proof, err := statedb.GetSecureTrieProof(trie, slot); err != nil { log.Error("Get storage proof for intrinstic address failed", "error", err, "address", addr, "slot", slot) } else { + // TODO: + env.fillFlattenStorageProof(nil, proof) env.StorageProofs[addr.String()][slot.String()] = types.WrapProof(proof.GetData()) } } From 06fdc8cf4e51c2fe01bc1a0cb1a80a97dfde396d Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Tue, 30 Jul 2024 16:39:08 +0800 Subject: [PATCH 03/17] fix: init map --- rollup/tracing/tracing.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index e35203629f99..75b68199f685 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -116,6 +116,7 @@ func CreateTraceEnvHelper(chainConfig *params.ChainConfig, logConfig *vm.LogConf RootAfter: block.Root(), Proofs: make(map[string][]hexutil.Bytes), StorageProofs: make(map[string]map[string][]hexutil.Bytes), + FlattenProofs: make(map[string]hexutil.Bytes), }, Codes: make(map[common.Hash]vm.CodeInfo), ZkTrieTracer: make(map[string]state.ZktrieProofTracer), @@ -376,6 +377,7 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B txStorageTrace := &types.StorageTrace{ Proofs: make(map[string][]hexutil.Bytes), StorageProofs: make(map[string]map[string][]hexutil.Bytes), + FlattenProofs: make(map[string]hexutil.Bytes), } // still we have no state root for per tx, only set the head and tail if index == 0 { From 11a21da8cc505474498350ad8458bb30ae8d16a3 Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Tue, 30 Jul 2024 17:02:49 +0800 Subject: [PATCH 04/17] fix lock issue --- rollup/tracing/tracing.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index 75b68199f685..a59d95098778 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -482,10 +482,14 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B log.Error("Storage proof not available", "error", err, "address", addrStr, "key", keyStr) // but we still mark the proofs map with nil array } - wrappedProof := types.WrapProof(proof.GetData()) - env.sMu.Lock() + + env.pMu.Lock() // TODO: env.fillFlattenStorageProof(txStorageTrace, proof) + env.pMu.Unlock() + + wrappedProof := types.WrapProof(proof.GetData()) + env.sMu.Lock() txm[keyStr] = wrappedProof m[keyStr] = wrappedProof if zktrieTracer.Available() { From 2238551903bad5aa814d95eb1e976cd7bb865e01 Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Tue, 30 Jul 2024 17:46:09 +0800 Subject: [PATCH 05/17] add deletion proof --- rollup/tracing/tracing.go | 13 ++++++++++++- trie/zk_trie_proof_test.go | 10 +++++----- trie/zktrie_deletionproof.go | 24 +++++++++++++++++------- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index a59d95098778..dd7dfca8a99d 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -253,21 +253,32 @@ func (env *TraceEnv) GetBlockTrace(block *types.Block) (*types.BlockTrace, error pend.Wait() // after all tx has been traced, collect "deletion proof" for zktrie + deleteionProofs := make(map[string]hexutil.Bytes) + for _, tracer := range env.ZkTrieTracer { delProofs, err := tracer.GetDeletionProofs() if err != nil { log.Error("deletion proof failure", "error", err) } else { - for _, proof := range delProofs { + for key, proof := range delProofs { + deleteionProofs[hexutil.Encode(key.Bytes())] = proof env.DeletionProofs = append(env.DeletionProofs, proof) } } } + //TODO: merge deletion proof + for k, v := range deleteionProofs { + env.FlattenProofs[k] = v + } + // build dummy per-tx deletion proof for _, txStorageTrace := range env.TxStorageTraces { if txStorageTrace != nil { txStorageTrace.DeletionProofs = env.DeletionProofs + for k, v := range deleteionProofs { + txStorageTrace.FlattenProofs[k] = v + } } } diff --git a/trie/zk_trie_proof_test.go b/trie/zk_trie_proof_test.go index aec28fde5aad..f494bbf64a88 100644 --- a/trie/zk_trie_proof_test.go +++ b/trie/zk_trie_proof_test.go @@ -243,12 +243,12 @@ func TestProofWithDeletion(t *testing.T) { assert.NoError(t, err) //assert.Equal(t, len(sibling1), len(delTracer.GetProofs())) - siblings, err := proofTracer.GetDeletionProofs() + siblings, err := proofTracer.GetDeletionProofNodes() assert.NoError(t, err) assert.Equal(t, 0, len(siblings)) proofTracer.MarkDeletion(s_key1.Bytes()) - siblings, err = proofTracer.GetDeletionProofs() + siblings, err = proofTracer.GetDeletionProofNodes() assert.NoError(t, err) assert.Equal(t, 1, len(siblings)) l := len(siblings[0]) @@ -259,7 +259,7 @@ func TestProofWithDeletion(t *testing.T) { // Marking a key that is currently not hit (but terminated by an empty node) // also causes it to be added to the deletion proof proofTracer.MarkDeletion(s_key2.Bytes()) - siblings, err = proofTracer.GetDeletionProofs() + siblings, err = proofTracer.GetDeletionProofNodes() assert.NoError(t, err) assert.Equal(t, 2, len(siblings)) @@ -277,12 +277,12 @@ func TestProofWithDeletion(t *testing.T) { assert.NoError(t, err) proofTracer.MarkDeletion(s_key1.Bytes()) - siblings, err = proofTracer.GetDeletionProofs() + siblings, err = proofTracer.GetDeletionProofNodes() assert.NoError(t, err) assert.Equal(t, 1, len(siblings)) proofTracer.MarkDeletion(s_key2.Bytes()) - siblings, err = proofTracer.GetDeletionProofs() + siblings, err = proofTracer.GetDeletionProofNodes() assert.NoError(t, err) assert.Equal(t, 2, len(siblings)) diff --git a/trie/zktrie_deletionproof.go b/trie/zktrie_deletionproof.go index 7ae2a11ff87b..ff221674b772 100644 --- a/trie/zktrie_deletionproof.go +++ b/trie/zktrie_deletionproof.go @@ -51,13 +51,28 @@ func (t *ProofTracer) Merge(another *ProofTracer) *ProofTracer { return t } +// GetDeletionProofNodes extract the value part from deletion proofs +func (t *ProofTracer) GetDeletionProofNodes() ([][]byte, error) { + + retMap, err := t.GetDeletionProofs() + if err != nil { + return nil, err + } + + var ret [][]byte + for _, bt := range retMap { + ret = append(ret, bt) + } + return ret, nil +} + // GetDeletionProofs generate current deletionTracer and collect deletion proofs // which is possible to be used from all rawPaths, which enabling witness generator // to predict the final state root after executing any deletion // along any of the rawpath, no matter of the deletion occurs in any position of the mpt ops // Note the collected sibling node has no key along with it since witness generator would // always decode the node for its purpose -func (t *ProofTracer) GetDeletionProofs() ([][]byte, error) { +func (t *ProofTracer) GetDeletionProofs() (map[zkt.Hash][]byte, error) { retMap := map[zkt.Hash][]byte{} @@ -93,12 +108,7 @@ func (t *ProofTracer) GetDeletionProofs() ([][]byte, error) { } } - var ret [][]byte - for _, bt := range retMap { - ret = append(ret, bt) - } - - return ret, nil + return retMap, nil } From 7abeb463415a027a536c126e82251ae934ab6fd8 Mon Sep 17 00:00:00 2001 From: noelwei Date: Sat, 3 Aug 2024 20:49:53 +0900 Subject: [PATCH 06/17] fix endian represent of key --- rollup/tracing/tracing.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index dd7dfca8a99d..8234f1eb89b5 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -26,6 +26,7 @@ import ( "github.com/scroll-tech/go-ethereum/rollup/fees" "github.com/scroll-tech/go-ethereum/rollup/rcfg" "github.com/scroll-tech/go-ethereum/rollup/withdrawtrie" + zktrie "github.com/scroll-tech/zktrie/types" ) var ( @@ -540,7 +541,10 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B func (env *TraceEnv) fillFlattenStorageProof(trace *types.StorageTrace, proof proofList) { for _, i := range proof { - keyStr := hexutil.Encode(i.Key) + // the "raw key" is in fact a zktrie.Hash (bytes stored with little-endian) + // we need to convert it into big-endian + hashContainer := zktrie.NewHashFromBytes(i.Key) + keyStr := hexutil.Encode(hashContainer[:]) env.FlattenProofs[keyStr] = i.Value if trace != nil { trace.FlattenProofs[keyStr] = i.Value From 84b00d2b54ee370453e4fbd598c8da287c91a71a Mon Sep 17 00:00:00 2001 From: noelwei Date: Mon, 5 Aug 2024 00:24:12 +0900 Subject: [PATCH 07/17] add flatten proof for coinbase --- rollup/tracing/tracing.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index 8234f1eb89b5..44f6e90012d0 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -175,12 +175,14 @@ func CreateTraceEnv(chainConfig *params.ChainConfig, chainContext core.ChainCont key := coinbase.String() if _, exist := env.Proofs[key]; !exist { - proof, err := env.state.GetProof(coinbase) + proof, err := env.state.GetFullProof(coinbase) if err != nil { log.Error("Proof for coinbase not available", "coinbase", coinbase, "error", err) // but we still mark the proofs map with nil array } - env.Proofs[key] = types.WrapProof(proof) + // TODO: + env.fillFlattenStorageProof(nil, proof) + env.Proofs[key] = types.WrapProof(proof.GetData()) } return env, nil From 49151d434c5cc92dd14610ce0737ef77f284abc1 Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Wed, 7 Aug 2024 12:05:45 +0800 Subject: [PATCH 08/17] WIP: preimage for key --- core/state/state_prove.go | 11 +++++++---- core/state/statedb.go | 7 ++++--- core/types/l2trace.go | 2 +- rollup/tracing/tracing.go | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/core/state/state_prove.go b/core/state/state_prove.go index 5fe374c946fd..668e20eb74b4 100644 --- a/core/state/state_prove.go +++ b/core/state/state_prove.go @@ -74,15 +74,18 @@ func (s *StateDB) GetStorageTrieForProof(addr common.Address) (Trie, error) { // GetSecureTrieProof handle any interface with Prove (should be a Trie in most case) and // deliver the proof in bytes -func (s *StateDB) GetSecureTrieProof(trieProve TrieProve, key common.Hash) (FullProofList, error) { +func (s *StateDB) GetSecureTrieProof(trieProve TrieProve, key common.Hash) (FullProofList, common.Hash, error) { var proof FullProofList + var hash common.Hash var err error if s.IsZktrie() { key_s, _ := zkt.ToSecureKeyBytes(key.Bytes()) - err = trieProve.Prove(key_s.Bytes(), 0, &proof) + hash = common.BytesToHash(key_s.Bytes()) + err = trieProve.Prove(hash.Bytes(), 0, &proof) } else { - err = trieProve.Prove(crypto.Keccak256(key.Bytes()), 0, &proof) + hash = common.BytesToHash(crypto.Keccak256(key.Bytes())) + err = trieProve.Prove(hash.Bytes(), 0, &proof) } - return proof, err + return proof, hash, err } diff --git a/core/state/statedb.go b/core/state/statedb.go index 0ce7a662155b..ec876bc7882a 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -371,7 +371,8 @@ func (s *StateDB) GetProofByHash(addrHash common.Hash) ([][]byte, error) { } // GetFullProof returns the Merkle proof for a given account, with both node data and key -func (s *StateDB) GetFullProof(addr common.Address) (FullProofList, error) { +// also the key for address is provided +func (s *StateDB) GetFullProof(addr common.Address) (FullProofList, common.Hash, error) { var hash common.Hash if s.IsZktrie() { addr_s, _ := zkt.ToSecureKeyBytes(addr.Bytes()) @@ -381,7 +382,7 @@ func (s *StateDB) GetFullProof(addr common.Address) (FullProofList, error) { } var proof FullProofList err := s.trie.Prove(hash[:], 0, &proof) - return proof, err + return proof, hash, err } func (s *StateDB) GetLiveStateAccount(addr common.Address) *types.StateAccount { @@ -402,7 +403,7 @@ func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte, if trie == nil { return nil, errors.New("storage trie for requested address does not exist") } - proof, err := s.GetSecureTrieProof(trie, key) + proof, _, err := s.GetSecureTrieProof(trie, key) if err != nil { return nil, err } diff --git a/core/types/l2trace.go b/core/types/l2trace.go index 278836f13112..55c3d9655379 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -46,7 +46,7 @@ type StorageTrace struct { StorageProofs map[string]map[string][]hexutil.Bytes `json:"storageProofs,omitempty"` // The "flatten" db nodes - FlattenProofs map[string]hexutil.Bytes `json:"flattenProofs,omitempty"` + FlattenProofs map[common.Hash]hexutil.Bytes `json:"flattenProofs,omitempty"` // Node entries for deletion, no need to distinguish what it is from, just read them // into the partial db diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index 44f6e90012d0..c90bb1ea0c25 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -73,7 +73,7 @@ type TraceEnv struct { // The following Mutexes are used to protect against parallel read/write, // since txs are executed in parallel. pMu sync.Mutex // for `TraceEnv.StorageTrace.Proofs` - sMu sync.Mutex // for `TraceEnv.state`` + sMu sync.Mutex // for `TraceEnv.state` cMu sync.Mutex // for `TraceEnv.Codes` *types.StorageTrace From 8c2611c9d998d95b24011b039482392c18b0fc72 Mon Sep 17 00:00:00 2001 From: noelwei Date: Wed, 7 Aug 2024 14:25:24 +0800 Subject: [PATCH 09/17] key hash records --- core/types/l2trace.go | 5 ++++ rollup/tracing/tracing.go | 51 ++++++++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/core/types/l2trace.go b/core/types/l2trace.go index 55c3d9655379..637732b95342 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -48,6 +48,11 @@ type StorageTrace struct { // The "flatten" db nodes FlattenProofs map[common.Hash]hexutil.Bytes `json:"flattenProofs,omitempty"` + // The hash of secured addresses + AddressHashes map[common.Address]common.Hash `json:"addressHashes,omitempty"` + // The hash of secured store key + StoreKeyHashes map[common.Hash]common.Hash `json:"storeKeyHashes,omitempty"` + // Node entries for deletion, no need to distinguish what it is from, just read them // into the partial db DeletionProofs []hexutil.Bytes `json:"deletionProofs,omitempty"` diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index c90bb1ea0c25..54a308694151 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -113,11 +113,13 @@ func CreateTraceEnvHelper(chainConfig *params.ChainConfig, logConfig *vm.LogConf state: statedb, blockCtx: blockCtx, StorageTrace: &types.StorageTrace{ - RootBefore: rootBefore, - RootAfter: block.Root(), - Proofs: make(map[string][]hexutil.Bytes), - StorageProofs: make(map[string]map[string][]hexutil.Bytes), - FlattenProofs: make(map[string]hexutil.Bytes), + RootBefore: rootBefore, + RootAfter: block.Root(), + Proofs: make(map[string][]hexutil.Bytes), + StorageProofs: make(map[string]map[string][]hexutil.Bytes), + FlattenProofs: make(map[common.Hash]hexutil.Bytes), + AddressHashes: make(map[common.Address]common.Hash), + StoreKeyHashes: make(map[common.Hash]common.Hash), }, Codes: make(map[common.Hash]vm.CodeInfo), ZkTrieTracer: make(map[string]state.ZktrieProofTracer), @@ -175,12 +177,13 @@ func CreateTraceEnv(chainConfig *params.ChainConfig, chainContext core.ChainCont key := coinbase.String() if _, exist := env.Proofs[key]; !exist { - proof, err := env.state.GetFullProof(coinbase) + proof, addrHash, err := env.state.GetFullProof(coinbase) if err != nil { log.Error("Proof for coinbase not available", "coinbase", coinbase, "error", err) // but we still mark the proofs map with nil array } // TODO: + env.AddressHashes[coinbase] = addrHash env.fillFlattenStorageProof(nil, proof) env.Proofs[key] = types.WrapProof(proof.GetData()) } @@ -256,7 +259,7 @@ func (env *TraceEnv) GetBlockTrace(block *types.Block) (*types.BlockTrace, error pend.Wait() // after all tx has been traced, collect "deletion proof" for zktrie - deleteionProofs := make(map[string]hexutil.Bytes) + deleteionProofs := make(map[common.Hash]hexutil.Bytes) for _, tracer := range env.ZkTrieTracer { delProofs, err := tracer.GetDeletionProofs() @@ -264,7 +267,7 @@ func (env *TraceEnv) GetBlockTrace(block *types.Block) (*types.BlockTrace, error log.Error("deletion proof failure", "error", err) } else { for key, proof := range delProofs { - deleteionProofs[hexutil.Encode(key.Bytes())] = proof + deleteionProofs[common.BytesToHash(key.Bytes())] = proof env.DeletionProofs = append(env.DeletionProofs, proof) } } @@ -389,9 +392,11 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B } txStorageTrace := &types.StorageTrace{ - Proofs: make(map[string][]hexutil.Bytes), - StorageProofs: make(map[string]map[string][]hexutil.Bytes), - FlattenProofs: make(map[string]hexutil.Bytes), + Proofs: make(map[string][]hexutil.Bytes), + StorageProofs: make(map[string]map[string][]hexutil.Bytes), + FlattenProofs: make(map[common.Hash]hexutil.Bytes), + AddressHashes: make(map[common.Address]common.Hash), + StoreKeyHashes: make(map[common.Hash]common.Hash), } // still we have no state root for per tx, only set the head and tail if index == 0 { @@ -425,7 +430,7 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B if existed { continue } - proof, err := state.GetFullProof(addr) + proof, addrHash, err := state.GetFullProof(addr) if err != nil { log.Error("Proof not available", "address", addrStr, "error", err) // but we still mark the proofs map with nil array @@ -434,6 +439,8 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B env.pMu.Lock() // TODO: env.fillFlattenStorageProof(txStorageTrace, proof) + txStorageTrace.AddressHashes[addr] = addrHash + env.AddressHashes[addr] = addrHash env.Proofs[addrStr] = wrappedProof txStorageTrace.Proofs[addrStr] = wrappedProof env.pMu.Unlock() @@ -486,11 +493,12 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B env.sMu.Unlock() var proof proofList + var keyHash common.Hash var err error if zktrieTracer.Available() { - proof, err = state.GetSecureTrieProof(zktrieTracer, key) + proof, keyHash, err = state.GetSecureTrieProof(zktrieTracer, key) } else { - proof, err = state.GetSecureTrieProof(trie, key) + proof, keyHash, err = state.GetSecureTrieProof(trie, key) } if err != nil { log.Error("Storage proof not available", "error", err, "address", addrStr, "key", keyStr) @@ -500,6 +508,8 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B env.pMu.Lock() // TODO: env.fillFlattenStorageProof(txStorageTrace, proof) + txStorageTrace.StoreKeyHashes[key] = keyHash + env.StoreKeyHashes[key] = keyHash env.pMu.Unlock() wrappedProof := types.WrapProof(proof.GetData()) @@ -545,11 +555,10 @@ func (env *TraceEnv) fillFlattenStorageProof(trace *types.StorageTrace, proof pr for _, i := range proof { // the "raw key" is in fact a zktrie.Hash (bytes stored with little-endian) // we need to convert it into big-endian - hashContainer := zktrie.NewHashFromBytes(i.Key) - keyStr := hexutil.Encode(hashContainer[:]) - env.FlattenProofs[keyStr] = i.Value + hash := common.BytesToHash(zktrie.NewHashFromBytes(i.Key)[:]) + env.FlattenProofs[hash] = i.Value if trace != nil { - trace.FlattenProofs[keyStr] = i.Value + trace.FlattenProofs[hash] = i.Value } } } @@ -582,11 +591,12 @@ func (env *TraceEnv) fillBlockTrace(block *types.Block) (*types.BlockTrace, erro for addr, storages := range intrinsicStorageProofs { if _, existed := env.Proofs[addr.String()]; !existed { - if proof, err := statedb.GetFullProof(addr); err != nil { + if proof, addrHash, err := statedb.GetFullProof(addr); err != nil { log.Error("Proof for intrinstic address not available", "error", err, "address", addr) } else { // TODO: env.fillFlattenStorageProof(nil, proof) + env.AddressHashes[addr] = addrHash env.Proofs[addr.String()] = types.WrapProof(proof.GetData()) } } @@ -599,11 +609,12 @@ func (env *TraceEnv) fillBlockTrace(block *types.Block) (*types.BlockTrace, erro if _, existed := env.StorageProofs[addr.String()][slot.String()]; !existed { if trie, err := statedb.GetStorageTrieForProof(addr); err != nil { log.Error("Storage proof for intrinstic address not available", "error", err, "address", addr) - } else if proof, err := statedb.GetSecureTrieProof(trie, slot); err != nil { + } else if proof, keyHash, err := statedb.GetSecureTrieProof(trie, slot); err != nil { log.Error("Get storage proof for intrinstic address failed", "error", err, "address", addr, "slot", slot) } else { // TODO: env.fillFlattenStorageProof(nil, proof) + env.StoreKeyHashes[slot] = keyHash env.StorageProofs[addr.String()][slot.String()] = types.WrapProof(proof.GetData()) } } From 3a805b4c6e9aceb110381ca51cb356de47f8037c Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Tue, 13 Aug 2024 19:11:33 +0800 Subject: [PATCH 10/17] filter for l2trace --- core/types/l2trace.go | 18 ++++++++++++++++++ eth/tracers/api_blocktrace.go | 15 ++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/core/types/l2trace.go b/core/types/l2trace.go index 637732b95342..6c125def6f64 100644 --- a/core/types/l2trace.go +++ b/core/types/l2trace.go @@ -58,6 +58,24 @@ type StorageTrace struct { DeletionProofs []hexutil.Bytes `json:"deletionProofs,omitempty"` } +func (tr *StorageTrace) ApplyFilter(legacy bool) { + if legacy { + tr.FlattenProofs = nil + tr.AddressHashes = nil + tr.StoreKeyHashes = nil + } else { + for k := range tr.Proofs { + tr.Proofs[k] = []hexutil.Bytes{} + } + for _, st := range tr.StorageProofs { + for k := range st { + st[k] = []hexutil.Bytes{} + } + } + tr.DeletionProofs = []hexutil.Bytes{} + } +} + // ExecutionResult groups all structured logs emitted by the EVM // while replaying a transaction in debug mode as well as transaction // execution status, the amount of gas used and the return value diff --git a/eth/tracers/api_blocktrace.go b/eth/tracers/api_blocktrace.go index a52daa29983d..e9cc964852aa 100644 --- a/eth/tracers/api_blocktrace.go +++ b/eth/tracers/api_blocktrace.go @@ -81,6 +81,7 @@ func (api *API) GetTxBlockTraceOnTopOfBlock(ctx context.Context, tx *types.Trans // Make trace environment for current block, and then get the trace for the block. func (api *API) createTraceEnvAndGetBlockTrace(ctx context.Context, config *TraceConfig, block *types.Block) (*types.BlockTrace, error) { + legacyTrace := false if config == nil { config = &TraceConfig{ LogConfig: &vm.LogConfig{ @@ -91,6 +92,10 @@ func (api *API) createTraceEnvAndGetBlockTrace(ctx context.Context, config *Trac }, } } else if config.Tracer != nil { + if *config.Tracer == "legacy" { + legacyTrace = true + } + config.Tracer = nil log.Warn("Tracer params is unsupported") } @@ -109,5 +114,13 @@ func (api *API) createTraceEnvAndGetBlockTrace(ctx context.Context, config *Trac } chaindb := api.backend.ChainDb() - return api.scrollTracerWrapper.CreateTraceEnvAndGetBlockTrace(api.backend.ChainConfig(), api.chainContext(ctx), api.backend.Engine(), chaindb, statedb, parent, block, true) + l2Trace, err := api.scrollTracerWrapper.CreateTraceEnvAndGetBlockTrace(api.backend.ChainConfig(), api.chainContext(ctx), api.backend.Engine(), chaindb, statedb, parent, block, true) + if err != nil { + return nil, err + } + l2Trace.StorageTrace.ApplyFilter(legacyTrace) + for _, st := range l2Trace.TxStorageTraces { + st.ApplyFilter(legacyTrace) + } + return l2Trace, nil } From 2a2b2b8565841d9662d70c27650683fc0da18715 Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Wed, 21 Aug 2024 20:48:46 +0800 Subject: [PATCH 11/17] add union mode --- core/vm/logger.go | 15 +++++++++------ eth/tracers/api_blocktrace.go | 23 +++++++++++++++-------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/core/vm/logger.go b/core/vm/logger.go index 740c7b93cc05..c6ffbf470948 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -50,12 +50,15 @@ func (s Storage) Copy() Storage { // LogConfig are the configuration options for structured logger the EVM type LogConfig struct { - EnableMemory bool // enable memory capture - DisableStack bool // disable stack capture - DisableStorage bool // disable storage capture - EnableReturnData bool // enable return data capture - Debug bool // print output during capture end - Limit int // maximum length of output, but zero means unlimited + EnableMemory bool // enable memory capture + DisableStack bool // disable stack capture + DisableStorage bool // disable storage capture + EnableReturnData bool // enable return data capture + Debug bool // print output during capture end + Limit int // maximum length of output, but zero means unlimited + StoragePoofFormat *string // format of storage proofs, can be + // "legacy" (use the legacy proof format) or + // "union" (output both flatten and legacy proof) // Chain overrides, can be used to execute a trace using future fork rules Overrides *params.ChainConfig `json:"overrides,omitempty"` } diff --git a/eth/tracers/api_blocktrace.go b/eth/tracers/api_blocktrace.go index e9cc964852aa..d7db5172b3fb 100644 --- a/eth/tracers/api_blocktrace.go +++ b/eth/tracers/api_blocktrace.go @@ -81,7 +81,8 @@ func (api *API) GetTxBlockTraceOnTopOfBlock(ctx context.Context, tx *types.Trans // Make trace environment for current block, and then get the trace for the block. func (api *API) createTraceEnvAndGetBlockTrace(ctx context.Context, config *TraceConfig, block *types.Block) (*types.BlockTrace, error) { - legacyTrace := false + legacyStorageTrace := false + unionStorageTrace := false if config == nil { config = &TraceConfig{ LogConfig: &vm.LogConfig{ @@ -92,14 +93,18 @@ func (api *API) createTraceEnvAndGetBlockTrace(ctx context.Context, config *Trac }, } } else if config.Tracer != nil { - if *config.Tracer == "legacy" { - legacyTrace = true - } - config.Tracer = nil log.Warn("Tracer params is unsupported") } + if config.StoragePoofFormat != nil { + if *config.StoragePoofFormat == "legacy" { + legacyStorageTrace = true + } else if *config.StoragePoofFormat == "union" { + unionStorageTrace = true + } + } + parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) if err != nil { return nil, err @@ -118,9 +123,11 @@ func (api *API) createTraceEnvAndGetBlockTrace(ctx context.Context, config *Trac if err != nil { return nil, err } - l2Trace.StorageTrace.ApplyFilter(legacyTrace) - for _, st := range l2Trace.TxStorageTraces { - st.ApplyFilter(legacyTrace) + if !unionStorageTrace { + l2Trace.StorageTrace.ApplyFilter(legacyStorageTrace) + for _, st := range l2Trace.TxStorageTraces { + st.ApplyFilter(legacyStorageTrace) + } } return l2Trace, nil } From 164adae856aaa8153d130b78231a1a986df4c54f Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Wed, 21 Aug 2024 21:38:04 +0800 Subject: [PATCH 12/17] fix typo --- core/vm/logger.go | 14 +++++++------- eth/tracers/api_blocktrace.go | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/vm/logger.go b/core/vm/logger.go index c6ffbf470948..156aba21f140 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -50,13 +50,13 @@ func (s Storage) Copy() Storage { // LogConfig are the configuration options for structured logger the EVM type LogConfig struct { - EnableMemory bool // enable memory capture - DisableStack bool // disable stack capture - DisableStorage bool // disable storage capture - EnableReturnData bool // enable return data capture - Debug bool // print output during capture end - Limit int // maximum length of output, but zero means unlimited - StoragePoofFormat *string // format of storage proofs, can be + EnableMemory bool // enable memory capture + DisableStack bool // disable stack capture + DisableStorage bool // disable storage capture + EnableReturnData bool // enable return data capture + Debug bool // print output during capture end + Limit int // maximum length of output, but zero means unlimited + StorageProofFormat *string // format of storage proofs, can be // "legacy" (use the legacy proof format) or // "union" (output both flatten and legacy proof) // Chain overrides, can be used to execute a trace using future fork rules diff --git a/eth/tracers/api_blocktrace.go b/eth/tracers/api_blocktrace.go index d7db5172b3fb..53d79b90cef3 100644 --- a/eth/tracers/api_blocktrace.go +++ b/eth/tracers/api_blocktrace.go @@ -97,10 +97,10 @@ func (api *API) createTraceEnvAndGetBlockTrace(ctx context.Context, config *Trac log.Warn("Tracer params is unsupported") } - if config.StoragePoofFormat != nil { - if *config.StoragePoofFormat == "legacy" { + if config.LogConfig != nil && config.StorageProofFormat != nil { + if *config.StorageProofFormat == "legacy" { legacyStorageTrace = true - } else if *config.StoragePoofFormat == "union" { + } else if *config.StorageProofFormat == "union" { unionStorageTrace = true } } From da019eef04a89ef5ebd056803b222f6a0b31690e Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Wed, 21 Aug 2024 21:51:54 +0800 Subject: [PATCH 13/17] fix go imports --- rollup/tracing/tracing.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index 54a308694151..94922eaf7b1d 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -8,6 +8,8 @@ import ( "sync" "time" + zktrie "github.com/scroll-tech/zktrie/types" + "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common/hexutil" "github.com/scroll-tech/go-ethereum/consensus" @@ -26,7 +28,6 @@ import ( "github.com/scroll-tech/go-ethereum/rollup/fees" "github.com/scroll-tech/go-ethereum/rollup/rcfg" "github.com/scroll-tech/go-ethereum/rollup/withdrawtrie" - zktrie "github.com/scroll-tech/zktrie/types" ) var ( From 13e46cfeab81d6f0d736ddc8a8f70915d4bb257a Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Thu, 22 Aug 2024 18:17:16 +0800 Subject: [PATCH 14/17] set default format to legacy --- eth/tracers/api_blocktrace.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eth/tracers/api_blocktrace.go b/eth/tracers/api_blocktrace.go index 53d79b90cef3..fa9de7a82dbf 100644 --- a/eth/tracers/api_blocktrace.go +++ b/eth/tracers/api_blocktrace.go @@ -81,7 +81,7 @@ func (api *API) GetTxBlockTraceOnTopOfBlock(ctx context.Context, tx *types.Trans // Make trace environment for current block, and then get the trace for the block. func (api *API) createTraceEnvAndGetBlockTrace(ctx context.Context, config *TraceConfig, block *types.Block) (*types.BlockTrace, error) { - legacyStorageTrace := false + legacyStorageTrace := true unionStorageTrace := false if config == nil { config = &TraceConfig{ @@ -98,8 +98,8 @@ func (api *API) createTraceEnvAndGetBlockTrace(ctx context.Context, config *Trac } if config.LogConfig != nil && config.StorageProofFormat != nil { - if *config.StorageProofFormat == "legacy" { - legacyStorageTrace = true + if *config.StorageProofFormat == "flatten" { + legacyStorageTrace = false } else if *config.StorageProofFormat == "union" { unionStorageTrace = true } From 796882908e3f1226e675915b23ae2a0af36b1a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Irmak?= Date: Thu, 22 Aug 2024 19:23:22 +0300 Subject: [PATCH 15/17] ++ --- eth/tracers/api_blocktrace.go | 64 +++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/eth/tracers/api_blocktrace.go b/eth/tracers/api_blocktrace.go index a52daa29983d..048cee370a56 100644 --- a/eth/tracers/api_blocktrace.go +++ b/eth/tracers/api_blocktrace.go @@ -79,6 +79,70 @@ func (api *API) GetTxBlockTraceOnTopOfBlock(ctx context.Context, tx *types.Trans return api.createTraceEnvAndGetBlockTrace(ctx, config, block) } +func (api *API) GetTxByTxBlockTrace(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) ([]*types.BlockTrace, error) { + if api.scrollTracerWrapper == nil { + return nil, errNoScrollTracerWrapper + } + + // Try to retrieve the specified block + var ( + err error + block *types.Block + ) + if number, ok := blockNrOrHash.Number(); ok { + block, err = api.blockByNumber(ctx, number) + } else if hash, ok := blockNrOrHash.Hash(); ok { + block, err = api.blockByHash(ctx, hash) + } else { + return nil, errors.New("invalid arguments; neither block number nor hash specified") + } + if err != nil { + return nil, err + } + if block.NumberU64() == 0 { + return nil, errors.New("genesis is not traceable") + } + + if config == nil { + config = &TraceConfig{ + LogConfig: &vm.LogConfig{ + DisableStorage: true, + DisableStack: true, + EnableMemory: false, + EnableReturnData: true, + }, + } + } else if config.Tracer != nil { + config.Tracer = nil + log.Warn("Tracer params is unsupported") + } + + parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) + if err != nil { + return nil, err + } + reexec := defaultTraceReexec + if config != nil && config.Reexec != nil { + reexec = *config.Reexec + } + statedb, err := api.backend.StateAtBlock(ctx, parent, reexec, nil, true, true) + if err != nil { + return nil, err + } + + chaindb := api.backend.ChainDb() + traces := []*types.BlockTrace{} + for _, tx := range block.Transactions() { + singleTxBlock := types.NewBlockWithHeader(block.Header()).WithBody([]*types.Transaction{tx}, nil) + trace, err := api.scrollTracerWrapper.CreateTraceEnvAndGetBlockTrace(api.backend.ChainConfig(), api.chainContext(ctx), api.backend.Engine(), chaindb, statedb, parent, singleTxBlock, true) + if err != nil { + return nil, err + } + traces = append(traces, trace) + } + return traces, nil +} + // Make trace environment for current block, and then get the trace for the block. func (api *API) createTraceEnvAndGetBlockTrace(ctx context.Context, config *TraceConfig, block *types.Block) (*types.BlockTrace, error) { if config == nil { From e565e14ffb75f3a67180eab729101ccfe3613ef9 Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Sat, 7 Sep 2024 10:46:50 +0800 Subject: [PATCH 16/17] induce partial trace mode --- eth/tracers/api_blocktrace.go | 16 +++++++++++++- rollup/tracing/tracing.go | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/eth/tracers/api_blocktrace.go b/eth/tracers/api_blocktrace.go index dd91ba75b5ae..8a255a9832a2 100644 --- a/eth/tracers/api_blocktrace.go +++ b/eth/tracers/api_blocktrace.go @@ -22,8 +22,14 @@ type TraceBlock interface { GetTxBlockTraceOnTopOfBlock(ctx context.Context, tx *types.Transaction, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (*types.BlockTrace, error) } +type TracerEnv interface { + ResetForPartialTrace(*types.Block) error + GetBlockTrace(*types.Block) (*types.BlockTrace, error) +} + type scrollTracerWrapper interface { CreateTraceEnvAndGetBlockTrace(*params.ChainConfig, core.ChainContext, consensus.Engine, ethdb.Database, *state.StateDB, *types.Block, *types.Block, bool) (*types.BlockTrace, error) + CreateTraceEnv(*params.ChainConfig, core.ChainContext, consensus.Engine, ethdb.Database, *state.StateDB, *types.Block, *types.Block, bool) (TracerEnv, error) } // GetBlockTraceByNumberOrHash replays the block and returns the structured BlockTrace by hash or number. @@ -132,12 +138,20 @@ func (api *API) GetTxByTxBlockTrace(ctx context.Context, blockNrOrHash rpc.Block chaindb := api.backend.ChainDb() traces := []*types.BlockTrace{} + traceEnv, err := api.scrollTracerWrapper.CreateTraceEnv(api.backend.ChainConfig(), api.chainContext(ctx), api.backend.Engine(), chaindb, statedb, parent, block, true) + if err != nil { + return nil, err + } for _, tx := range block.Transactions() { singleTxBlock := types.NewBlockWithHeader(block.Header()).WithBody([]*types.Transaction{tx}, nil) - trace, err := api.scrollTracerWrapper.CreateTraceEnvAndGetBlockTrace(api.backend.ChainConfig(), api.chainContext(ctx), api.backend.Engine(), chaindb, statedb, parent, singleTxBlock, true) + if err := traceEnv.ResetForPartialTrace(singleTxBlock); err != nil { + return nil, err + } + trace, err := traceEnv.GetBlockTrace(singleTxBlock) if err != nil { return nil, err } + trace.StorageTrace.ApplyFilter(false) traces = append(traces, trace) } return traces, nil diff --git a/rollup/tracing/tracing.go b/rollup/tracing/tracing.go index 254595d1c715..b6693bedf490 100644 --- a/rollup/tracing/tracing.go +++ b/rollup/tracing/tracing.go @@ -50,6 +50,11 @@ func NewTracerWrapper() *TracerWrapper { return &TracerWrapper{} } +func (tw *TracerWrapper) CreateTraceEnv(chainConfig *params.ChainConfig, chainContext core.ChainContext, engine consensus.Engine, chaindb ethdb.Database, statedb *state.StateDB, parent *types.Block, block *types.Block, commitAfterApply bool) (tracers.TracerEnv, error) { + traceEnv, err := CreateTraceEnv(chainConfig, chainContext, engine, chaindb, statedb, parent, block, commitAfterApply) + return traceEnv, err +} + // CreateTraceEnvAndGetBlockTrace wraps the whole block tracing logic for a block func (tw *TracerWrapper) CreateTraceEnvAndGetBlockTrace(chainConfig *params.ChainConfig, chainContext core.ChainContext, engine consensus.Engine, chaindb ethdb.Database, statedb *state.StateDB, parent *types.Block, block *types.Block, commitAfterApply bool) (*types.BlockTrace, error) { traceEnv, err := CreateTraceEnv(chainConfig, chainContext, engine, chaindb, statedb, parent, block, commitAfterApply) @@ -192,6 +197,41 @@ func CreateTraceEnv(chainConfig *params.ChainConfig, chainContext core.ChainCont return env, nil } +func (env *TraceEnv) ResetForPartialTrace(partialBlk *types.Block) error { + + if env.StorageTrace == nil { + return fmt.Errorf("not init") + } + + // TODO: can we chained the RootBefore / After? + oldStorage := env.StorageTrace + + // only reset which can be reset + env.signer = types.MakeSigner(env.chainConfig, partialBlk.Number()) + env.StorageTrace = &types.StorageTrace{ + RootBefore: oldStorage.RootBefore, + RootAfter: partialBlk.Root(), + Proofs: make(map[string][]hexutil.Bytes), + StorageProofs: make(map[string]map[string][]hexutil.Bytes), + FlattenProofs: make(map[common.Hash]hexutil.Bytes), + AddressHashes: make(map[common.Address]common.Hash), + StoreKeyHashes: make(map[common.Hash]common.Hash), + } + env.Codes = make(map[common.Hash]vm.CodeInfo) + env.ExecutionResults = make([]*types.ExecutionResult, partialBlk.Transactions().Len()) + env.TxStorageTraces = make([]*types.StorageTrace, partialBlk.Transactions().Len()) + + // still need to restore coinbase's proof .... + proof, addrHash, err := env.state.GetFullProof(env.coinbase) + if err == nil { + env.AddressHashes[env.coinbase] = addrHash + env.fillFlattenStorageProof(nil, proof) + env.Proofs[env.coinbase.String()] = types.WrapProof(proof.GetData()) + } + + return nil +} + func (env *TraceEnv) GetBlockTrace(block *types.Block) (*types.BlockTrace, error) { // Execute all the transaction contained within the block concurrently var ( From 9ce5c5ad5eb7b73dbc4578ab4ce74a401791bd11 Mon Sep 17 00:00:00 2001 From: Ho Vei Date: Sat, 7 Sep 2024 19:31:38 +0800 Subject: [PATCH 17/17] disable trace filter --- eth/tracers/api_blocktrace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/tracers/api_blocktrace.go b/eth/tracers/api_blocktrace.go index 8a255a9832a2..c69b9f9fbec2 100644 --- a/eth/tracers/api_blocktrace.go +++ b/eth/tracers/api_blocktrace.go @@ -151,7 +151,7 @@ func (api *API) GetTxByTxBlockTrace(ctx context.Context, blockNrOrHash rpc.Block if err != nil { return nil, err } - trace.StorageTrace.ApplyFilter(false) + // trace.StorageTrace.ApplyFilter(false) traces = append(traces, trace) } return traces, nil