all: implement path-based state scheme (#25963)

* all: implement path-based state scheme

* all: edits from review

* core/rawdb, trie/triedb/pathdb: review changes

* core, light, trie, eth, tests: reimplement pbss history

* core, trie/triedb/pathdb: track block number in state history

* trie/triedb/pathdb: add history documentation

* core, trie/triedb/pathdb: address comments from Peter's review

Important changes to list:

- Cache trie nodes by path in clean cache
- Remove root->id mappings when history is truncated

* trie/triedb/pathdb: fallback to disk if unexpect node in clean cache

* core/rawdb: fix tests

* trie/triedb/pathdb: rename metrics, change clean cache key

* trie/triedb: manage the clean cache inside of disk layer

* trie/triedb/pathdb: move journal function

* trie/triedb/path: fix tests

* trie/triedb/pathdb: fix journal

* trie/triedb/pathdb: fix history

* trie/triedb/pathdb: try to fix tests on windows

* core, trie: address comments

* trie/triedb/pathdb: fix test issues

---------

Co-authored-by: Felix Lange <fjl@twurst.com>
Co-authored-by: Martin Holst Swende <martin@swende.se>
This commit is contained in:
rjl493456442
2023-08-01 15:17:32 +03:00
committed by GitHub
co-authored by Felix Lange Martin Holst Swende
parent 9d744f0ca8
commit 7de748d3f6
43 changed files with 4418 additions and 226 deletions
+22 -40
View File
@@ -25,8 +25,8 @@ import (
)
// Node is a wrapper which contains the encoded blob of the trie node and its
// unique hash identifier. It is general enough that can be used to represent
// trie nodes corresponding to different trie implementations.
// node hash. It is general enough that can be used to represent trie node
// corresponding to different trie implementations.
type Node struct {
Hash common.Hash // Node hash, empty for deleted node
Blob []byte // Encoded node blob, nil for the deleted node
@@ -42,35 +42,13 @@ func (n *Node) IsDeleted() bool {
return n.Hash == (common.Hash{})
}
// WithPrev wraps the Node with the previous node value attached.
type WithPrev struct {
*Node
Prev []byte // Encoded original value, nil means it's non-existent
}
// Unwrap returns the internal Node object.
func (n *WithPrev) Unwrap() *Node {
return n.Node
}
// Size returns the total memory size used by this node. It overloads
// the function in Node by counting the size of previous value as well.
func (n *WithPrev) Size() int {
return n.Node.Size() + len(n.Prev)
}
// New constructs a node with provided node information.
func New(hash common.Hash, blob []byte) *Node {
return &Node{Hash: hash, Blob: blob}
}
// NewWithPrev constructs a node with provided node information.
func NewWithPrev(hash common.Hash, blob []byte, prev []byte) *WithPrev {
return &WithPrev{
Node: New(hash, blob),
Prev: prev,
}
}
// NewDeleted constructs a node which is deleted.
func NewDeleted() *Node { return New(common.Hash{}, nil) }
// leaf represents a trie leaf node
type leaf struct {
@@ -83,7 +61,7 @@ type leaf struct {
type NodeSet struct {
Owner common.Hash
Leaves []*leaf
Nodes map[string]*WithPrev
Nodes map[string]*Node
updates int // the count of updated and inserted nodes
deletes int // the count of deleted nodes
}
@@ -93,7 +71,7 @@ type NodeSet struct {
func NewNodeSet(owner common.Hash) *NodeSet {
return &NodeSet{
Owner: owner,
Nodes: make(map[string]*WithPrev),
Nodes: make(map[string]*Node),
}
}
@@ -104,17 +82,17 @@ func (set *NodeSet) ForEachWithOrder(callback func(path string, n *Node)) {
for path := range set.Nodes {
paths = append(paths, path)
}
// Bottom-up, longest path first
// Bottom-up, the longest path first
slices.SortFunc(paths, func(a, b string) bool {
return a > b // Sort in reverse order
})
for _, path := range paths {
callback(path, set.Nodes[path].Unwrap())
callback(path, set.Nodes[path])
}
}
// AddNode adds the provided node into set.
func (set *NodeSet) AddNode(path []byte, n *WithPrev) {
func (set *NodeSet) AddNode(path []byte, n *Node) {
if n.IsDeleted() {
set.deletes += 1
} else {
@@ -124,7 +102,7 @@ func (set *NodeSet) AddNode(path []byte, n *WithPrev) {
}
// Merge adds a set of nodes into the set.
func (set *NodeSet) Merge(owner common.Hash, nodes map[string]*WithPrev) error {
func (set *NodeSet) Merge(owner common.Hash, nodes map[string]*Node) error {
if set.Owner != owner {
return fmt.Errorf("nodesets belong to different owner are not mergeable %x-%x", set.Owner, owner)
}
@@ -172,16 +150,11 @@ func (set *NodeSet) Summary() string {
for path, n := range set.Nodes {
// Deletion
if n.IsDeleted() {
fmt.Fprintf(out, " [-]: %x prev: %x\n", path, n.Prev)
fmt.Fprintf(out, " [-]: %x\n", path)
continue
}
// Insertion
if len(n.Prev) == 0 {
fmt.Fprintf(out, " [+]: %x -> %v\n", path, n.Hash)
continue
}
// Update
fmt.Fprintf(out, " [*]: %x -> %v prev: %x\n", path, n.Hash, n.Prev)
// Insertion or update
fmt.Fprintf(out, " [+/*]: %x -> %v \n", path, n.Hash)
}
}
for _, n := range set.Leaves {
@@ -217,3 +190,12 @@ func (set *MergedNodeSet) Merge(other *NodeSet) error {
set.Sets[other.Owner] = other
return nil
}
// Flatten returns a two-dimensional map for internal nodes.
func (set *MergedNodeSet) Flatten() map[common.Hash]map[string]*Node {
nodes := make(map[common.Hash]map[string]*Node)
for owner, set := range set.Sets {
nodes[owner] = set.Nodes
}
return nodes
}