github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/trie/database_test.go (about) 1 // Copyright 2019 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package trie 18 19 import ( 20 "github.com/ethereum/go-ethereum/common" 21 "github.com/ethereum/go-ethereum/core/rawdb" 22 "github.com/ethereum/go-ethereum/core/types" 23 "github.com/ethereum/go-ethereum/ethdb" 24 "github.com/ethereum/go-ethereum/trie/trienode" 25 "github.com/ethereum/go-ethereum/triedb/database" 26 ) 27 28 // testReader implements database.Reader interface, providing function to 29 // access trie nodes. 30 type testReader struct { 31 db ethdb.Database 32 scheme string 33 nodes []*trienode.MergedNodeSet // sorted from new to old 34 } 35 36 // Node implements database.Reader interface, retrieving trie node with 37 // all available cached layers. 38 func (r *testReader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) { 39 // Check the node presence with the cached layer, from latest to oldest. 40 for _, nodes := range r.nodes { 41 if _, ok := nodes.Sets[owner]; !ok { 42 continue 43 } 44 n, ok := nodes.Sets[owner].Nodes[string(path)] 45 if !ok { 46 continue 47 } 48 if n.IsDeleted() || n.Hash != hash { 49 return nil, &MissingNodeError{Owner: owner, Path: path, NodeHash: hash} 50 } 51 return n.Blob, nil 52 } 53 // Check the node presence in database. 54 return rawdb.ReadTrieNode(r.db, owner, path, hash, r.scheme), nil 55 } 56 57 // testDb implements database.Database interface, using for testing purpose. 58 type testDb struct { 59 disk ethdb.Database 60 root common.Hash 61 scheme string 62 nodes map[common.Hash]*trienode.MergedNodeSet 63 parents map[common.Hash]common.Hash 64 } 65 66 func newTestDatabase(diskdb ethdb.Database, scheme string) *testDb { 67 return &testDb{ 68 disk: diskdb, 69 root: types.EmptyRootHash, 70 scheme: scheme, 71 nodes: make(map[common.Hash]*trienode.MergedNodeSet), 72 parents: make(map[common.Hash]common.Hash), 73 } 74 } 75 76 func (db *testDb) Reader(stateRoot common.Hash) (database.Reader, error) { 77 nodes, _ := db.dirties(stateRoot, true) 78 return &testReader{db: db.disk, scheme: db.scheme, nodes: nodes}, nil 79 } 80 81 func (db *testDb) Preimage(hash common.Hash) []byte { 82 return rawdb.ReadPreimage(db.disk, hash) 83 } 84 85 func (db *testDb) InsertPreimage(preimages map[common.Hash][]byte) { 86 rawdb.WritePreimages(db.disk, preimages) 87 } 88 89 func (db *testDb) Scheme() string { return db.scheme } 90 91 func (db *testDb) Update(root common.Hash, parent common.Hash, nodes *trienode.MergedNodeSet) error { 92 if root == parent { 93 return nil 94 } 95 if _, ok := db.nodes[root]; ok { 96 return nil 97 } 98 db.parents[root] = parent 99 db.nodes[root] = nodes 100 return nil 101 } 102 103 func (db *testDb) dirties(root common.Hash, topToBottom bool) ([]*trienode.MergedNodeSet, []common.Hash) { 104 var ( 105 pending []*trienode.MergedNodeSet 106 roots []common.Hash 107 ) 108 for { 109 if root == db.root { 110 break 111 } 112 nodes, ok := db.nodes[root] 113 if !ok { 114 break 115 } 116 if topToBottom { 117 pending = append(pending, nodes) 118 roots = append(roots, root) 119 } else { 120 pending = append([]*trienode.MergedNodeSet{nodes}, pending...) 121 roots = append([]common.Hash{root}, roots...) 122 } 123 root = db.parents[root] 124 } 125 return pending, roots 126 } 127 128 func (db *testDb) Commit(root common.Hash) error { 129 if root == db.root { 130 return nil 131 } 132 pending, roots := db.dirties(root, false) 133 for i, nodes := range pending { 134 for owner, set := range nodes.Sets { 135 if owner == (common.Hash{}) { 136 continue 137 } 138 set.ForEachWithOrder(func(path string, n *trienode.Node) { 139 rawdb.WriteTrieNode(db.disk, owner, []byte(path), n.Hash, n.Blob, db.scheme) 140 }) 141 } 142 nodes.Sets[common.Hash{}].ForEachWithOrder(func(path string, n *trienode.Node) { 143 rawdb.WriteTrieNode(db.disk, common.Hash{}, []byte(path), n.Hash, n.Blob, db.scheme) 144 }) 145 db.root = roots[i] 146 } 147 for _, root := range roots { 148 delete(db.nodes, root) 149 delete(db.parents, root) 150 } 151 return nil 152 }