github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/core/state/database.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:34</date>
    10  //</624342617307484160>
    11  
    12  
    13  package state
    14  
    15  import (
    16  	"fmt"
    17  	"sync"
    18  
    19  	"github.com/ethereum/go-ethereum/common"
    20  	"github.com/ethereum/go-ethereum/ethdb"
    21  	"github.com/ethereum/go-ethereum/trie"
    22  	lru "github.com/hashicorp/golang-lru"
    23  )
    24  
    25  //trie缓存生成限制,在此之后将trie节点从内存中逐出。
    26  var MaxTrieCacheGen = uint16(120)
    27  
    28  const (
    29  //要保留的过去尝试次数。此值的选择方式如下:
    30  //合理的链条重铺深度将达到现有的三重。
    31  	maxPastTries = 12
    32  
    33  //要保留的codehash->大小关联数。
    34  	codeSizeCacheSize = 100000
    35  )
    36  
    37  //数据库将访问权限包装为“尝试”和“合同代码”。
    38  type Database interface {
    39  //opentrie打开主帐户trie。
    40  	OpenTrie(root common.Hash) (Trie, error)
    41  
    42  //openstoragetrie打开帐户的存储trie。
    43  	OpenStorageTrie(addrHash, root common.Hash) (Trie, error)
    44  
    45  //copy trie返回给定trie的独立副本。
    46  	CopyTrie(Trie) Trie
    47  
    48  //ContractCode检索特定合同的代码。
    49  	ContractCode(addrHash, codeHash common.Hash) ([]byte, error)
    50  
    51  //ContractCodeSize检索特定合同代码的大小。
    52  	ContractCodeSize(addrHash, codeHash common.Hash) (int, error)
    53  
    54  //triedb检索用于数据存储的低级trie数据库。
    55  	TrieDB() *trie.Database
    56  }
    57  
    58  //特里亚是以太梅克尔特里亚。
    59  type Trie interface {
    60  	TryGet(key []byte) ([]byte, error)
    61  	TryUpdate(key, value []byte) error
    62  	TryDelete(key []byte) error
    63  	Commit(onleaf trie.LeafCallback) (common.Hash, error)
    64  	Hash() common.Hash
    65  	NodeIterator(startKey []byte) trie.NodeIterator
    66  GetKey([]byte) []byte //TODO(FJL):移除SecureTrie时移除此项
    67  	Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error
    68  }
    69  
    70  //NeXDATA为状态创建后备存储。返回的数据库是安全的
    71  //同时使用并将缓存的trie节点保留在内存中。游泳池是可选的
    72  //在低级存储层和
    73  //高级Trie抽象。
    74  func NewDatabase(db ethdb.Database) Database {
    75  	csc, _ := lru.New(codeSizeCacheSize)
    76  	return &cachingDB{
    77  		db:            trie.NewDatabase(db),
    78  		codeSizeCache: csc,
    79  	}
    80  }
    81  
    82  type cachingDB struct {
    83  	db            *trie.Database
    84  	mu            sync.Mutex
    85  	pastTries     []*trie.SecureTrie
    86  	codeSizeCache *lru.Cache
    87  }
    88  
    89  //opentrie打开主帐户trie。
    90  func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
    91  	db.mu.Lock()
    92  	defer db.mu.Unlock()
    93  
    94  	for i := len(db.pastTries) - 1; i >= 0; i-- {
    95  		if db.pastTries[i].Hash() == root {
    96  			return cachedTrie{db.pastTries[i].Copy(), db}, nil
    97  		}
    98  	}
    99  	tr, err := trie.NewSecure(root, db.db, MaxTrieCacheGen)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	return cachedTrie{tr, db}, nil
   104  }
   105  
   106  func (db *cachingDB) pushTrie(t *trie.SecureTrie) {
   107  	db.mu.Lock()
   108  	defer db.mu.Unlock()
   109  
   110  	if len(db.pastTries) >= maxPastTries {
   111  		copy(db.pastTries, db.pastTries[1:])
   112  		db.pastTries[len(db.pastTries)-1] = t
   113  	} else {
   114  		db.pastTries = append(db.pastTries, t)
   115  	}
   116  }
   117  
   118  //openstoragetrie打开帐户的存储trie。
   119  func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) {
   120  	return trie.NewSecure(root, db.db, 0)
   121  }
   122  
   123  //copy trie返回给定trie的独立副本。
   124  func (db *cachingDB) CopyTrie(t Trie) Trie {
   125  	switch t := t.(type) {
   126  	case cachedTrie:
   127  		return cachedTrie{t.SecureTrie.Copy(), db}
   128  	case *trie.SecureTrie:
   129  		return t.Copy()
   130  	default:
   131  		panic(fmt.Errorf("unknown trie type %T", t))
   132  	}
   133  }
   134  
   135  //ContractCode检索特定合同的代码。
   136  func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) {
   137  	code, err := db.db.Node(codeHash)
   138  	if err == nil {
   139  		db.codeSizeCache.Add(codeHash, len(code))
   140  	}
   141  	return code, err
   142  }
   143  
   144  //ContractCodeSize检索特定合同代码的大小。
   145  func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) {
   146  	if cached, ok := db.codeSizeCache.Get(codeHash); ok {
   147  		return cached.(int), nil
   148  	}
   149  	code, err := db.ContractCode(addrHash, codeHash)
   150  	return len(code), err
   151  }
   152  
   153  //triedb检索任何中间trie节点缓存层。
   154  func (db *cachingDB) TrieDB() *trie.Database {
   155  	return db.db
   156  }
   157  
   158  //cachedtrie在提交时将其trie插入cachingdb。
   159  type cachedTrie struct {
   160  	*trie.SecureTrie
   161  	db *cachingDB
   162  }
   163  
   164  func (m cachedTrie) Commit(onleaf trie.LeafCallback) (common.Hash, error) {
   165  	root, err := m.SecureTrie.Commit(onleaf)
   166  	if err == nil {
   167  		m.db.pushTrie(m.SecureTrie)
   168  	}
   169  	return root, err
   170  }
   171  
   172  func (m cachedTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
   173  	return m.SecureTrie.Prove(key, fromLevel, proofDb)
   174  }
   175