Skip to content

Commit 28a4f25

Browse files
gzliudanrjl493456442holiman
authored
cmd, core, eth, trie: track deleted nodes ethereum#22225 ethereum#25757 (XinFinOrg#1120)
Co-authored-by: rjl493456442 <[email protected]> Co-authored-by: Martin Holst Swende <[email protected]>
1 parent d11e128 commit 28a4f25

27 files changed

+784
-163
lines changed

XDCx/tradingstate/XDCx_trie.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func NewXDCXTrie(root common.Hash, db *trie.Database) (*XDCXTrie, error) {
5757
if db == nil {
5858
panic("trie.NewXDCXTrie called without a database")
5959
}
60-
trie, err := trie.New(common.Hash{}, root, db)
60+
trie, err := trie.New(trie.TrieID(root), db)
6161
if err != nil {
6262
return nil, err
6363
}

XDCxlending/lendingstate/XDCx_trie.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func NewXDCXTrie(root common.Hash, db *trie.Database) (*XDCXTrie, error) {
5757
if db == nil {
5858
panic("trie.NewXDCXTrie called without a database")
5959
}
60-
trie, err := trie.New(common.Hash{}, root, db)
60+
trie, err := trie.New(trie.TrieID(root), db)
6161
if err != nil {
6262
return nil, err
6363
}

cmd/XDC/dbcmd.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"os"
2222
"path/filepath"
2323
"slices"
24+
"strconv"
2425
"time"
2526

2627
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
@@ -30,6 +31,7 @@ import (
3031
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
3132
"github.com/XinFinOrg/XDPoSChain/ethdb"
3233
"github.com/XinFinOrg/XDPoSChain/log"
34+
"github.com/XinFinOrg/XDPoSChain/trie"
3335
"github.com/urfave/cli/v2"
3436
)
3537

@@ -54,6 +56,7 @@ Remove blockchain and state databases`,
5456
dbGetCmd,
5557
dbDeleteCmd,
5658
dbPutCmd,
59+
dbGetSlotsCmd,
5760
},
5861
}
5962
dbInspectCmd = &cli.Command{
@@ -119,6 +122,16 @@ WARNING: This is a low-level operation which may cause database corruption!`,
119122
Description: `This command sets a given database key to the given value.
120123
WARNING: This is a low-level operation which may cause database corruption!`,
121124
}
125+
dbGetSlotsCmd = &cli.Command{
126+
Action: dbDumpTrie,
127+
Name: "dumptrie",
128+
Usage: "Show the storage key/values of a given storage trie",
129+
ArgsUsage: "<hex-encoded state root> <hex-encoded account hash> <hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>",
130+
Flags: slices.Concat([]cli.Flag{
131+
utils.SyncModeFlag,
132+
}, utils.NetworkFlags, utils.DatabaseFlags),
133+
Description: "This command looks up the specified database key from the database.",
134+
}
122135
)
123136

124137
func removeDB(ctx *cli.Context) error {
@@ -328,3 +341,64 @@ func dbPut(ctx *cli.Context) error {
328341
}
329342
return db.Put(key, value)
330343
}
344+
345+
// dbDumpTrie shows the key-value slots of a given storage trie
346+
func dbDumpTrie(ctx *cli.Context) error {
347+
if ctx.NArg() < 3 {
348+
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
349+
}
350+
stack, _ := makeConfigNode(ctx)
351+
defer stack.Close()
352+
353+
db := utils.MakeChainDatabase(ctx, stack, true)
354+
defer db.Close()
355+
356+
var (
357+
state []byte
358+
storage []byte
359+
account []byte
360+
start []byte
361+
max = int64(-1)
362+
err error
363+
)
364+
if state, err = hexutil.Decode(ctx.Args().Get(0)); err != nil {
365+
log.Info("Could not decode the state root", "error", err)
366+
return err
367+
}
368+
if account, err = hexutil.Decode(ctx.Args().Get(1)); err != nil {
369+
log.Info("Could not decode the account hash", "error", err)
370+
return err
371+
}
372+
if storage, err = hexutil.Decode(ctx.Args().Get(2)); err != nil {
373+
log.Info("Could not decode the storage trie root", "error", err)
374+
return err
375+
}
376+
if ctx.NArg() > 3 {
377+
if start, err = hexutil.Decode(ctx.Args().Get(3)); err != nil {
378+
log.Info("Could not decode the seek position", "error", err)
379+
return err
380+
}
381+
}
382+
if ctx.NArg() > 4 {
383+
if max, err = strconv.ParseInt(ctx.Args().Get(4), 10, 64); err != nil {
384+
log.Info("Could not decode the max count", "error", err)
385+
return err
386+
}
387+
}
388+
id := trie.StorageTrieID(common.BytesToHash(state), common.BytesToHash(account), common.BytesToHash(storage))
389+
theTrie, err := trie.New(id, trie.NewDatabase(db))
390+
if err != nil {
391+
return err
392+
}
393+
var count int64
394+
it := trie.NewIterator(theTrie.NodeIterator(start))
395+
for it.Next() {
396+
if max > 0 && count == max {
397+
fmt.Printf("Exiting after %d values\n", count)
398+
break
399+
}
400+
fmt.Printf(" %d. key %#x: %#x\n", count, it.Key, it.Value)
401+
count++
402+
}
403+
return it.Err
404+
}

core/blockchain.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ var (
7272
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
7373
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
7474

75+
triedbCommitTimer = metrics.NewRegisteredTimer("chain/triedb/commits", nil)
76+
7577
blockInsertTimer = metrics.NewRegisteredResettingTimer("chain/inserts", nil)
7678
blockValidationTimer = metrics.NewRegisteredResettingTimer("chain/validation", nil)
7779
blockExecutionTimer = metrics.NewRegisteredResettingTimer("chain/execution", nil)
@@ -561,10 +563,10 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error {
561563
if block == nil {
562564
return fmt.Errorf("non existent block [%x..]", hash[:4])
563565
}
564-
if _, err := trie.NewStateTrie(common.Hash{}, block.Root(), bc.stateCache.TrieDB()); err != nil {
565-
return err
566+
root := block.Root()
567+
if !bc.HasState(root) {
568+
return fmt.Errorf("non existent state [%x..]", root[:4])
566569
}
567-
568570
// If all checks out, manually set the head block.
569571
if !bc.chainmu.TryLock() {
570572
return errChainStopped
@@ -1932,6 +1934,7 @@ func (bc *BlockChain) processBlock(block *types.Block, parent *types.Header, sta
19321934
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
19331935
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
19341936
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
1937+
triedbCommitTimer.Update(statedb.TrieDBCommits) // Triedb commits are complete, we can mark them
19351938
triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing
19361939
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
19371940
blockExecutionTimer.Update(ptime - (statedb.AccountReads + statedb.StorageReads)) // The time spent on EVM processing

core/state/database.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type Database interface {
4242
OpenTrie(root common.Hash) (Trie, error)
4343

4444
// OpenStorageTrie opens the storage trie of an account.
45-
OpenStorageTrie(addrHash, root common.Hash) (Trie, error)
45+
OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error)
4646

4747
// CopyTrie returns an independent copy of the given trie.
4848
CopyTrie(Trie) Trie
@@ -146,16 +146,16 @@ type cachingDB struct {
146146

147147
// OpenTrie opens the main account trie at a specific root hash.
148148
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
149-
tr, err := trie.NewStateTrie(common.Hash{}, root, db.db)
149+
tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.db)
150150
if err != nil {
151151
return nil, err
152152
}
153153
return tr, nil
154154
}
155155

156156
// OpenStorageTrie opens the storage trie of an account.
157-
func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) {
158-
tr, err := trie.NewStateTrie(addrHash, root, db.db)
157+
func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) {
158+
tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, addrHash, root), db.db)
159159
if err != nil {
160160
return nil, err
161161
}

core/state/iterator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func (it *nodeIterator) step() error {
109109
if err := rlp.Decode(bytes.NewReader(it.stateIt.LeafBlob()), &account); err != nil {
110110
return err
111111
}
112-
dataTrie, err := it.state.db.OpenStorageTrie(common.BytesToHash(it.stateIt.LeafKey()), account.Root)
112+
dataTrie, err := it.state.db.OpenStorageTrie(it.state.originalRoot, common.BytesToHash(it.stateIt.LeafKey()), account.Root)
113113
if err != nil {
114114
return err
115115
}

core/state/metrics.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ package state
1919
import "github.com/XinFinOrg/XDPoSChain/metrics"
2020

2121
var (
22-
accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil)
23-
storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil)
24-
accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil)
25-
storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil)
26-
accountTrieCommittedMeter = metrics.NewRegisteredMeter("state/commit/accountnodes", nil)
27-
storageTriesCommittedMeter = metrics.NewRegisteredMeter("state/commit/storagenodes", nil)
22+
accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil)
23+
storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil)
24+
accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil)
25+
storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil)
26+
accountTrieUpdatedMeter = metrics.NewRegisteredMeter("state/update/accountnodes", nil)
27+
storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil)
28+
accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil)
29+
storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil)
2830
)

core/state/state_object.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func (s *stateObject) touch() {
158158
// be loaded.
159159
func (s *stateObject) getTrie(db Database) (Trie, error) {
160160
if s.trie == nil {
161-
tr, err := db.OpenStorageTrie(s.addrHash, s.data.Root)
161+
tr, err := db.OpenStorageTrie(s.db.originalRoot, s.addrHash, s.data.Root)
162162
if err != nil {
163163
return nil, err
164164
}

core/state/statedb.go

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ type StateDB struct {
5050
trie Trie
5151
logger *tracing.Hooks
5252

53+
// originalRoot is the pre-state root, before any changes were made.
54+
// It will be updated when the Commit is called.
55+
originalRoot common.Hash
56+
5357
// This map holds 'live' objects, which will get modified while processing a state transition.
5458
stateObjects map[common.Address]*stateObject
5559
stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie
@@ -96,6 +100,7 @@ type StateDB struct {
96100
StorageHashes time.Duration
97101
StorageUpdates time.Duration
98102
StorageCommits time.Duration
103+
TrieDBCommits time.Duration
99104

100105
AccountUpdated int
101106
StorageUpdated int
@@ -120,6 +125,7 @@ func New(root common.Hash, db Database) (*StateDB, error) {
120125
return &StateDB{
121126
db: db,
122127
trie: tr,
128+
originalRoot: root,
123129
stateObjects: make(map[common.Address]*stateObject),
124130
stateObjectsPending: make(map[common.Address]struct{}),
125131
stateObjectsDirty: make(map[common.Address]struct{}),
@@ -665,6 +671,7 @@ func (s *StateDB) Copy() *StateDB {
665671
state := &StateDB{
666672
db: s.db,
667673
trie: s.db.CopyTrie(s.trie),
674+
originalRoot: s.originalRoot,
668675
stateObjects: make(map[common.Address]*stateObject, len(s.journal.dirties)),
669676
stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)),
670677
stateObjectsDirty: make(map[common.Address]struct{}, len(s.journal.dirties)),
@@ -852,9 +859,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
852859
}
853860
// Commit objects to the trie, measuring the elapsed time
854861
var (
855-
accountTrieNodes int
856-
storageTrieNodes int
857-
nodes = trie.NewMergedNodeSet()
862+
accountTrieNodesUpdated int
863+
accountTrieNodesDeleted int
864+
storageTrieNodesUpdated int
865+
storageTrieNodesDeleted int
866+
nodes = trie.NewMergedNodeSet()
858867
)
859868
codeWriter := s.db.DiskDB().NewBatch()
860869
for addr := range s.stateObjectsDirty {
@@ -874,7 +883,9 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
874883
if err := nodes.Merge(set); err != nil {
875884
return common.Hash{}, err
876885
}
877-
storageTrieNodes += set.Len()
886+
updates, deleted := set.Size()
887+
storageTrieNodesUpdated += updates
888+
storageTrieNodesDeleted += deleted
878889
}
879890
}
880891
// If the contract is destructed, the storage is still left in the
@@ -904,7 +915,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
904915
if err := nodes.Merge(set); err != nil {
905916
return common.Hash{}, err
906917
}
907-
accountTrieNodes = set.Len()
918+
accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size()
908919
}
909920
// Report the commit metrics
910921
s.AccountCommits += time.Since(start)
@@ -913,18 +924,32 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
913924
storageUpdatedMeter.Mark(int64(s.StorageUpdated))
914925
accountDeletedMeter.Mark(int64(s.AccountDeleted))
915926
storageDeletedMeter.Mark(int64(s.StorageDeleted))
916-
accountTrieCommittedMeter.Mark(int64(accountTrieNodes))
917-
storageTriesCommittedMeter.Mark(int64(storageTrieNodes))
927+
accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated))
928+
accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted))
929+
storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated))
930+
storageTriesDeletedMeter.Mark(int64(storageTrieNodesDeleted))
918931
s.AccountUpdated, s.AccountDeleted = 0, 0
919932
s.StorageUpdated, s.StorageDeleted = 0, 0
920933

921934
if len(s.stateObjectsDestruct) > 0 {
922935
s.stateObjectsDestruct = make(map[common.Address]struct{})
923936
}
924-
if err := s.db.TrieDB().Update(nodes); err != nil {
925-
return common.Hash{}, err
937+
if root == (common.Hash{}) {
938+
root = types.EmptyRootHash
939+
}
940+
origin := s.originalRoot
941+
if origin == (common.Hash{}) {
942+
origin = types.EmptyRootHash
943+
}
944+
if root != origin {
945+
start := time.Now()
946+
if err := s.db.TrieDB().Update(nodes); err != nil {
947+
return common.Hash{}, err
948+
}
949+
s.originalRoot = root
950+
s.TrieDBCommits += time.Since(start)
926951
}
927-
return root, err
952+
return root, nil
928953
}
929954

930955
// Prepare handles the preparatory steps for executing a state transition with.

core/state/sync_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func checkTrieConsistency(db ethdb.KeyValueStore, root common.Hash) error {
105105
if v, _ := db.Get(root[:]); v == nil {
106106
return nil // Consider a non existent state consistent.
107107
}
108-
trie, err := trie.New(common.Hash{}, root, trie.NewDatabase(db))
108+
trie, err := trie.New(trie.StateTrieID(root), trie.NewDatabase(db))
109109
if err != nil {
110110
return err
111111
}
@@ -174,7 +174,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) {
174174
if commit {
175175
srcDb.TrieDB().Commit(srcRoot, false)
176176
}
177-
srcTrie, _ := trie.New(common.Hash{}, srcRoot, srcDb.TrieDB())
177+
srcTrie, _ := trie.New(trie.StateTrieID(srcRoot), srcDb.TrieDB())
178178

179179
// Create a destination state and sync with the scheduler
180180
dstDb := rawdb.NewMemoryDatabase()
@@ -222,7 +222,8 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) {
222222
if err := rlp.DecodeBytes(srcTrie.Get(node.syncPath[0]), &acc); err != nil {
223223
t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err)
224224
}
225-
stTrie, err := trie.New(common.BytesToHash(node.syncPath[0]), acc.Root, srcDb.TrieDB())
225+
id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root)
226+
stTrie, err := trie.New(id, srcDb.TrieDB())
226227
if err != nil {
227228
t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err)
228229
}

0 commit comments

Comments
 (0)