Skip to content

Commit d3bc832

Browse files
lispcmask-ppnoel20040xmountaintop
authored
zktrie part1: change storage proof from per step to per block (#102)
* change storage proof from step-wise to block-wise. Step-wise proof will be reconstructed in prover side * minor * minor * Update worker.go * purge hexInt * Update l2trace.go * Refactor l2witness/opt-storage-proof (#112) * rename GetStateData to GetLiveStateObject * revert EvmTxTraces type * rename GetLiveStateObject to GetLiveStateAccount * fix typo * some renamings * format codes * fix typo * fix typos * format codes some reverts some renamings some renamings format codes * update comments update comments * update comments update comments update comments * update comments update comments update comments * rename * rename * update * update comments Co-authored-by: maskpp <maskpp266@gmail.com> Co-authored-by: Ho Vei <noelwei@gmail.com> Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
1 parent 35f6a91 commit d3bc832

9 files changed

+334
-217
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# Auto detect text files and perform LF normalization
22
* text=auto
33
*.sol linguist-language=Solidity
4+
*.go text eol=lf

core/blockchain.go

+10-45
Original file line numberDiff line numberDiff line change
@@ -1193,17 +1193,17 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
11931193
}
11941194

11951195
// WriteBlockWithState writes the block and all associated state to the database.
1196-
func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces []*types.ExecutionResult, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
1196+
func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces []*types.ExecutionResult, storageTrace *types.StorageTrace, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
11971197
if !bc.chainmu.TryLock() {
11981198
return NonStatTy, errInsertionInterrupted
11991199
}
12001200
defer bc.chainmu.Unlock()
1201-
return bc.writeBlockWithState(block, receipts, logs, evmTraces, state, emitHeadEvent)
1201+
return bc.writeBlockWithState(block, receipts, logs, evmTraces, storageTrace, state, emitHeadEvent)
12021202
}
12031203

12041204
// writeBlockWithState writes the block and all associated state to the database,
12051205
// but is expects the chain mutex to be held.
1206-
func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces []*types.ExecutionResult, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
1206+
func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, logs []*types.Log, evmTraces []*types.ExecutionResult, storageTrace *types.StorageTrace, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
12071207
if bc.insertStopped() {
12081208
return NonStatTy, errInsertionInterrupted
12091209
}
@@ -1327,7 +1327,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
13271327
// Fill blockResult content
13281328
var blockResult *types.BlockResult
13291329
if evmTraces != nil {
1330-
blockResult = bc.writeBlockResult(state, block, evmTraces)
1330+
blockResult = bc.writeBlockResult(state, block, evmTraces, storageTrace)
13311331
bc.blockResultCache.Add(block.Hash(), blockResult)
13321332
}
13331333

@@ -1351,57 +1351,22 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
13511351
}
13521352

13531353
// Fill blockResult content
1354-
func (bc *BlockChain) writeBlockResult(state *state.StateDB, block *types.Block, evmTraces []*types.ExecutionResult) *types.BlockResult {
1354+
func (bc *BlockChain) writeBlockResult(state *state.StateDB, block *types.Block, evmTraces []*types.ExecutionResult, storageTrace *types.StorageTrace) *types.BlockResult {
13551355
blockResult := &types.BlockResult{
13561356
ExecutionResults: evmTraces,
1357+
StorageTrace: storageTrace,
13571358
}
1358-
coinbase := types.AccountProofWrapper{
1359+
coinbase := types.AccountWrapper{
13591360
Address: block.Coinbase(),
13601361
Nonce: state.GetNonce(block.Coinbase()),
13611362
Balance: (*hexutil.Big)(state.GetBalance(block.Coinbase())),
13621363
CodeHash: state.GetCodeHash(block.Coinbase()),
13631364
}
1364-
// Get coinbase address's account proof.
1365-
proof, err := state.GetProof(block.Coinbase())
1366-
if err != nil {
1367-
log.Error("Failed to get proof", "blockNumber", block.NumberU64(), "address", block.Coinbase().String(), "err", err)
1368-
} else {
1369-
coinbase.Proof = make([]string, len(proof))
1370-
for i := range proof {
1371-
coinbase.Proof[i] = hexutil.Encode(proof[i])
1372-
}
1373-
}
13741365

13751366
blockResult.BlockTrace = types.NewTraceBlock(bc.chainConfig, block, &coinbase)
1367+
blockResult.StorageTrace.RootAfter = state.GetRootHash()
13761368
for i, tx := range block.Transactions() {
13771369
evmTrace := blockResult.ExecutionResults[i]
1378-
1379-
from := evmTrace.From.Address
1380-
// Get proof
1381-
proof, err := state.GetProof(from)
1382-
if err != nil {
1383-
log.Error("Failed to get proof", "blockNumber", block.NumberU64(), "address", from.String(), "err", err)
1384-
} else {
1385-
evmTrace.From.Proof = make([]string, len(proof))
1386-
for i := range proof {
1387-
evmTrace.From.Proof[i] = hexutil.Encode(proof[i])
1388-
}
1389-
}
1390-
1391-
if evmTrace.To != nil {
1392-
to := evmTrace.To.Address
1393-
// Get proof
1394-
proof, err = state.GetProof(to)
1395-
if err != nil {
1396-
log.Error("Failed to get proof", "blockNumber", block.NumberU64(), "address", to.String(), "err", err)
1397-
} else {
1398-
evmTrace.To.Proof = make([]string, len(proof))
1399-
for i := range proof {
1400-
evmTrace.To.Proof[i] = hexutil.Encode(proof[i])
1401-
}
1402-
}
1403-
}
1404-
14051370
// Contract is called
14061371
if len(tx.Data()) != 0 && tx.To() != nil {
14071372
evmTrace.ByteCode = hexutil.Encode(state.GetCode(*tx.To()))
@@ -1727,8 +1692,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
17271692

17281693
// Write the block to the chain and get the status.
17291694
substart = time.Now()
1730-
// EvmTraces is nil is safe because l2geth's p2p server is stoped and the code will not execute there.
1731-
status, err := bc.writeBlockWithState(block, receipts, logs, nil, statedb, false)
1695+
// EvmTraces & StorageTrace being nil is safe because l2geth's p2p server is stoped and the code will not execute there.
1696+
status, err := bc.writeBlockWithState(block, receipts, logs, nil, nil, statedb, false)
17321697
atomic.StoreUint32(&followupInterrupt, 1)
17331698
if err != nil {
17341699
return it.index, err

core/state/statedb.go

+35
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,41 @@ func (s *StateDB) GetProofByHash(addrHash common.Hash) ([][]byte, error) {
325325
return proof, err
326326
}
327327

328+
func (s *StateDB) GetLiveStateAccount(addr common.Address) *types.StateAccount {
329+
obj, ok := s.stateObjects[addr]
330+
if !ok {
331+
return nil
332+
}
333+
return &obj.data
334+
}
335+
336+
func (s *StateDB) GetRootHash() common.Hash {
337+
return s.trie.Hash()
338+
}
339+
340+
// StorageTrieProof is not in Db interface and used explictily for reading proof in storage trie (not the dirty value)
341+
func (s *StateDB) GetStorageTrieProof(a common.Address, key common.Hash) ([][]byte, error) {
342+
// try the trie in stateObject first, else we would create one
343+
stateObject := s.getStateObject(a)
344+
if stateObject == nil {
345+
return nil, errors.New("storage trie for requested address does not exist")
346+
}
347+
348+
trie := stateObject.trie
349+
var err error
350+
if trie == nil {
351+
// use a new, temporary trie
352+
trie, err = s.db.OpenStorageTrie(stateObject.addrHash, stateObject.data.Root)
353+
if err != nil {
354+
return nil, fmt.Errorf("can't create storage trie on root %s: %v ", stateObject.data.Root, err)
355+
}
356+
}
357+
358+
var proof proofList
359+
err = trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof)
360+
return proof, err
361+
}
362+
328363
// GetStorageProof returns the Merkle proof for given storage slot.
329364
func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte, error) {
330365
var proof proofList

core/types/l2trace.go

+50-22
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,44 @@ var (
2323
// BlockResult contains block execution traces and results required for rollers.
2424
type BlockResult struct {
2525
BlockTrace *BlockTrace `json:"blockTrace"`
26+
StorageTrace *StorageTrace `json:"storageTrace"`
2627
ExecutionResults []*ExecutionResult `json:"executionResults"`
2728
}
2829

30+
// StorageTrace stores proofs of storage needed by storage circuit
31+
type StorageTrace struct {
32+
// Root hash before block execution:
33+
RootBefore common.Hash `json:"rootBefore,omitempty"`
34+
// Root hash after block execution, is nil if execution has failed
35+
RootAfter common.Hash `json:"rootAfter,omitempty"`
36+
37+
// All proofs BEFORE execution, for accounts which would be used in tracing
38+
Proofs map[string][]hexutil.Bytes `json:"proofs"`
39+
40+
// All storage proofs BEFORE execution
41+
StorageProofs map[string]map[string][]hexutil.Bytes `json:"storageProofs,omitempty"`
42+
}
43+
2944
// ExecutionResult groups all structured logs emitted by the EVM
3045
// while replaying a transaction in debug mode as well as transaction
3146
// execution status, the amount of gas used and the return value
3247
type ExecutionResult struct {
3348
Gas uint64 `json:"gas"`
3449
Failed bool `json:"failed"`
3550
ReturnValue string `json:"returnValue,omitempty"`
36-
// Sender's account proof.
37-
From *AccountProofWrapper `json:"from,omitempty"`
38-
// Receiver's account proof.
39-
To *AccountProofWrapper `json:"to,omitempty"`
40-
// It's exist only when tx is a contract call.
51+
// Sender's account state (before Tx)
52+
From *AccountWrapper `json:"from,omitempty"`
53+
// Receiver's account state (before Tx)
54+
To *AccountWrapper `json:"to,omitempty"`
55+
// AccountCreated record the account if the tx is "create"
56+
// (for creating inside a contract, we just handle CREATE op)
57+
AccountCreated *AccountWrapper `json:"accountCreated,omitempty"`
58+
59+
// Record all accounts' state which would be affected AFTER tx executed
60+
// currently they are just `from` and `to` account
61+
AccountsAfter []*AccountWrapper `json:"accountAfter"`
62+
63+
// `CodeHash` only exists when tx is a contract call.
4164
CodeHash *common.Hash `json:"codeHash,omitempty"`
4265
// If it is a contract call, the contract code is returned.
4366
ByteCode string `json:"byteCode,omitempty"`
@@ -77,30 +100,35 @@ func NewStructLogResBasic(pc uint64, op string, gas, gasCost uint64, depth int,
77100
}
78101

79102
type ExtraData struct {
103+
// Indicate the call succeeds or not for CALL/CREATE op
104+
CallFailed bool `json:"callFailed,omitempty"`
80105
// CALL | CALLCODE | DELEGATECALL | STATICCALL: [tx.to address’s code, stack.nth_last(1) address’s code]
81106
CodeList [][]byte `json:"codeList,omitempty"`
82107
// SSTORE | SLOAD: [storageProof]
83-
// SELFDESTRUCT: [contract address’s accountProof, stack.nth_last(0) address’s accountProof]
84-
// SELFBALANCE: [contract address’s accountProof]
85-
// BALANCE | EXTCODEHASH: [stack.nth_last(0) address’s accountProof]
86-
// CREATE | CREATE2: [sender's accountProof, created contract address’s accountProof]
87-
// CALL | CALLCODE: [caller contract address’s accountProof, stack.nth_last(1) address’s accountProof]
88-
ProofList []*AccountProofWrapper `json:"proofList,omitempty"`
108+
// SELFDESTRUCT: [contract address’s account, stack.nth_last(0) address’s account]
109+
// SELFBALANCE: [contract address’s account]
110+
// BALANCE | EXTCODEHASH: [stack.nth_last(0) address’s account]
111+
// CREATE | CREATE2: [created contract address’s account (before constructed),
112+
// created contract address's account (after constructed)]
113+
// CALL | CALLCODE: [caller contract address’s account,
114+
// stack.nth_last(1) (i.e. callee) address’s account,
115+
// callee contract address's account (value updated, before called)]
116+
// STATICCALL: [stack.nth_last(1) (i.e. callee) address’s account,
117+
// callee contract address's account (before called)]
118+
StateList []*AccountWrapper `json:"proofList,omitempty"`
89119
}
90120

91-
type AccountProofWrapper struct {
92-
Address common.Address `json:"address"`
93-
Nonce uint64 `json:"nonce"`
94-
Balance *hexutil.Big `json:"balance"`
95-
CodeHash common.Hash `json:"codeHash,omitempty"`
96-
Proof []string `json:"proof,omitempty"`
97-
Storage *StorageProofWrapper `json:"storage,omitempty"` // StorageProofWrapper can be empty if irrelated to storage operation
121+
type AccountWrapper struct {
122+
Address common.Address `json:"address"`
123+
Nonce uint64 `json:"nonce"`
124+
Balance *hexutil.Big `json:"balance"`
125+
CodeHash common.Hash `json:"codeHash,omitempty"`
126+
Storage *StorageWrapper `json:"storage,omitempty"` // StorageWrapper can be empty if irrelated to storage operation
98127
}
99128

100129
// while key & value can also be retrieved from StructLogRes.Storage,
101130
// we still stored in here for roller's processing convenience.
102-
type StorageProofWrapper struct {
103-
Key string `json:"key,omitempty"`
104-
Value string `json:"value,omitempty"`
105-
Proof []string `json:"proof,omitempty"`
131+
type StorageWrapper struct {
132+
Key string `json:"key,omitempty"`
133+
Value string `json:"value,omitempty"`
106134
}

core/types/l2trace_block.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import (
99
)
1010

1111
type BlockTrace struct {
12-
Number *hexutil.Big `json:"number"`
13-
Hash common.Hash `json:"hash"`
14-
GasLimit uint64 `json:"gasLimit"`
15-
Difficulty *hexutil.Big `json:"difficulty"`
16-
BaseFee *hexutil.Big `json:"baseFee"`
17-
Coinbase *AccountProofWrapper `json:"coinbase"`
18-
Time uint64 `json:"time"`
19-
Transactions []*TransactionTrace `json:"transactions"`
12+
Number *hexutil.Big `json:"number"`
13+
Hash common.Hash `json:"hash"`
14+
GasLimit uint64 `json:"gasLimit"`
15+
Difficulty *hexutil.Big `json:"difficulty"`
16+
BaseFee *hexutil.Big `json:"baseFee"`
17+
Coinbase *AccountWrapper `json:"coinbase"`
18+
Time uint64 `json:"time"`
19+
Transactions []*TransactionTrace `json:"transactions"`
2020
}
2121

2222
type TransactionTrace struct {
@@ -36,7 +36,7 @@ type TransactionTrace struct {
3636
}
3737

3838
// NewTraceBlock supports necessary fields for roller.
39-
func NewTraceBlock(config *params.ChainConfig, block *Block, coinbase *AccountProofWrapper) *BlockTrace {
39+
func NewTraceBlock(config *params.ChainConfig, block *Block, coinbase *AccountWrapper) *BlockTrace {
4040
txs := make([]*TransactionTrace, block.Transactions().Len())
4141
for i, tx := range block.Transactions() {
4242
txs[i] = newTraceTransaction(tx, block.NumberU64(), config)

core/vm/interface.go

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ type StateDB interface {
4747
GetState(common.Address, common.Hash) common.Hash
4848
SetState(common.Address, common.Hash, common.Hash)
4949

50+
GetRootHash() common.Hash
51+
GetLiveStateAccount(addr common.Address) *types.StateAccount
5052
GetProof(addr common.Address) ([][]byte, error)
5153
GetProofByHash(addrHash common.Hash) ([][]byte, error)
5254
GetStorageProof(a common.Address, key common.Hash) ([][]byte, error)

0 commit comments

Comments
 (0)