github.com/luckypickle/go-ethereum-vet@v1.14.2/light/trie.go (about)

     1  // Copyright 2015 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 light
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  
    24  	"github.com/luckypickle/go-ethereum-vet/common"
    25  	"github.com/luckypickle/go-ethereum-vet/core/state"
    26  	"github.com/luckypickle/go-ethereum-vet/core/types"
    27  	"github.com/luckypickle/go-ethereum-vet/crypto"
    28  	"github.com/luckypickle/go-ethereum-vet/ethdb"
    29  	"github.com/luckypickle/go-ethereum-vet/trie"
    30  )
    31  
    32  func NewState(ctx context.Context, head *types.Header, odr OdrBackend) *state.StateDB {
    33  	state, _ := state.New(head.Root, NewStateDatabase(ctx, head, odr))
    34  	return state
    35  }
    36  
    37  func NewStateDatabase(ctx context.Context, head *types.Header, odr OdrBackend) state.Database {
    38  	return &odrDatabase{ctx, StateTrieID(head), odr}
    39  }
    40  
    41  type odrDatabase struct {
    42  	ctx     context.Context
    43  	id      *TrieID
    44  	backend OdrBackend
    45  }
    46  
    47  func (db *odrDatabase) OpenTrie(root common.Hash) (state.Trie, error) {
    48  	return &odrTrie{db: db, id: db.id}, nil
    49  }
    50  
    51  func (db *odrDatabase) OpenStorageTrie(addrHash, root common.Hash) (state.Trie, error) {
    52  	return &odrTrie{db: db, id: StorageTrieID(db.id, addrHash, root)}, nil
    53  }
    54  
    55  func (db *odrDatabase) CopyTrie(t state.Trie) state.Trie {
    56  	switch t := t.(type) {
    57  	case *odrTrie:
    58  		cpy := &odrTrie{db: t.db, id: t.id}
    59  		if t.trie != nil {
    60  			cpytrie := *t.trie
    61  			cpy.trie = &cpytrie
    62  		}
    63  		return cpy
    64  	default:
    65  		panic(fmt.Errorf("unknown trie type %T", t))
    66  	}
    67  }
    68  
    69  func (db *odrDatabase) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) {
    70  	if codeHash == sha3_nil {
    71  		return nil, nil
    72  	}
    73  	if code, err := db.backend.Database().Get(codeHash[:]); err == nil {
    74  		return code, nil
    75  	}
    76  	id := *db.id
    77  	id.AccKey = addrHash[:]
    78  	req := &CodeRequest{Id: &id, Hash: codeHash}
    79  	err := db.backend.Retrieve(db.ctx, req)
    80  	return req.Data, err
    81  }
    82  
    83  func (db *odrDatabase) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) {
    84  	code, err := db.ContractCode(addrHash, codeHash)
    85  	return len(code), err
    86  }
    87  
    88  func (db *odrDatabase) TrieDB() *trie.Database {
    89  	return nil
    90  }
    91  
    92  type odrTrie struct {
    93  	db   *odrDatabase
    94  	id   *TrieID
    95  	trie *trie.Trie
    96  }
    97  
    98  func (t *odrTrie) TryGet(key []byte) ([]byte, error) {
    99  	key = crypto.Keccak256(key)
   100  	var res []byte
   101  	err := t.do(key, func() (err error) {
   102  		res, err = t.trie.TryGet(key)
   103  		return err
   104  	})
   105  	return res, err
   106  }
   107  
   108  func (t *odrTrie) TryUpdate(key, value []byte) error {
   109  	key = crypto.Keccak256(key)
   110  	return t.do(key, func() error {
   111  		return t.trie.TryDelete(key)
   112  	})
   113  }
   114  
   115  func (t *odrTrie) TryDelete(key []byte) error {
   116  	key = crypto.Keccak256(key)
   117  	return t.do(key, func() error {
   118  		return t.trie.TryDelete(key)
   119  	})
   120  }
   121  
   122  func (t *odrTrie) Commit(onleaf trie.LeafCallback) (common.Hash, error) {
   123  	if t.trie == nil {
   124  		return t.id.Root, nil
   125  	}
   126  	return t.trie.Commit(onleaf)
   127  }
   128  
   129  func (t *odrTrie) Hash() common.Hash {
   130  	if t.trie == nil {
   131  		return t.id.Root
   132  	}
   133  	return t.trie.Hash()
   134  }
   135  
   136  func (t *odrTrie) NodeIterator(startkey []byte) trie.NodeIterator {
   137  	return newNodeIterator(t, startkey)
   138  }
   139  
   140  func (t *odrTrie) GetKey(sha []byte) []byte {
   141  	return nil
   142  }
   143  
   144  func (t *odrTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
   145  	return errors.New("not implemented, needs client/server interface split")
   146  }
   147  
   148  // do tries and retries to execute a function until it returns with no error or
   149  // an error type other than MissingNodeError
   150  func (t *odrTrie) do(key []byte, fn func() error) error {
   151  	for {
   152  		var err error
   153  		if t.trie == nil {
   154  			t.trie, err = trie.New(t.id.Root, trie.NewDatabase(t.db.backend.Database()))
   155  		}
   156  		if err == nil {
   157  			err = fn()
   158  		}
   159  		if _, ok := err.(*trie.MissingNodeError); !ok {
   160  			return err
   161  		}
   162  		r := &TrieRequest{Id: t.id, Key: key}
   163  		if err := t.db.backend.Retrieve(t.db.ctx, r); err != nil {
   164  			return err
   165  		}
   166  	}
   167  }
   168  
   169  type nodeIterator struct {
   170  	trie.NodeIterator
   171  	t   *odrTrie
   172  	err error
   173  }
   174  
   175  func newNodeIterator(t *odrTrie, startkey []byte) trie.NodeIterator {
   176  	it := &nodeIterator{t: t}
   177  	// Open the actual non-ODR trie if that hasn't happened yet.
   178  	if t.trie == nil {
   179  		it.do(func() error {
   180  			t, err := trie.New(t.id.Root, trie.NewDatabase(t.db.backend.Database()))
   181  			if err == nil {
   182  				it.t.trie = t
   183  			}
   184  			return err
   185  		})
   186  	}
   187  	it.do(func() error {
   188  		it.NodeIterator = it.t.trie.NodeIterator(startkey)
   189  		return it.NodeIterator.Error()
   190  	})
   191  	return it
   192  }
   193  
   194  func (it *nodeIterator) Next(descend bool) bool {
   195  	var ok bool
   196  	it.do(func() error {
   197  		ok = it.NodeIterator.Next(descend)
   198  		return it.NodeIterator.Error()
   199  	})
   200  	return ok
   201  }
   202  
   203  // do runs fn and attempts to fill in missing nodes by retrieving.
   204  func (it *nodeIterator) do(fn func() error) {
   205  	var lasthash common.Hash
   206  	for {
   207  		it.err = fn()
   208  		missing, ok := it.err.(*trie.MissingNodeError)
   209  		if !ok {
   210  			return
   211  		}
   212  		if missing.NodeHash == lasthash {
   213  			it.err = fmt.Errorf("retrieve loop for trie node %x", missing.NodeHash)
   214  			return
   215  		}
   216  		lasthash = missing.NodeHash
   217  		r := &TrieRequest{Id: it.t.id, Key: nibblesToKey(missing.Path)}
   218  		if it.err = it.t.db.backend.Retrieve(it.t.db.ctx, r); it.err != nil {
   219  			return
   220  		}
   221  	}
   222  }
   223  
   224  func (it *nodeIterator) Error() error {
   225  	if it.err != nil {
   226  		return it.err
   227  	}
   228  	return it.NodeIterator.Error()
   229  }
   230  
   231  func nibblesToKey(nib []byte) []byte {
   232  	if len(nib) > 0 && nib[len(nib)-1] == 0x10 {
   233  		nib = nib[:len(nib)-1] // drop terminator
   234  	}
   235  	if len(nib)&1 == 1 {
   236  		nib = append(nib, 0) // make even
   237  	}
   238  	key := make([]byte, len(nib)/2)
   239  	for bi, ni := 0, 0; ni < len(nib); bi, ni = bi+1, ni+2 {
   240  		key[bi] = nib[ni]<<4 | nib[ni+1]
   241  	}
   242  	return key
   243  }