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  }