github.com/theQRL/go-zond@v0.1.1/core/rawdb/accessors_trie.go (about)

     1  // Copyright 2022 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 rawdb
    18  
    19  import (
    20  	"fmt"
    21  	"sync"
    22  
    23  	"github.com/theQRL/go-zond/common"
    24  	"github.com/theQRL/go-zond/crypto"
    25  	"github.com/theQRL/go-zond/log"
    26  	"github.com/theQRL/go-zond/zonddb"
    27  	"golang.org/x/crypto/sha3"
    28  )
    29  
    30  // HashScheme is the legacy hash-based state scheme with which trie nodes are
    31  // stored in the disk with node hash as the database key. The advantage of this
    32  // scheme is that different versions of trie nodes can be stored in disk, which
    33  // is very beneficial for constructing archive nodes. The drawback is it will
    34  // store different trie nodes on the same path to different locations on the disk
    35  // with no data locality, and it's unfriendly for designing state pruning.
    36  //
    37  // Now this scheme is still kept for backward compatibility, and it will be used
    38  // for archive node and some other tries(e.g. light trie).
    39  const HashScheme = "hash"
    40  
    41  // PathScheme is the new path-based state scheme with which trie nodes are stored
    42  // in the disk with node path as the database key. This scheme will only store one
    43  // version of state data in the disk, which means that the state pruning operation
    44  // is native. At the same time, this scheme will put adjacent trie nodes in the same
    45  // area of the disk with good data locality property. But this scheme needs to rely
    46  // on extra state diffs to survive deep reorg.
    47  const PathScheme = "path"
    48  
    49  // hasher is used to compute the sha256 hash of the provided data.
    50  type hasher struct{ sha crypto.KeccakState }
    51  
    52  var hasherPool = sync.Pool{
    53  	New: func() interface{} { return &hasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} },
    54  }
    55  
    56  func newHasher() *hasher {
    57  	return hasherPool.Get().(*hasher)
    58  }
    59  
    60  func (h *hasher) hash(data []byte) common.Hash {
    61  	return crypto.HashData(h.sha, data)
    62  }
    63  
    64  func (h *hasher) release() {
    65  	hasherPool.Put(h)
    66  }
    67  
    68  // ReadAccountTrieNode retrieves the account trie node and the associated node
    69  // hash with the specified node path.
    70  func ReadAccountTrieNode(db zonddb.KeyValueReader, path []byte) ([]byte, common.Hash) {
    71  	data, err := db.Get(accountTrieNodeKey(path))
    72  	if err != nil {
    73  		return nil, common.Hash{}
    74  	}
    75  	h := newHasher()
    76  	defer h.release()
    77  	return data, h.hash(data)
    78  }
    79  
    80  // HasAccountTrieNode checks the account trie node presence with the specified
    81  // node path and the associated node hash.
    82  func HasAccountTrieNode(db zonddb.KeyValueReader, path []byte, hash common.Hash) bool {
    83  	data, err := db.Get(accountTrieNodeKey(path))
    84  	if err != nil {
    85  		return false
    86  	}
    87  	h := newHasher()
    88  	defer h.release()
    89  	return h.hash(data) == hash
    90  }
    91  
    92  // WriteAccountTrieNode writes the provided account trie node into database.
    93  func WriteAccountTrieNode(db zonddb.KeyValueWriter, path []byte, node []byte) {
    94  	if err := db.Put(accountTrieNodeKey(path), node); err != nil {
    95  		log.Crit("Failed to store account trie node", "err", err)
    96  	}
    97  }
    98  
    99  // DeleteAccountTrieNode deletes the specified account trie node from the database.
   100  func DeleteAccountTrieNode(db zonddb.KeyValueWriter, path []byte) {
   101  	if err := db.Delete(accountTrieNodeKey(path)); err != nil {
   102  		log.Crit("Failed to delete account trie node", "err", err)
   103  	}
   104  }
   105  
   106  // ReadStorageTrieNode retrieves the storage trie node and the associated node
   107  // hash with the specified node path.
   108  func ReadStorageTrieNode(db zonddb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) {
   109  	data, err := db.Get(storageTrieNodeKey(accountHash, path))
   110  	if err != nil {
   111  		return nil, common.Hash{}
   112  	}
   113  	h := newHasher()
   114  	defer h.release()
   115  	return data, h.hash(data)
   116  }
   117  
   118  // HasStorageTrieNode checks the storage trie node presence with the provided
   119  // node path and the associated node hash.
   120  func HasStorageTrieNode(db zonddb.KeyValueReader, accountHash common.Hash, path []byte, hash common.Hash) bool {
   121  	data, err := db.Get(storageTrieNodeKey(accountHash, path))
   122  	if err != nil {
   123  		return false
   124  	}
   125  	h := newHasher()
   126  	defer h.release()
   127  	return h.hash(data) == hash
   128  }
   129  
   130  // WriteStorageTrieNode writes the provided storage trie node into database.
   131  func WriteStorageTrieNode(db zonddb.KeyValueWriter, accountHash common.Hash, path []byte, node []byte) {
   132  	if err := db.Put(storageTrieNodeKey(accountHash, path), node); err != nil {
   133  		log.Crit("Failed to store storage trie node", "err", err)
   134  	}
   135  }
   136  
   137  // DeleteStorageTrieNode deletes the specified storage trie node from the database.
   138  func DeleteStorageTrieNode(db zonddb.KeyValueWriter, accountHash common.Hash, path []byte) {
   139  	if err := db.Delete(storageTrieNodeKey(accountHash, path)); err != nil {
   140  		log.Crit("Failed to delete storage trie node", "err", err)
   141  	}
   142  }
   143  
   144  // ReadLegacyTrieNode retrieves the legacy trie node with the given
   145  // associated node hash.
   146  func ReadLegacyTrieNode(db zonddb.KeyValueReader, hash common.Hash) []byte {
   147  	data, err := db.Get(hash.Bytes())
   148  	if err != nil {
   149  		return nil
   150  	}
   151  	return data
   152  }
   153  
   154  // HasLegacyTrieNode checks if the trie node with the provided hash is present in db.
   155  func HasLegacyTrieNode(db zonddb.KeyValueReader, hash common.Hash) bool {
   156  	ok, _ := db.Has(hash.Bytes())
   157  	return ok
   158  }
   159  
   160  // WriteLegacyTrieNode writes the provided legacy trie node to database.
   161  func WriteLegacyTrieNode(db zonddb.KeyValueWriter, hash common.Hash, node []byte) {
   162  	if err := db.Put(hash.Bytes(), node); err != nil {
   163  		log.Crit("Failed to store legacy trie node", "err", err)
   164  	}
   165  }
   166  
   167  // DeleteLegacyTrieNode deletes the specified legacy trie node from database.
   168  func DeleteLegacyTrieNode(db zonddb.KeyValueWriter, hash common.Hash) {
   169  	if err := db.Delete(hash.Bytes()); err != nil {
   170  		log.Crit("Failed to delete legacy trie node", "err", err)
   171  	}
   172  }
   173  
   174  // HasTrieNode checks the trie node presence with the provided node info and
   175  // the associated node hash.
   176  func HasTrieNode(db zonddb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) bool {
   177  	switch scheme {
   178  	case HashScheme:
   179  		return HasLegacyTrieNode(db, hash)
   180  	case PathScheme:
   181  		if owner == (common.Hash{}) {
   182  			return HasAccountTrieNode(db, path, hash)
   183  		}
   184  		return HasStorageTrieNode(db, owner, path, hash)
   185  	default:
   186  		panic(fmt.Sprintf("Unknown scheme %v", scheme))
   187  	}
   188  }
   189  
   190  // ReadTrieNode retrieves the trie node from database with the provided node info
   191  // and associated node hash.
   192  // hashScheme-based lookup requires the following:
   193  //   - hash
   194  //
   195  // pathScheme-based lookup requires the following:
   196  //   - owner
   197  //   - path
   198  func ReadTrieNode(db zonddb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) []byte {
   199  	switch scheme {
   200  	case HashScheme:
   201  		return ReadLegacyTrieNode(db, hash)
   202  	case PathScheme:
   203  		var (
   204  			blob  []byte
   205  			nHash common.Hash
   206  		)
   207  		if owner == (common.Hash{}) {
   208  			blob, nHash = ReadAccountTrieNode(db, path)
   209  		} else {
   210  			blob, nHash = ReadStorageTrieNode(db, owner, path)
   211  		}
   212  		if nHash != hash {
   213  			return nil
   214  		}
   215  		return blob
   216  	default:
   217  		panic(fmt.Sprintf("Unknown scheme %v", scheme))
   218  	}
   219  }
   220  
   221  // WriteTrieNode writes the trie node into database with the provided node info
   222  // and associated node hash.
   223  // hashScheme-based lookup requires the following:
   224  //   - hash
   225  //
   226  // pathScheme-based lookup requires the following:
   227  //   - owner
   228  //   - path
   229  func WriteTrieNode(db zonddb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, node []byte, scheme string) {
   230  	switch scheme {
   231  	case HashScheme:
   232  		WriteLegacyTrieNode(db, hash, node)
   233  	case PathScheme:
   234  		if owner == (common.Hash{}) {
   235  			WriteAccountTrieNode(db, path, node)
   236  		} else {
   237  			WriteStorageTrieNode(db, owner, path, node)
   238  		}
   239  	default:
   240  		panic(fmt.Sprintf("Unknown scheme %v", scheme))
   241  	}
   242  }
   243  
   244  // DeleteTrieNode deletes the trie node from database with the provided node info
   245  // and associated node hash.
   246  // hashScheme-based lookup requires the following:
   247  //   - hash
   248  //
   249  // pathScheme-based lookup requires the following:
   250  //   - owner
   251  //   - path
   252  func DeleteTrieNode(db zonddb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, scheme string) {
   253  	switch scheme {
   254  	case HashScheme:
   255  		DeleteLegacyTrieNode(db, hash)
   256  	case PathScheme:
   257  		if owner == (common.Hash{}) {
   258  			DeleteAccountTrieNode(db, path)
   259  		} else {
   260  			DeleteStorageTrieNode(db, owner, path)
   261  		}
   262  	default:
   263  		panic(fmt.Sprintf("Unknown scheme %v", scheme))
   264  	}
   265  }
   266  
   267  // ReadStateScheme reads the state scheme of persistent state, or none
   268  // if the state is not present in database.
   269  func ReadStateScheme(db zonddb.Reader) string {
   270  	// Check if state in path-based scheme is present
   271  	blob, _ := ReadAccountTrieNode(db, nil)
   272  	if len(blob) != 0 {
   273  		return PathScheme
   274  	}
   275  	// In a hash-based scheme, the genesis state is consistently stored
   276  	// on the disk. To assess the scheme of the persistent state, it
   277  	// suffices to inspect the scheme of the genesis state.
   278  	header := ReadHeader(db, ReadCanonicalHash(db, 0), 0)
   279  	if header == nil {
   280  		return "" // empty datadir
   281  	}
   282  	blob = ReadLegacyTrieNode(db, header.Root)
   283  	if len(blob) == 0 {
   284  		return "" // no state in disk
   285  	}
   286  	return HashScheme
   287  }