github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/trie/secure_trie.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 19:16:45</date>
    10  //</624450123312664576>
    11  
    12  
    13  package trie
    14  
    15  import (
    16  	"fmt"
    17  
    18  	"github.com/ethereum/go-ethereum/common"
    19  	"github.com/ethereum/go-ethereum/log"
    20  )
    21  
    22  //securetrie使用键哈希对trie进行包装。在安全的测试中,所有
    23  //访问操作使用keccak256散列密钥。这防止
    24  //通过创建长的节点链来调用代码
    25  //增加访问时间。
    26  //
    27  //与常规trie相反,只能使用
    28  //新建,必须具有附加的数据库。数据库还存储
    29  //每个键的预映像。
    30  //
    31  //SecureTrie不能同时使用。
    32  type SecureTrie struct {
    33  	trie             Trie
    34  	hashKeyBuf       [common.HashLength]byte
    35  	secKeyCache      map[string][]byte
    36  secKeyCacheOwner *SecureTrie //指向self的指针,不匹配时替换密钥缓存
    37  }
    38  
    39  //NewSecure从备份数据库创建具有现有根节点的trie
    40  //以及可选的中间内存节点池。
    41  //
    42  //如果根是空字符串的零哈希或sha3哈希,则
    43  //trie最初是空的。否则,如果db为零,new将恐慌。
    44  //如果找不到根节点,则返回MissingNodeError。
    45  //
    46  //访问trie会根据需要从数据库或节点池加载节点。
    47  //加载的节点将一直保留,直到其“缓存生成”过期。
    48  //每次调用commit都会创建新的缓存生成。
    49  //cachelimit设置要保留的上一代缓存的数量。
    50  func NewSecure(root common.Hash, db *Database, cachelimit uint16) (*SecureTrie, error) {
    51  	if db == nil {
    52  		panic("trie.NewSecure called without a database")
    53  	}
    54  	trie, err := New(root, db)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	trie.SetCacheLimit(cachelimit)
    59  	return &SecureTrie{trie: *trie}, nil
    60  }
    61  
    62  //get返回存储在trie中的键的值。
    63  //调用方不能修改值字节。
    64  func (t *SecureTrie) Get(key []byte) []byte {
    65  	res, err := t.TryGet(key)
    66  	if err != nil {
    67  		log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
    68  	}
    69  	return res
    70  }
    71  
    72  //Tryget返回存储在trie中的键的值。
    73  //调用方不能修改值字节。
    74  //如果在数据库中找不到节点,则返回MissingNodeError。
    75  func (t *SecureTrie) TryGet(key []byte) ([]byte, error) {
    76  	return t.trie.TryGet(t.hashKey(key))
    77  }
    78  
    79  //更新trie中的关联键和值。后续呼叫
    80  //get将返回值。如果值的长度为零,则任何现有值
    81  //从trie中删除,调用get将返回nil。
    82  //
    83  //当值字节是
    84  //存储在trie中。
    85  func (t *SecureTrie) Update(key, value []byte) {
    86  	if err := t.TryUpdate(key, value); err != nil {
    87  		log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
    88  	}
    89  }
    90  
    91  //TryUpdate将键与trie中的值关联。后续呼叫
    92  //get将返回值。如果值的长度为零,则任何现有值
    93  //从trie中删除,调用get将返回nil。
    94  //
    95  //当值字节是
    96  //存储在trie中。
    97  //
    98  //如果在数据库中找不到节点,则返回MissingNodeError。
    99  func (t *SecureTrie) TryUpdate(key, value []byte) error {
   100  	hk := t.hashKey(key)
   101  	err := t.trie.TryUpdate(hk, value)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	t.getSecKeyCache()[string(hk)] = common.CopyBytes(key)
   106  	return nil
   107  }
   108  
   109  //删除从trie中删除键的任何现有值。
   110  func (t *SecureTrie) Delete(key []byte) {
   111  	if err := t.TryDelete(key); err != nil {
   112  		log.Error(fmt.Sprintf("Unhandled trie error: %v", err))
   113  	}
   114  }
   115  
   116  //Trydelete从trie中删除键的任何现有值。
   117  //如果在数据库中找不到节点,则返回MissingNodeError。
   118  func (t *SecureTrie) TryDelete(key []byte) error {
   119  	hk := t.hashKey(key)
   120  	delete(t.getSecKeyCache(), string(hk))
   121  	return t.trie.TryDelete(hk)
   122  }
   123  
   124  //getkey返回哈希键的sha3 preimage
   125  //以前用于存储值。
   126  func (t *SecureTrie) GetKey(shaKey []byte) []byte {
   127  	if key, ok := t.getSecKeyCache()[string(shaKey)]; ok {
   128  		return key
   129  	}
   130  	key, _ := t.trie.db.preimage(common.BytesToHash(shaKey))
   131  	return key
   132  }
   133  
   134  //commit将所有节点和安全哈希预映像写入trie的数据库。
   135  //节点以其sha3散列作为密钥存储。
   136  //
   137  //提交将刷新内存中的节点。后续的get调用将加载节点
   138  //从数据库中。
   139  func (t *SecureTrie) Commit(onleaf LeafCallback) (root common.Hash, err error) {
   140  //将所有预映像写入实际磁盘数据库
   141  	if len(t.getSecKeyCache()) > 0 {
   142  		t.trie.db.lock.Lock()
   143  		for hk, key := range t.secKeyCache {
   144  			t.trie.db.insertPreimage(common.BytesToHash([]byte(hk)), key)
   145  		}
   146  		t.trie.db.lock.Unlock()
   147  
   148  		t.secKeyCache = make(map[string][]byte)
   149  	}
   150  //将trie提交到其中间节点数据库
   151  	return t.trie.Commit(onleaf)
   152  }
   153  
   154  //hash返回securetrie的根哈希。它不会写信给
   155  //即使trie没有数据库也可以使用。
   156  func (t *SecureTrie) Hash() common.Hash {
   157  	return t.trie.Hash()
   158  }
   159  
   160  //root返回securetrie的根哈希。
   161  //已弃用:请改用哈希。
   162  func (t *SecureTrie) Root() []byte {
   163  	return t.trie.Root()
   164  }
   165  
   166  //copy返回securetrie的副本。
   167  func (t *SecureTrie) Copy() *SecureTrie {
   168  	cpy := *t
   169  	return &cpy
   170  }
   171  
   172  //nodeiterator返回返回底层trie节点的迭代器。迭代
   173  //从给定的开始键之后的键开始。
   174  func (t *SecureTrie) NodeIterator(start []byte) NodeIterator {
   175  	return t.trie.NodeIterator(start)
   176  }
   177  
   178  //hash key返回作为临时缓冲区的键的哈希。
   179  //调用方不能保留返回值,因为它将成为
   180  //下次调用hashkey或seckey时无效。
   181  func (t *SecureTrie) hashKey(key []byte) []byte {
   182  	h := newHasher(0, 0, nil)
   183  	h.sha.Reset()
   184  	h.sha.Write(key)
   185  	buf := h.sha.Sum(t.hashKeyBuf[:0])
   186  	returnHasherToPool(h)
   187  	return buf
   188  }
   189  
   190  //GetSecKeyCache返回当前的安全密钥缓存,如果
   191  //所有权已更改(即当前安全的trie是另一个拥有者的副本
   192  //实际缓存)。
   193  func (t *SecureTrie) getSecKeyCache() map[string][]byte {
   194  	if t != t.secKeyCacheOwner {
   195  		t.secKeyCacheOwner = t
   196  		t.secKeyCache = make(map[string][]byte)
   197  	}
   198  	return t.secKeyCache
   199  }
   200