Skip to content

Commit 03c37cd

Browse files
rjl493456442fjl
andauthored
core/state: introduce code reader interface (ethereum#30816)
This PR introduces a `ContractCodeReader` interface with functions defined: type ContractCodeReader interface { Code(addr common.Address, codeHash common.Hash) ([]byte, error) CodeSize(addr common.Address, codeHash common.Hash) (int, error) } This interface can be implemented in various ways. Although the codebase currently includes only one implementation, additional implementations could be created for different purposes and scenarios, such as a code reader designed for the Verkle tree approach or one that reads code from the witness. *Notably, this interface modifies the function’s semantics. If the contract code is not found, no error will be returned. An error should only be returned in the event of an unexpected issue, primarily for future implementations.* The original state.Reader interface is extended with ContractCodeReader methods, it gives us more flexibility to manipulate the reader with additional logic on top, e.g. Hooks. type Reader interface { ContractCodeReader StateReader } --------- Co-authored-by: Felix Lange <[email protected]>
1 parent 05148d9 commit 03c37cd

File tree

8 files changed

+176
-120
lines changed

8 files changed

+176
-120
lines changed

core/blockchain_reader.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,10 +344,7 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool {
344344

345345
// ContractCodeWithPrefix retrieves a blob of data associated with a contract
346346
// hash either from ephemeral in-memory cache, or from persistent storage.
347-
//
348-
// If the code doesn't exist in the in-memory cache, check the storage with
349-
// new code scheme.
350-
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
347+
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) []byte {
351348
// TODO(rjl493456442) The associated account address is also required
352349
// in Verkle scheme. Fix it once snap-sync is supported for Verkle.
353350
return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash)

core/state/database.go

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package state
1818

1919
import (
20-
"errors"
2120
"fmt"
2221

2322
"github.com/ethereum/go-ethereum/common"
@@ -55,12 +54,6 @@ type Database interface {
5554
// OpenStorageTrie opens the storage trie of an account.
5655
OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error)
5756

58-
// ContractCode retrieves a particular contract's code.
59-
ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error)
60-
61-
// ContractCodeSize retrieves a particular contracts code's size.
62-
ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error)
63-
6457
// PointCache returns the cache holding points used in verkle tree key computation
6558
PointCache() *utils.PointCache
6659

@@ -180,15 +173,15 @@ func NewDatabaseForTesting() *CachingDB {
180173

181174
// Reader returns a state reader associated with the specified state root.
182175
func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
183-
var readers []Reader
176+
var readers []StateReader
184177

185178
// Set up the state snapshot reader if available. This feature
186179
// is optional and may be partially useful if it's not fully
187180
// generated.
188181
if db.snap != nil {
189182
snap := db.snap.Snapshot(stateRoot)
190183
if snap != nil {
191-
readers = append(readers, newStateReader(snap)) // snap reader is optional
184+
readers = append(readers, newFlatReader(snap))
192185
}
193186
}
194187
// Set up the trie reader, which is expected to always be available
@@ -199,7 +192,11 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
199192
}
200193
readers = append(readers, tr)
201194

202-
return newMultiReader(readers...)
195+
combined, err := newMultiStateReader(readers...)
196+
if err != nil {
197+
return nil, err
198+
}
199+
return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil
203200
}
204201

205202
// OpenTrie opens the main account trie at a specific root hash.
@@ -229,45 +226,20 @@ func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
229226
return tr, nil
230227
}
231228

232-
// ContractCode retrieves a particular contract's code.
233-
func (db *CachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
234-
code, _ := db.codeCache.Get(codeHash)
235-
if len(code) > 0 {
236-
return code, nil
237-
}
238-
code = rawdb.ReadCode(db.disk, codeHash)
239-
if len(code) > 0 {
240-
db.codeCache.Add(codeHash, code)
241-
db.codeSizeCache.Add(codeHash, len(code))
242-
return code, nil
243-
}
244-
return nil, errors.New("not found")
245-
}
246-
247229
// ContractCodeWithPrefix retrieves a particular contract's code. If the
248230
// code can't be found in the cache, then check the existence with **new**
249231
// db scheme.
250-
func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) {
232+
func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) []byte {
251233
code, _ := db.codeCache.Get(codeHash)
252234
if len(code) > 0 {
253-
return code, nil
235+
return code
254236
}
255237
code = rawdb.ReadCodeWithPrefix(db.disk, codeHash)
256238
if len(code) > 0 {
257239
db.codeCache.Add(codeHash, code)
258240
db.codeSizeCache.Add(codeHash, len(code))
259-
return code, nil
260-
}
261-
return nil, errors.New("not found")
262-
}
263-
264-
// ContractCodeSize retrieves a particular contracts code's size.
265-
func (db *CachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) {
266-
if cached, ok := db.codeSizeCache.Get(codeHash); ok {
267-
return cached, nil
268241
}
269-
code, err := db.ContractCode(addr, codeHash)
270-
return len(code), err
242+
return code
271243
}
272244

273245
// TrieDB retrieves any intermediate trie-node caching layer.

core/state/iterator.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,13 @@ func (it *nodeIterator) step() error {
136136
}
137137
if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
138138
it.codeHash = common.BytesToHash(account.CodeHash)
139-
it.code, err = it.state.db.ContractCode(address, common.BytesToHash(account.CodeHash))
139+
it.code, err = it.state.reader.Code(address, common.BytesToHash(account.CodeHash))
140140
if err != nil {
141141
return fmt.Errorf("code %x: %v", account.CodeHash, err)
142142
}
143+
if len(it.code) == 0 {
144+
return fmt.Errorf("code is not found: %x", account.CodeHash)
145+
}
143146
}
144147
it.accountHash = it.stateIt.Parent()
145148
return nil

0 commit comments

Comments
 (0)