github.com/ethereum/go-ethereum@v1.16.1/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.NodeReader 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.NodeReader 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.NodeDatabase 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) NodeReader(stateRoot common.Hash) (database.NodeReader, 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) PreimageEnabled() bool {
    90  	return true
    91  }
    92  
    93  func (db *testDb) Scheme() string { return db.scheme }
    94  
    95  func (db *testDb) Update(root common.Hash, parent common.Hash, nodes *trienode.MergedNodeSet) error {
    96  	if root == parent {
    97  		return nil
    98  	}
    99  	if _, ok := db.nodes[root]; ok {
   100  		return nil
   101  	}
   102  	db.parents[root] = parent
   103  	db.nodes[root] = nodes
   104  	return nil
   105  }
   106  
   107  func (db *testDb) dirties(root common.Hash, topToBottom bool) ([]*trienode.MergedNodeSet, []common.Hash) {
   108  	var (
   109  		pending []*trienode.MergedNodeSet
   110  		roots   []common.Hash
   111  	)
   112  	for {
   113  		if root == db.root {
   114  			break
   115  		}
   116  		nodes, ok := db.nodes[root]
   117  		if !ok {
   118  			break
   119  		}
   120  		if topToBottom {
   121  			pending = append(pending, nodes)
   122  			roots = append(roots, root)
   123  		} else {
   124  			pending = append([]*trienode.MergedNodeSet{nodes}, pending...)
   125  			roots = append([]common.Hash{root}, roots...)
   126  		}
   127  		root = db.parents[root]
   128  	}
   129  	return pending, roots
   130  }
   131  
   132  func (db *testDb) Commit(root common.Hash) error {
   133  	if root == db.root {
   134  		return nil
   135  	}
   136  	pending, roots := db.dirties(root, false)
   137  	for i, nodes := range pending {
   138  		for owner, set := range nodes.Sets {
   139  			if owner == (common.Hash{}) {
   140  				continue
   141  			}
   142  			set.ForEachWithOrder(func(path string, n *trienode.Node) {
   143  				rawdb.WriteTrieNode(db.disk, owner, []byte(path), n.Hash, n.Blob, db.scheme)
   144  			})
   145  		}
   146  		nodes.Sets[common.Hash{}].ForEachWithOrder(func(path string, n *trienode.Node) {
   147  			rawdb.WriteTrieNode(db.disk, common.Hash{}, []byte(path), n.Hash, n.Blob, db.scheme)
   148  		})
   149  		db.root = roots[i]
   150  	}
   151  	for _, root := range roots {
   152  		delete(db.nodes, root)
   153  		delete(db.parents, root)
   154  	}
   155  	return nil
   156  }