Skip to content

Commit

Permalink
core,trie: use direct get for statedb
Browse files Browse the repository at this point in the history
  • Loading branch information
fynnss committed May 11, 2024
1 parent 462e2bf commit 22cee6d
Show file tree
Hide file tree
Showing 17 changed files with 285 additions and 43 deletions.
4 changes: 2 additions & 2 deletions core/rawdb/accessors_trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ func DeleteAccountTrieNode(db ethdb.KeyValueWriter, path []byte) {
func EncodeNibbles(bytes []byte) []byte {
nibbles := make([]byte, len(bytes)*2)
for i, b := range bytes {
nibbles[i*2] = b >> 4 // 取字节高4位
nibbles[i*2+1] = b & 0x0F // 取字节低4位
nibbles[i*2] = b >> 4
nibbles[i*2+1] = b & 0x0F
}
return nibbles
}
Expand Down
4 changes: 2 additions & 2 deletions core/state/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ type Trie interface {
// the trie, nil will be returned. If the trie is corrupted(e.g. some nodes
// are missing or the account blob is incorrect for decoding), an error will
// be returned.
GetAccount(address common.Address) (*types.StateAccount, error)
GetAccount(address common.Address, direct bool) (*types.StateAccount, error)

// GetStorage returns the value for key stored in the trie. The value bytes
// must not be modified by the caller. If a node was not found in the database,
// a trie.MissingNodeError is returned.
GetStorage(addr common.Address, key []byte) ([]byte, error)
GetStorage(addr common.Address, key []byte, direct bool) ([]byte, error)

// UpdateAccount abstracts an account write to the trie. It encodes the
// provided account object with associated algorithm and then updates it
Expand Down
2 changes: 1 addition & 1 deletion core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
s.db.setError(err)
return common.Hash{}
}
val, err := tr.GetStorage(s.address, key.Bytes())
val, err := tr.GetStorage(s.address, key.Bytes(), true)
s.db.StorageReads += time.Since(start)

if err != nil {
Expand Down
16 changes: 14 additions & 2 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
if data == nil {
start := time.Now()
var err error
data, err = s.trie.GetAccount(addr)
data, err = s.trie.GetAccount(addr, true)
s.AccountReads += time.Since(start)

if err != nil {
Expand Down Expand Up @@ -1292,7 +1292,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
}
if root != origin {
start = time.Now()
set := triestate.New(s.accountsOrigin, s.storagesOrigin)
set := triestate.New(s.accountsOrigin, s.storagesOrigin, s.mustConvertSlmAccount(s.accounts), s.storages, s.convertAccountSet(s.stateObjectsDestruct))
if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil {
return common.Hash{}, err
}
Expand All @@ -1313,6 +1313,18 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
return root, nil
}

func (s *StateDB) mustConvertSlmAccount(slmAccounts map[common.Hash][]byte) map[common.Hash][]byte {
ret := make(map[common.Hash][]byte)
for h, acc := range slmAccounts {
fullAccount, err := types.FullAccountRLP(acc)
if err != nil {
panic(fmt.Sprintf("mustConvertSlmAccount, acc: %v", common.Bytes2Hex(acc)))
}
ret[h] = fullAccount
}
return ret
}

// Prepare handles the preparatory steps for executing a state transition with.
// This method must be invoked before state transition.
//
Expand Down
4 changes: 2 additions & 2 deletions core/state/trie_prefetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,9 @@ func (sf *subfetcher) loop() {
sf.dups++
} else {
if len(task) == common.AddressLength {
sf.trie.GetAccount(common.BytesToAddress(task))
sf.trie.GetAccount(common.BytesToAddress(task), false)
} else {
sf.trie.GetStorage(sf.addr, task)
sf.trie.GetStorage(sf.addr, task, false)
}
sf.seen[string(task)] = struct{}{}
}
Expand Down
24 changes: 20 additions & 4 deletions trie/secure_trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,16 @@ func (t *StateTrie) MustGet(key []byte) []byte {
// and slot key. The value bytes must not be modified by the caller.
// If the specified storage slot is not in the trie, nil will be returned.
// If a trie node is not found in the database, a MissingNodeError is returned.
func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
enc, err := t.trie.Get(t.hashKey(key))
func (t *StateTrie) GetStorage(_ common.Address, key []byte, direct bool) ([]byte, error) {
var (
enc []byte
err error
)
if direct {
enc, err = t.trie.GetDirectly(t.hashKey(key))
} else {
enc, err = t.trie.Get(t.hashKey(key))
}
if err != nil || len(enc) == 0 {
return nil, err
}
Expand All @@ -98,8 +106,16 @@ func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
// GetAccount attempts to retrieve an account with provided account address.
// If the specified account is not in the trie, nil will be returned.
// If a trie node is not found in the database, a MissingNodeError is returned.
func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
res, err := t.trie.Get(t.hashKey(address.Bytes()))
func (t *StateTrie) GetAccount(address common.Address, direct bool) (*types.StateAccount, error) {
var (
res []byte
err error
)
if direct {
res, err = t.trie.GetDirectly(t.hashKey(address.Bytes()))
} else {
res, err = t.trie.Get(t.hashKey(address.Bytes()))
}
if res == nil || err != nil {
return nil, err
}
Expand Down
13 changes: 9 additions & 4 deletions trie/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,15 @@ func (t *tracer) deletedNodes() []string {
// It's possible a few deleted nodes were embedded
// in their parent before, the deletions can be no
// effect by deleting nothing, filter them out.
_, ok := t.accessList[path]
if !ok {
continue
}

// Note: In order to read the account/storage
// directly from pathdb, redundant storage is made
// for the embedded node in committer.store, so it
// cannot be filtered out here.
// _, ok := t.accessList[path]
// if !ok {
// continue
// }
paths = append(paths, path)
}
return paths
Expand Down
11 changes: 11 additions & 0 deletions trie/trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,17 @@ func (t *Trie) Get(key []byte) ([]byte, error) {
return value, err
}

func (t *Trie) GetDirectly(key []byte) ([]byte, error) {
if t.reader.reader == nil {
return nil, nil
}
if t.owner == (common.Hash{}) {
return t.reader.reader.Account(common.BytesToHash(key))
} else {
return t.reader.reader.Storage(t.owner, common.BytesToHash(key))
}
}

func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode node, didResolve bool, err error) {
switch n := (origNode).(type) {
case nil:
Expand Down
10 changes: 7 additions & 3 deletions trie/triestate/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,14 @@ type Set struct {
}

// New constructs the state set with provided data.
func New(accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte) *Set {
func New(accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte,
latestAccount map[common.Hash][]byte, latestStorages map[common.Hash]map[common.Hash][]byte, destructSet map[common.Hash]struct{}) *Set {
return &Set{
Accounts: accounts,
Storages: storages,
Accounts: accounts,
Storages: storages,
LatestAccounts: latestAccount,
LatestStorages: latestStorages,
DestructSet: destructSet,
}
}

Expand Down
4 changes: 2 additions & 2 deletions trie/verkle.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (t *VerkleTrie) GetKey(key []byte) []byte {
// GetAccount implements state.Trie, retrieving the account with the specified
// account address. If the specified account is not in the verkle tree, nil will
// be returned. If the tree is corrupted, an error will be returned.
func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error) {
func (t *VerkleTrie) GetAccount(addr common.Address, _ bool) (*types.StateAccount, error) {
var (
acc = &types.StateAccount{}
values [][]byte
Expand Down Expand Up @@ -118,7 +118,7 @@ func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error
// GetStorage implements state.Trie, retrieving the storage slot with the specified
// account address and storage key. If the specified slot is not in the verkle tree,
// nil will be returned. If the tree is corrupted, an error will be returned.
func (t *VerkleTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) {
func (t *VerkleTrie) GetStorage(addr common.Address, key []byte, _ bool) ([]byte, error) {
k := utils.StorageSlotKeyWithEvaluatedAddress(t.cache.Get(addr.Bytes()), key)
val, err := t.root.Get(k, t.nodeResolver)
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions triedb/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ type Reader interface {
// Don't modify the returned byte slice since it's not deep-copied and
// still be referenced by database.
Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error)

// Account retrieves the account with the provided account hash,
Account(hash common.Hash) ([]byte, error)

// Storage retrieves the storage key-value with the provided account hash,
Storage(accountHash, storageHash common.Hash) ([]byte, error)
}

// PreimageStore wraps the methods of a backing store for reading and writing
Expand Down
8 changes: 8 additions & 0 deletions triedb/hashdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,14 @@ type reader struct {
db *Database
}

func (reader reader) Account(hash common.Hash) ([]byte, error) {
panic("Not Supported")
}

func (reader reader) Storage(accountHash, storageHash common.Hash) ([]byte, error) {
panic("Not Supported")
}

// Node retrieves the trie node with the given node hash. No error will be
// returned if the node is not found.
func (reader *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
Expand Down
2 changes: 1 addition & 1 deletion triedb/pathdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ func (db *Database) Enable(root common.Hash) error {
}
// Re-construct a new disk layer backed by persistent state
// with **empty clean cache and node buffer**.
db.tree.reset(newDiskLayer(root, 0, db, nil, newNodeBuffer(db.bufferSize, nil, 0)))
db.tree.reset(newDiskLayer(root, 0, db, nil, newNodeBuffer(db.bufferSize, nil, nil, nil, nil, 0)))

// Re-enable the database as the final step.
db.waitSync = false
Expand Down

0 comments on commit 22cee6d

Please sign in to comment.