github.com/avence12/go-ethereum@v1.5.10-0.20170320123548-1dfd65f6d047/light/state.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  	"math/big"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/crypto"
    24  	"golang.org/x/net/context"
    25  )
    26  
    27  // LightState is a memory representation of a state.
    28  // This version is ODR capable, caching only the already accessed part of the
    29  // state, retrieving unknown parts on-demand from the ODR backend. Changes are
    30  // never stored in the local database, only in the memory objects.
    31  type LightState struct {
    32  	odr          OdrBackend
    33  	trie         *LightTrie
    34  	id           *TrieID
    35  	stateObjects map[string]*StateObject
    36  	refund       *big.Int
    37  }
    38  
    39  // NewLightState creates a new LightState with the specified root.
    40  // Note that the creation of a light state is always successful, even if the
    41  // root is non-existent. In that case, ODR retrieval will always be unsuccessful
    42  // and every operation will return with an error or wait for the context to be
    43  // cancelled.
    44  func NewLightState(id *TrieID, odr OdrBackend) *LightState {
    45  	var tr *LightTrie
    46  	if id != nil {
    47  		tr = NewLightTrie(id, odr, true)
    48  	}
    49  	return &LightState{
    50  		odr:          odr,
    51  		trie:         tr,
    52  		id:           id,
    53  		stateObjects: make(map[string]*StateObject),
    54  		refund:       new(big.Int),
    55  	}
    56  }
    57  
    58  // AddRefund adds an amount to the refund value collected during a vm execution
    59  func (self *LightState) AddRefund(gas *big.Int) {
    60  	self.refund.Add(self.refund, gas)
    61  }
    62  
    63  // HasAccount returns true if an account exists at the given address
    64  func (self *LightState) HasAccount(ctx context.Context, addr common.Address) (bool, error) {
    65  	so, err := self.GetStateObject(ctx, addr)
    66  	return so != nil, err
    67  }
    68  
    69  // GetBalance retrieves the balance from the given address or 0 if the account does
    70  // not exist
    71  func (self *LightState) GetBalance(ctx context.Context, addr common.Address) (*big.Int, error) {
    72  	stateObject, err := self.GetStateObject(ctx, addr)
    73  	if err != nil {
    74  		return common.Big0, err
    75  	}
    76  	if stateObject != nil {
    77  		return stateObject.balance, nil
    78  	}
    79  
    80  	return common.Big0, nil
    81  }
    82  
    83  // GetNonce returns the nonce at the given address or 0 if the account does
    84  // not exist
    85  func (self *LightState) GetNonce(ctx context.Context, addr common.Address) (uint64, error) {
    86  	stateObject, err := self.GetStateObject(ctx, addr)
    87  	if err != nil {
    88  		return 0, err
    89  	}
    90  	if stateObject != nil {
    91  		return stateObject.nonce, nil
    92  	}
    93  	return 0, nil
    94  }
    95  
    96  // GetCode returns the contract code at the given address or nil if the account
    97  // does not exist
    98  func (self *LightState) GetCode(ctx context.Context, addr common.Address) ([]byte, error) {
    99  	stateObject, err := self.GetStateObject(ctx, addr)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	if stateObject != nil {
   104  		return stateObject.code, nil
   105  	}
   106  	return nil, nil
   107  }
   108  
   109  // GetState returns the contract storage value at storage address b from the
   110  // contract address a or common.Hash{} if the account does not exist
   111  func (self *LightState) GetState(ctx context.Context, a common.Address, b common.Hash) (common.Hash, error) {
   112  	stateObject, err := self.GetStateObject(ctx, a)
   113  	if err == nil && stateObject != nil {
   114  		return stateObject.GetState(ctx, b)
   115  	}
   116  	return common.Hash{}, err
   117  }
   118  
   119  // HasSuicided returns true if the given account has been marked for deletion
   120  // or false if the account does not exist
   121  func (self *LightState) HasSuicided(ctx context.Context, addr common.Address) (bool, error) {
   122  	stateObject, err := self.GetStateObject(ctx, addr)
   123  	if err == nil && stateObject != nil {
   124  		return stateObject.remove, nil
   125  	}
   126  	return false, err
   127  }
   128  
   129  /*
   130   * SETTERS
   131   */
   132  
   133  // AddBalance adds the given amount to the balance of the specified account
   134  func (self *LightState) AddBalance(ctx context.Context, addr common.Address, amount *big.Int) error {
   135  	stateObject, err := self.GetOrNewStateObject(ctx, addr)
   136  	if err == nil && stateObject != nil {
   137  		stateObject.AddBalance(amount)
   138  	}
   139  	return err
   140  }
   141  
   142  // SubBalance adds the given amount to the balance of the specified account
   143  func (self *LightState) SubBalance(ctx context.Context, addr common.Address, amount *big.Int) error {
   144  	stateObject, err := self.GetOrNewStateObject(ctx, addr)
   145  	if err == nil && stateObject != nil {
   146  		stateObject.SubBalance(amount)
   147  	}
   148  	return err
   149  }
   150  
   151  // SetNonce sets the nonce of the specified account
   152  func (self *LightState) SetNonce(ctx context.Context, addr common.Address, nonce uint64) error {
   153  	stateObject, err := self.GetOrNewStateObject(ctx, addr)
   154  	if err == nil && stateObject != nil {
   155  		stateObject.SetNonce(nonce)
   156  	}
   157  	return err
   158  }
   159  
   160  // SetCode sets the contract code at the specified account
   161  func (self *LightState) SetCode(ctx context.Context, addr common.Address, code []byte) error {
   162  	stateObject, err := self.GetOrNewStateObject(ctx, addr)
   163  	if err == nil && stateObject != nil {
   164  		stateObject.SetCode(crypto.Keccak256Hash(code), code)
   165  	}
   166  	return err
   167  }
   168  
   169  // SetState sets the storage value at storage address key of the account addr
   170  func (self *LightState) SetState(ctx context.Context, addr common.Address, key common.Hash, value common.Hash) error {
   171  	stateObject, err := self.GetOrNewStateObject(ctx, addr)
   172  	if err == nil && stateObject != nil {
   173  		stateObject.SetState(key, value)
   174  	}
   175  	return err
   176  }
   177  
   178  // Delete marks an account to be removed and clears its balance
   179  func (self *LightState) Suicide(ctx context.Context, addr common.Address) (bool, error) {
   180  	stateObject, err := self.GetOrNewStateObject(ctx, addr)
   181  	if err == nil && stateObject != nil {
   182  		stateObject.MarkForDeletion()
   183  		stateObject.balance = new(big.Int)
   184  
   185  		return true, nil
   186  	}
   187  
   188  	return false, err
   189  }
   190  
   191  //
   192  // Get, set, new state object methods
   193  //
   194  
   195  // GetStateObject returns the state object of the given account or nil if the
   196  // account does not exist
   197  func (self *LightState) GetStateObject(ctx context.Context, addr common.Address) (stateObject *StateObject, err error) {
   198  	stateObject = self.stateObjects[addr.Str()]
   199  	if stateObject != nil {
   200  		if stateObject.deleted {
   201  			stateObject = nil
   202  		}
   203  		return stateObject, nil
   204  	}
   205  	data, err := self.trie.Get(ctx, addr[:])
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	if len(data) == 0 {
   210  		return nil, nil
   211  	}
   212  
   213  	stateObject, err = DecodeObject(ctx, self.id, addr, self.odr, []byte(data))
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  
   218  	self.SetStateObject(stateObject)
   219  
   220  	return stateObject, nil
   221  }
   222  
   223  // SetStateObject sets the state object of the given account
   224  func (self *LightState) SetStateObject(object *StateObject) {
   225  	self.stateObjects[object.Address().Str()] = object
   226  }
   227  
   228  // GetOrNewStateObject returns the state object of the given account or creates a
   229  // new one if the account does not exist
   230  func (self *LightState) GetOrNewStateObject(ctx context.Context, addr common.Address) (*StateObject, error) {
   231  	stateObject, err := self.GetStateObject(ctx, addr)
   232  	if err == nil && (stateObject == nil || stateObject.deleted) {
   233  		stateObject, err = self.CreateStateObject(ctx, addr)
   234  	}
   235  	return stateObject, err
   236  }
   237  
   238  // newStateObject creates a state object whether it exists in the state or not
   239  func (self *LightState) newStateObject(addr common.Address) *StateObject {
   240  	stateObject := NewStateObject(addr, self.odr)
   241  	self.stateObjects[addr.Str()] = stateObject
   242  
   243  	return stateObject
   244  }
   245  
   246  // CreateStateObject creates creates a new state object and takes ownership.
   247  // This is different from "NewStateObject"
   248  func (self *LightState) CreateStateObject(ctx context.Context, addr common.Address) (*StateObject, error) {
   249  	// Get previous (if any)
   250  	so, err := self.GetStateObject(ctx, addr)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  	// Create a new one
   255  	newSo := self.newStateObject(addr)
   256  
   257  	// If it existed set the balance to the new account
   258  	if so != nil {
   259  		newSo.balance = so.balance
   260  	}
   261  
   262  	return newSo, nil
   263  }
   264  
   265  // ForEachStorage calls a callback function for every key/value pair found
   266  // in the local storage cache. Note that unlike core/state.StateObject,
   267  // light.StateObject only returns cached values and doesn't download the
   268  // entire storage tree.
   269  func (self *LightState) ForEachStorage(ctx context.Context, addr common.Address, cb func(key, value common.Hash) bool) error {
   270  	so, err := self.GetStateObject(ctx, addr)
   271  	if err != nil {
   272  		return err
   273  	}
   274  
   275  	if so == nil {
   276  		return nil
   277  	}
   278  
   279  	for h, v := range so.storage {
   280  		cb(h, v)
   281  	}
   282  	return nil
   283  }
   284  
   285  //
   286  // Setting, copying of the state methods
   287  //
   288  
   289  // Copy creates a copy of the state
   290  func (self *LightState) Copy() *LightState {
   291  	// ignore error - we assume state-to-be-copied always exists
   292  	state := NewLightState(nil, self.odr)
   293  	state.trie = self.trie
   294  	state.id = self.id
   295  	for k, stateObject := range self.stateObjects {
   296  		if stateObject.dirty {
   297  			state.stateObjects[k] = stateObject.Copy()
   298  		}
   299  	}
   300  
   301  	state.refund.Set(self.refund)
   302  	return state
   303  }
   304  
   305  // Set copies the contents of the given state onto this state, overwriting
   306  // its contents
   307  func (self *LightState) Set(state *LightState) {
   308  	self.trie = state.trie
   309  	self.stateObjects = state.stateObjects
   310  	self.refund = state.refund
   311  }
   312  
   313  // GetRefund returns the refund value collected during a vm execution
   314  func (self *LightState) GetRefund() *big.Int {
   315  	return self.refund
   316  }