feat(trace): add per_tx_storage_trace (#372)

* add proof for predeployed storages

* reverse inneeded code

* update for mainbranch merging

* add pertx storage trace

* dummy tx proof

* add txstorage trace

* add coinbase storage as trace

* Update version.go

* address comments

---------

Co-authored-by: Ho Vei <noelwei@gmail.com>
This commit is contained in:
HAOYUatHZ 2023-07-04 22:21:12 +08:00 committed by GitHub
parent 38a6a1e964
commit 3cf5ba882d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 3 deletions

View file

@ -17,6 +17,7 @@ type BlockTrace struct {
Header *Header `json:"header"` Header *Header `json:"header"`
Transactions []*TransactionData `json:"transactions"` Transactions []*TransactionData `json:"transactions"`
StorageTrace *StorageTrace `json:"storageTrace"` StorageTrace *StorageTrace `json:"storageTrace"`
TxStorageTraces []*StorageTrace `json:"txStorageTraces,omitempty"`
ExecutionResults []*ExecutionResult `json:"executionResults"` ExecutionResults []*ExecutionResult `json:"executionResults"`
MPTWitness *json.RawMessage `json:"mptwitness,omitempty"` MPTWitness *json.RawMessage `json:"mptwitness,omitempty"`
WithdrawTrieRoot common.Hash `json:"withdraw_trie_root,omitempty"` WithdrawTrieRoot common.Hash `json:"withdraw_trie_root,omitempty"`

View file

@ -44,6 +44,7 @@ type traceEnv struct {
// this lock is used to protect StorageTrace's read and write mutual exclusion. // this lock is used to protect StorageTrace's read and write mutual exclusion.
sMu sync.Mutex sMu sync.Mutex
*types.StorageTrace *types.StorageTrace
txStorageTraces []*types.StorageTrace
// zktrie tracer is used for zktrie storage to build additional deletion proof // zktrie tracer is used for zktrie storage to build additional deletion proof
zkTrieTracer map[string]state.ZktrieProofTracer zkTrieTracer map[string]state.ZktrieProofTracer
executionResults []*types.ExecutionResult executionResults []*types.ExecutionResult
@ -125,6 +126,7 @@ func (api *API) createTraceEnv(ctx context.Context, config *TraceConfig, block *
}, },
zkTrieTracer: make(map[string]state.ZktrieProofTracer), zkTrieTracer: make(map[string]state.ZktrieProofTracer),
executionResults: make([]*types.ExecutionResult, block.Transactions().Len()), executionResults: make([]*types.ExecutionResult, block.Transactions().Len()),
txStorageTraces: make([]*types.StorageTrace, block.Transactions().Len()),
} }
key := coinbase.String() key := coinbase.String()
@ -211,6 +213,13 @@ func (api *API) getBlockTrace(block *types.Block, env *traceEnv) (*types.BlockTr
} }
} }
// build dummy per-tx deletion proof
for _, txStorageTrace := range env.txStorageTraces {
if txStorageTrace != nil {
txStorageTrace.DeletionProofs = env.DeletionProofs
}
}
// If execution failed in between, abort // If execution failed in between, abort
select { select {
case err := <-errCh: case err := <-errCh:
@ -298,6 +307,17 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
}) })
} }
txStorageTrace := &types.StorageTrace{
Proofs: make(map[string][]hexutil.Bytes),
StorageProofs: make(map[string]map[string][]hexutil.Bytes),
}
// still we have no state root for per tx, only set the head and tail
if index == 0 {
txStorageTrace.RootBefore = state.GetRootHash()
} else if index == len(block.Transactions())-1 {
txStorageTrace.RootAfter = block.Root()
}
// merge required proof data // merge required proof data
proofAccounts := tracer.UpdatedAccounts() proofAccounts := tracer.UpdatedAccounts()
proofAccounts[vmenv.FeeRecipient()] = struct{}{} proofAccounts[vmenv.FeeRecipient()] = struct{}{}
@ -306,7 +326,10 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
addrStr := addr.String() addrStr := addr.String()
env.pMu.Lock() env.pMu.Lock()
_, existed := env.Proofs[addrStr] checkedProof, existed := env.Proofs[addrStr]
if existed {
txStorageTrace.Proofs[addrStr] = checkedProof
}
env.pMu.Unlock() env.pMu.Unlock()
if existed { if existed {
continue continue
@ -322,6 +345,7 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
} }
env.pMu.Lock() env.pMu.Lock()
env.Proofs[addrStr] = wrappedProof env.Proofs[addrStr] = wrappedProof
txStorageTrace.Proofs[addrStr] = wrappedProof
env.pMu.Unlock() env.pMu.Unlock()
} }
@ -333,6 +357,10 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
rcfg.ScalarSlot: {}, rcfg.ScalarSlot: {},
}) })
for addr, keys := range proofStorages { for addr, keys := range proofStorages {
if _, existed := txStorageTrace.StorageProofs[addr.String()]; !existed {
txStorageTrace.StorageProofs[addr.String()] = make(map[string][]hexutil.Bytes)
}
env.sMu.Lock() env.sMu.Lock()
trie, err := state.GetStorageTrieForProof(addr) trie, err := state.GetStorageTrieForProof(addr)
if err != nil { if err != nil {
@ -349,6 +377,7 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
keyStr := key.String() keyStr := key.String()
isDelete := bytes.Equal(values.Bytes(), common.Hash{}.Bytes()) isDelete := bytes.Equal(values.Bytes(), common.Hash{}.Bytes())
txm := txStorageTrace.StorageProofs[addrStr]
env.sMu.Lock() env.sMu.Lock()
m, existed := env.StorageProofs[addrStr] m, existed := env.StorageProofs[addrStr]
if !existed { if !existed {
@ -357,7 +386,8 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
if zktrieTracer.Available() { if zktrieTracer.Available() {
env.zkTrieTracer[addrStr] = state.NewProofTracer(trie) env.zkTrieTracer[addrStr] = state.NewProofTracer(trie)
} }
} else if _, existed := m[keyStr]; existed { } else if proof, existed := m[keyStr]; existed {
txm[keyStr] = proof
// still need to touch tracer for deletion // still need to touch tracer for deletion
if isDelete && zktrieTracer.Available() { if isDelete && zktrieTracer.Available() {
env.zkTrieTracer[addrStr].MarkDeletion(key) env.zkTrieTracer[addrStr].MarkDeletion(key)
@ -383,6 +413,7 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
wrappedProof[i] = bt wrappedProof[i] = bt
} }
env.sMu.Lock() env.sMu.Lock()
txm[keyStr] = wrappedProof
m[keyStr] = wrappedProof m[keyStr] = wrappedProof
if zktrieTracer.Available() { if zktrieTracer.Available() {
if isDelete { if isDelete {
@ -405,6 +436,7 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc
ReturnValue: fmt.Sprintf("%x", returnVal), ReturnValue: fmt.Sprintf("%x", returnVal),
StructLogs: vm.FormatLogs(tracer.StructLogs()), StructLogs: vm.FormatLogs(tracer.StructLogs()),
} }
env.txStorageTraces[index] = txStorageTrace
return nil return nil
} }
@ -461,6 +493,7 @@ func (api *API) fillBlockTrace(env *traceEnv, block *types.Block) (*types.BlockT
Header: block.Header(), Header: block.Header(),
StorageTrace: env.StorageTrace, StorageTrace: env.StorageTrace,
ExecutionResults: env.executionResults, ExecutionResults: env.executionResults,
TxStorageTraces: env.txStorageTraces,
Transactions: txs, Transactions: txs,
} }

View file

@ -24,7 +24,7 @@ import (
const ( const (
VersionMajor = 4 // Major version component of the current release VersionMajor = 4 // Major version component of the current release
VersionMinor = 2 // Minor version component of the current release VersionMinor = 2 // Minor version component of the current release
VersionPatch = 5 // Patch version component of the current release VersionPatch = 6 // Patch version component of the current release
VersionMeta = "sepolia" // Version metadata to append to the version string VersionMeta = "sepolia" // Version metadata to append to the version string
) )