github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/light/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:39</date>
    10  //</624450096733360128>
    11  
    12  
    13  package light
    14  
    15  import (
    16  	"context"
    17  	"errors"
    18  	"fmt"
    19  
    20  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/core/state"
    22  	"github.com/ethereum/go-ethereum/core/types"
    23  	"github.com/ethereum/go-ethereum/crypto"
    24  	"github.com/ethereum/go-ethereum/ethdb"
    25  	"github.com/ethereum/go-ethereum/trie"
    26  )
    27  
    28  func NewState(ctx context.Context, head *types.Header, odr OdrBackend) *state.StateDB {
    29  	state, _ := state.New(head.Root, NewStateDatabase(ctx, head, odr))
    30  	return state
    31  }
    32  
    33  func NewStateDatabase(ctx context.Context, head *types.Header, odr OdrBackend) state.Database {
    34  	return &odrDatabase{ctx, StateTrieID(head), odr}
    35  }
    36  
    37  type odrDatabase struct {
    38  	ctx     context.Context
    39  	id      *TrieID
    40  	backend OdrBackend
    41  }
    42  
    43  func (db *odrDatabase) OpenTrie(root common.Hash) (state.Trie, error) {
    44  	return &odrTrie{db: db, id: db.id}, nil
    45  }
    46  
    47  func (db *odrDatabase) OpenStorageTrie(addrHash, root common.Hash) (state.Trie, error) {
    48  	return &odrTrie{db: db, id: StorageTrieID(db.id, addrHash, root)}, nil
    49  }
    50  
    51  func (db *odrDatabase) CopyTrie(t state.Trie) state.Trie {
    52  	switch t := t.(type) {
    53  	case *odrTrie:
    54  		cpy := &odrTrie{db: t.db, id: t.id}
    55  		if t.trie != nil {
    56  			cpytrie := *t.trie
    57  			cpy.trie = &cpytrie
    58  		}
    59  		return cpy
    60  	default:
    61  		panic(fmt.Errorf("unknown trie type %T", t))
    62  	}
    63  }
    64  
    65  func (db *odrDatabase) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) {
    66  	if codeHash == sha3_nil {
    67  		return nil, nil
    68  	}
    69  	if code, err := db.backend.Database().Get(codeHash[:]); err == nil {
    70  		return code, nil
    71  	}
    72  	id := *db.id
    73  	id.AccKey = addrHash[:]
    74  	req := &CodeRequest{Id: &id, Hash: codeHash}
    75  	err := db.backend.Retrieve(db.ctx, req)
    76  	return req.Data, err
    77  }
    78  
    79  func (db *odrDatabase) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) {
    80  	code, err := db.ContractCode(addrHash, codeHash)
    81  	return len(code), err
    82  }
    83  
    84  func (db *odrDatabase) TrieDB() *trie.Database {
    85  	return nil
    86  }
    87  
    88  type odrTrie struct {
    89  	db   *odrDatabase
    90  	id   *TrieID
    91  	trie *trie.Trie
    92  }
    93  
    94  func (t *odrTrie) TryGet(key []byte) ([]byte, error) {
    95  	key = crypto.Keccak256(key)
    96  	var res []byte
    97  	err := t.do(key, func() (err error) {
    98  		res, err = t.trie.TryGet(key)
    99  		return err
   100  	})
   101  	return res, err
   102  }
   103  
   104  func (t *odrTrie) TryUpdate(key, value []byte) error {
   105  	key = crypto.Keccak256(key)
   106  	return t.do(key, func() error {
   107  		return t.trie.TryUpdate(key, value)
   108  	})
   109  }
   110  
   111  func (t *odrTrie) TryDelete(key []byte) error {
   112  	key = crypto.Keccak256(key)
   113  	return t.do(key, func() error {
   114  		return t.trie.TryDelete(key)
   115  	})
   116  }
   117  
   118  func (t *odrTrie) Commit(onleaf trie.LeafCallback) (common.Hash, error) {
   119  	if t.trie == nil {
   120  		return t.id.Root, nil
   121  	}
   122  	return t.trie.Commit(onleaf)
   123  }
   124  
   125  func (t *odrTrie) Hash() common.Hash {
   126  	if t.trie == nil {
   127  		return t.id.Root
   128  	}
   129  	return t.trie.Hash()
   130  }
   131  
   132  func (t *odrTrie) NodeIterator(startkey []byte) trie.NodeIterator {
   133  	return newNodeIterator(t, startkey)
   134  }
   135  
   136  func (t *odrTrie) GetKey(sha []byte) []byte {
   137  	return nil
   138  }
   139  
   140  func (t *odrTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
   141  	return errors.New("not implemented, needs client/server interface split")
   142  }
   143  
   144  //尝试并重试执行一个函数,直到它返回时没有错误或
   145  //MissingNodeError以外的错误类型
   146  func (t *odrTrie) do(key []byte, fn func() error) error {
   147  	for {
   148  		var err error
   149  		if t.trie == nil {
   150  			t.trie, err = trie.New(t.id.Root, trie.NewDatabase(t.db.backend.Database()))
   151  		}
   152  		if err == nil {
   153  			err = fn()
   154  		}
   155  		if _, ok := err.(*trie.MissingNodeError); !ok {
   156  			return err
   157  		}
   158  		r := &TrieRequest{Id: t.id, Key: key}
   159  		if err := t.db.backend.Retrieve(t.db.ctx, r); err != nil {
   160  			return err
   161  		}
   162  	}
   163  }
   164  
   165  type nodeIterator struct {
   166  	trie.NodeIterator
   167  	t   *odrTrie
   168  	err error
   169  }
   170  
   171  func newNodeIterator(t *odrTrie, startkey []byte) trie.NodeIterator {
   172  	it := &nodeIterator{t: t}
   173  //如果还没有打开实际的非odr trie。
   174  	if t.trie == nil {
   175  		it.do(func() error {
   176  			t, err := trie.New(t.id.Root, trie.NewDatabase(t.db.backend.Database()))
   177  			if err == nil {
   178  				it.t.trie = t
   179  			}
   180  			return err
   181  		})
   182  	}
   183  	it.do(func() error {
   184  		it.NodeIterator = it.t.trie.NodeIterator(startkey)
   185  		return it.NodeIterator.Error()
   186  	})
   187  	return it
   188  }
   189  
   190  func (it *nodeIterator) Next(descend bool) bool {
   191  	var ok bool
   192  	it.do(func() error {
   193  		ok = it.NodeIterator.Next(descend)
   194  		return it.NodeIterator.Error()
   195  	})
   196  	return ok
   197  }
   198  
   199  //do运行fn并尝试通过检索来填充丢失的节点。
   200  func (it *nodeIterator) do(fn func() error) {
   201  	var lasthash common.Hash
   202  	for {
   203  		it.err = fn()
   204  		missing, ok := it.err.(*trie.MissingNodeError)
   205  		if !ok {
   206  			return
   207  		}
   208  		if missing.NodeHash == lasthash {
   209  			it.err = fmt.Errorf("retrieve loop for trie node %x", missing.NodeHash)
   210  			return
   211  		}
   212  		lasthash = missing.NodeHash
   213  		r := &TrieRequest{Id: it.t.id, Key: nibblesToKey(missing.Path)}
   214  		if it.err = it.t.db.backend.Retrieve(it.t.db.ctx, r); it.err != nil {
   215  			return
   216  		}
   217  	}
   218  }
   219  
   220  func (it *nodeIterator) Error() error {
   221  	if it.err != nil {
   222  		return it.err
   223  	}
   224  	return it.NodeIterator.Error()
   225  }
   226  
   227  func nibblesToKey(nib []byte) []byte {
   228  	if len(nib) > 0 && nib[len(nib)-1] == 0x10 {
   229  nib = nib[:len(nib)-1] //液滴终止器
   230  	}
   231  	if len(nib)&1 == 1 {
   232  nib = append(nib, 0) //使均匀
   233  	}
   234  	key := make([]byte, len(nib)/2)
   235  	for bi, ni := 0, 0; ni < len(nib); bi, ni = bi+1, ni+2 {
   236  		key[bi] = nib[ni]<<4 | nib[ni+1]
   237  	}
   238  	return key
   239  }
   240