Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

trie: add trie db wrapper; refactor trienode #588

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
rawdb, trie: fix comment
trie: change name WithPrev => NodeWithPrev
rawdb: add schema_test
  • Loading branch information
Francesco4203 committed Oct 1, 2024
commit 463b5d5ae4cff3ca4a3007d49c8e16f740960940
227 changes: 227 additions & 0 deletions core/rawdb/schema_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package rawdb

import (
"bytes"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)

var (
bytes4 = []byte{0x00, 0x01, 0x02, 0x03}
bytes20 = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03}
bytes32 = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
bytes63 = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e}
bytes64 = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
bytes65 = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}
)

func TestIsLegacyTrieNode(t *testing.T) {
tests := []struct {
name string
inputData []byte
inputKey []byte
expected bool
}{
{
name: "empty",
inputKey: []byte{},
expected: false,
},
{
name: "non-legacy (too short)",
inputKey: []byte{0x00, 0x01, 0x02, 0x03},
expected: false,
},
{
name: "legacy",
inputData: []byte{0x00, 0x01, 0x02, 0x03},
inputKey: crypto.Keccak256([]byte{0x00, 0x01, 0x02, 0x03}),
expected: true,
},
{
name: "non-legacy (too long)",
inputKey: []byte{0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00},
expected: false,
},
{
name: "non-legacy (key is not hash of data)",
inputData: []byte{0x00, 0x01, 0x02, 0x03},
inputKey: crypto.Keccak256([]byte{0x00, 0x01, 0x02, 0x04}),
expected: false,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if actual := IsLegacyTrieNode(test.inputKey, test.inputData); actual != test.expected {
t.Errorf("expected %v, got %v", test.expected, actual)
}
})
}
}

func TestIsAccountTrieNode(t *testing.T) {
tests := []struct {
name string
inputKey []byte
expectedCheck bool
expectedKey []byte
}{
{
name: "empty",
inputKey: []byte{},
expectedCheck: false,
expectedKey: nil,
},
{
name: "non account prefixed",
inputKey: bytes4,
expectedCheck: false,
expectedKey: nil,
},
{
name: "storage prefixed",
inputKey: append(trieNodeStoragePrefix, bytes4...),
expectedCheck: false,
expectedKey: nil,
},
{
name: "account prefixed length 4",
inputKey: accountTrieNodeKey(bytes4),
expectedCheck: true,
expectedKey: bytes4,
},
{
name: "account prefixed length 20",
inputKey: accountTrieNodeKey(bytes20),
expectedCheck: true,
expectedKey: bytes20,
},
{
name: "account prefixed length 63",
inputKey: accountTrieNodeKey(bytes63),
expectedCheck: true,
expectedKey: bytes63,
},
{
name: "account prefixed length 64",
inputKey: accountTrieNodeKey(bytes64),
expectedCheck: false,
expectedKey: nil,
},
{
name: "account prefixed length 65",
inputKey: accountTrieNodeKey(bytes65),
expectedCheck: false,
expectedKey: nil,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if check, key := IsAccountTrieNode(test.inputKey); check != test.expectedCheck || !bytes.Equal(key, test.expectedKey) {
t.Errorf("expected %v, %v, got %v, %v", test.expectedCheck, test.expectedKey, check, key)
}
})
}
}

func TestIsStorageTrieNode(t *testing.T) {
tests := []struct {
name string
inputKey []byte
expectedCheck bool
expectedHash common.Hash
expectedKey []byte
}{
{
name: "empty",
inputKey: []byte{},
expectedCheck: false,
expectedHash: common.Hash{},
expectedKey: nil,
},
{
name: "non storage prefixed",
inputKey: []byte{0x00, 0x01, 0x02, 0x03},
expectedCheck: false,
expectedHash: common.Hash{},
expectedKey: nil,
},
{
name: "account prefixed",
inputKey: accountTrieNodeKey(bytes4),
expectedCheck: false,
expectedHash: common.Hash{},
expectedKey: nil,
},
{
name: "storage prefixed hash 20 length 4",
inputKey: append(append(trieNodeStoragePrefix, bytes20...), bytes4...),
expectedCheck: false,
expectedHash: common.Hash{},
expectedKey: nil,
},
{
name: "storage prefixed hash 32 length 4",
inputKey: storageTrieNodeKey(common.BytesToHash(bytes32), bytes4),
expectedCheck: true,
expectedHash: common.BytesToHash(bytes32),
expectedKey: bytes4,
},
{
name: "storage prefixed hash 32 length 20",
inputKey: storageTrieNodeKey(common.BytesToHash(bytes20), bytes20),
expectedCheck: true,
expectedHash: common.BytesToHash(bytes20),
expectedKey: bytes20,
},
{
name: "storage prefixed hash 32 length 63",
inputKey: storageTrieNodeKey(common.BytesToHash(bytes65), bytes63),
expectedCheck: true,
expectedHash: common.BytesToHash(bytes65),
expectedKey: bytes63,
},
{
name: "storage prefixed hash 32 length 64",
inputKey: storageTrieNodeKey(common.BytesToHash(bytes32), bytes64),
expectedCheck: false,
expectedHash: common.Hash{},
expectedKey: nil,
},
{
name: "storage prefixed hash 32 length 65",
inputKey: storageTrieNodeKey(common.BytesToHash(bytes32), bytes65),
expectedCheck: false,
expectedHash: common.Hash{},
expectedKey: nil,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if check, hash, key := IsStorageTrieNode(test.inputKey); check != test.expectedCheck || !bytes.Equal(key, test.expectedKey) || hash != test.expectedHash {
t.Errorf("expected %v, %v, %v, got %v, %v, %v", test.expectedCheck, test.expectedHash, test.expectedKey, check, hash, key)
}
})
}
}
4 changes: 2 additions & 2 deletions trie/committer.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func (c *committer) store(path []byte, n node) node {
// deleted only if the node was existent in database before.
prev, ok := c.tracer.accessList[string(path)]
if ok {
c.nodes.AddNode(path, trienode.NewWithPrev(common.Hash{}, nil, prev))
c.nodes.AddNode(path, trienode.NewNodeWithPrev(common.Hash{}, nil, prev))
}
return n
}
Expand All @@ -179,7 +179,7 @@ func (c *committer) store(path []byte, n node) node {
var (
nhash = common.BytesToHash(hash)
blob, _ = rlp.EncodeToBytes(n)
node = trienode.NewWithPrev(
node = trienode.NewNodeWithPrev(
nhash,
blob,
c.tracer.accessList[string(path)],
Expand Down
2 changes: 1 addition & 1 deletion trie/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,6 @@ func (t *tracer) markDeletions(set *trienode.NodeSet) {
if !ok {
continue
}
set.AddNode([]byte(path), trienode.NewWithPrev(common.Hash{}, nil, prev))
set.AddNode([]byte(path), trienode.NewNodeWithPrev(common.Hash{}, nil, prev))
}
}
20 changes: 10 additions & 10 deletions trie/trienode/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,20 @@ func (n *Node) IsDeleted() bool {
return n.Hash == (common.Hash{})
}

// WithPrev wraps the Node with the previous node value attached.
type WithPrev struct {
// NodeWithPrev wraps the Node with the previous node value attached.
type NodeWithPrev struct {
*Node
Prev []byte // Encoded original value, nil means it's non-existent
}

// Unwrap returns the internal Node object.
func (n *WithPrev) Unwrap() *Node {
func (n *NodeWithPrev) 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 {
func (n *NodeWithPrev) Size() int {
return n.Node.Size() + len(n.Prev)
}

Expand All @@ -64,9 +64,9 @@ 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{
// NewNodeWithPrev constructs a node with provided node information.
func NewNodeWithPrev(hash common.Hash, blob []byte, prev []byte) *NodeWithPrev {
return &NodeWithPrev{
Node: New(hash, blob),
Prev: prev,
}
Expand All @@ -83,7 +83,7 @@ type leaf struct {
type NodeSet struct {
Owner common.Hash
Leaves []*leaf
Nodes map[string]*WithPrev
Nodes map[string]*NodeWithPrev
updates int // the count of updated and inserted nodes
deletes int // the count of deleted nodes
}
Expand All @@ -93,7 +93,7 @@ type NodeSet struct {
func NewNodeSet(owner common.Hash) *NodeSet {
return &NodeSet{
Owner: owner,
Nodes: make(map[string]*WithPrev),
Nodes: make(map[string]*NodeWithPrev),
}
}

Expand All @@ -112,7 +112,7 @@ func (set *NodeSet) ForEachWithOrder(callback func(path string, n *Node)) {
}

// AddNode adds the provided node into set.
func (set *NodeSet) AddNode(path []byte, n *WithPrev) {
func (set *NodeSet) AddNode(path []byte, n *NodeWithPrev) {
if n.IsDeleted() {
set.deletes += 1
} else {
Expand Down
Loading