github.com/amazechain/amc@v0.1.3/modules/state/state_object.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package state
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"github.com/amazechain/amc/common/account"
    23  	"github.com/amazechain/amc/common/types"
    24  	"github.com/amazechain/amc/internal/avm/rlp"
    25  	"github.com/amazechain/amc/utils"
    26  	"io"
    27  	"math/big"
    28  
    29  	"github.com/holiman/uint256"
    30  )
    31  
    32  // var emptyCodeHash = crypto.Keccak256(nil)
    33  var emptyCodeHash = utils.Keccak256(nil)
    34  var emptyCodeHashH = types.BytesToHash(emptyCodeHash)
    35  
    36  type Code []byte
    37  
    38  func (c Code) String() string {
    39  	return string(c) //strings.Join(Disassemble(c), " ")
    40  }
    41  
    42  type Storage map[types.Hash]uint256.Int
    43  
    44  func (s Storage) String() (str string) {
    45  	for key, value := range s {
    46  		str += fmt.Sprintf("%X : %X\n", key, value)
    47  	}
    48  
    49  	return
    50  }
    51  
    52  func (s Storage) Copy() Storage {
    53  	cpy := make(Storage)
    54  	for key, value := range s {
    55  		cpy[key] = value
    56  	}
    57  
    58  	return cpy
    59  }
    60  
    61  // stateObject represents an Ethereum account which is being modified.
    62  //
    63  // The usage pattern is as follows:
    64  // First you need to obtain a state object.
    65  // Account values can be accessed and modified through the object.
    66  type stateObject struct {
    67  	address  types.Address
    68  	data     account.StateAccount
    69  	original account.StateAccount
    70  	db       *IntraBlockState
    71  
    72  	// Write caches.
    73  	//trie Trie // storage trie, which becomes non-nil on first access
    74  	code Code // contract bytecode, which gets set when code is loaded
    75  
    76  	originStorage Storage // Storage cache of original entries to dedup rewrites
    77  	// blockOriginStorage keeps the values of storage items at the beginning of the block
    78  	// Used to make decision on whether to make a write to the
    79  	// database (value != origin) or not (value == origin)
    80  	blockOriginStorage Storage
    81  	dirtyStorage       Storage // Storage entries that need to be flushed to disk
    82  	fakeStorage        Storage // Fake storage which constructed by caller for debugging purpose.
    83  
    84  	// Cache flags.
    85  	// When an object is marked suicided it will be delete from the trie
    86  	// during the "update" phase of the state transition.
    87  	dirtyCode      bool // true if the code was updated
    88  	selfdestructed bool
    89  	deleted        bool // true if account was deleted during the lifetime of this object
    90  	created        bool // true if this object represents a newly created contract
    91  }
    92  
    93  // empty returns whether the account is considered empty.
    94  func (so *stateObject) empty() bool {
    95  	return so.data.Nonce == 0 && so.data.Balance.IsZero() && bytes.Equal(so.data.CodeHash[:], emptyCodeHash)
    96  }
    97  
    98  // newObject creates a state object.
    99  func newObject(db *IntraBlockState, address types.Address, data, original *account.StateAccount) *stateObject {
   100  	var so = stateObject{
   101  		db:                 db,
   102  		address:            address,
   103  		originStorage:      make(Storage),
   104  		blockOriginStorage: make(Storage),
   105  		dirtyStorage:       make(Storage),
   106  	}
   107  	so.data.Copy(data)
   108  	if !so.data.Initialised {
   109  		so.data.Balance.SetUint64(0)
   110  		so.data.Initialised = true
   111  	}
   112  	if so.data.CodeHash == (types.Hash{}) {
   113  		so.data.CodeHash = emptyCodeHashH
   114  	}
   115  	if so.data.Root == (types.Hash{}) {
   116  		// todo
   117  		//so.data.Root = trie.EmptyRoot
   118  	}
   119  	so.original.Copy(original)
   120  
   121  	return &so
   122  }
   123  
   124  // EncodeRLP implements rlp.Encoder.
   125  func (so *stateObject) EncodeRLP(w io.Writer) error {
   126  	return rlp.Encode(w, so.data)
   127  }
   128  
   129  // setError remembers the first non-nil error it is called with.
   130  func (so *stateObject) setError(err error) {
   131  	if so.db.savedErr == nil {
   132  		so.db.savedErr = err
   133  	}
   134  }
   135  
   136  func (so *stateObject) markSelfdestructed() {
   137  	so.selfdestructed = true
   138  }
   139  
   140  func (so *stateObject) touch() {
   141  	so.db.journal.append(touchChange{
   142  		account: &so.address,
   143  	})
   144  	if so.address == ripemd {
   145  		// Explicitly put it in the dirty-cache, which is otherwise generated from
   146  		// flattened journals.
   147  		so.db.journal.dirty(so.address)
   148  	}
   149  }
   150  
   151  // GetState returns a value from account storage.
   152  func (so *stateObject) GetState(key *types.Hash, out *uint256.Int) {
   153  	// If the fake storage is set, only lookup the state here(in the debugging mode)
   154  	if so.fakeStorage != nil {
   155  		*out = so.fakeStorage[*key]
   156  		return
   157  	}
   158  	value, dirty := so.dirtyStorage[*key]
   159  	if dirty {
   160  		*out = value
   161  		return
   162  	}
   163  	// Otherwise return the entry's original value
   164  	so.GetCommittedState(key, out)
   165  }
   166  
   167  // GetCommittedState retrieves a value from the committed account storage trie.
   168  func (so *stateObject) GetCommittedState(key *types.Hash, out *uint256.Int) {
   169  	// If the fake storage is set, only lookup the state here(in the debugging mode)
   170  	if so.fakeStorage != nil {
   171  		*out = so.fakeStorage[*key]
   172  		return
   173  	}
   174  	// If we have the original value cached, return that
   175  	{
   176  		value, cached := so.originStorage[*key]
   177  		if cached {
   178  			*out = value
   179  			return
   180  		}
   181  	}
   182  	if so.created {
   183  		out.Clear()
   184  		return
   185  	}
   186  
   187  	if so.db != nil && so.db.snap != nil && !so.db.snap.CanWrite() {
   188  		// Load from DB in case it is missing.
   189  		enc, err := so.db.snap.ReadAccountStorage(so.address, so.data.GetIncarnation(), key)
   190  		if err != nil {
   191  			so.setError(err)
   192  			out.Clear()
   193  			return
   194  		}
   195  		if enc != nil {
   196  			out.SetBytes(enc)
   197  		} else {
   198  			out.Clear()
   199  		}
   200  		//enc1, err1 := so.db.stateReader.ReadAccountStorage(so.address, so.data.GetIncarnation(), key)
   201  		//if !bytes.Equal(enc1, enc) {
   202  		//	fmt.Println(err1)
   203  		//}
   204  		so.originStorage[*key] = *out
   205  		so.blockOriginStorage[*key] = *out
   206  		return
   207  	}
   208  	// Load from DB in case it is missing.
   209  	enc, err := so.db.stateReader.ReadAccountStorage(so.address, so.data.GetIncarnation(), key)
   210  	if err != nil {
   211  		so.setError(err)
   212  		out.Clear()
   213  		return
   214  	}
   215  	if enc != nil {
   216  		if so.db.snap != nil && so.db.snap.CanWrite() {
   217  			so.db.snap.AddStorage(so.address, key, so.data.GetIncarnation(), enc)
   218  		}
   219  		out.SetBytes(enc)
   220  	} else {
   221  		out.Clear()
   222  	}
   223  	so.originStorage[*key] = *out
   224  	so.blockOriginStorage[*key] = *out
   225  }
   226  
   227  // SetState updates a value in account storage.
   228  func (so *stateObject) SetState(key *types.Hash, value uint256.Int) {
   229  	// If the fake storage is set, put the temporary state update here.
   230  	if so.fakeStorage != nil {
   231  		so.db.journal.append(fakeStorageChange{
   232  			account:  &so.address,
   233  			key:      *key,
   234  			prevalue: so.fakeStorage[*key],
   235  		})
   236  		so.fakeStorage[*key] = value
   237  		return
   238  	}
   239  	// If the new value is the same as old, don't set
   240  	var prev uint256.Int
   241  	so.GetState(key, &prev)
   242  	if prev == value {
   243  		return
   244  	}
   245  	// New value is different, update and journal the change
   246  	so.db.journal.append(storageChange{
   247  		account:  &so.address,
   248  		key:      *key,
   249  		prevalue: prev,
   250  	})
   251  	so.setState(key, value)
   252  }
   253  
   254  // SetStorage replaces the entire state storage with the given one.
   255  //
   256  // After this function is called, all original state will be ignored and state
   257  // lookup only happens in the fake state storage.
   258  //
   259  // Note this function should only be used for debugging purpose.
   260  func (so *stateObject) SetStorage(storage Storage) {
   261  	// Allocate fake storage if it's nil.
   262  	if so.fakeStorage == nil {
   263  		so.fakeStorage = make(Storage)
   264  	}
   265  	for key, value := range storage {
   266  		so.fakeStorage[key] = value
   267  	}
   268  	// Don't bother journal since this function should only be used for
   269  	// debugging and the `fake` storage won't be committed to database.
   270  }
   271  
   272  func (so *stateObject) setState(key *types.Hash, value uint256.Int) {
   273  	so.dirtyStorage[*key] = value
   274  }
   275  
   276  // updateTrie writes cached storage modifications into the object's storage trie.
   277  func (so *stateObject) updateTrie(stateWriter StateWriter) error {
   278  	for key, value := range so.dirtyStorage {
   279  		value := value
   280  		original := so.blockOriginStorage[key]
   281  		so.originStorage[key] = value
   282  		if err := stateWriter.WriteAccountStorage(so.address, so.data.GetIncarnation(), &key, &original, &value); err != nil {
   283  			return err
   284  		}
   285  	}
   286  	return nil
   287  }
   288  func (so *stateObject) printTrie() {
   289  	for key, value := range so.dirtyStorage {
   290  		fmt.Printf("WriteAccountStorage: %x,%x,%s\n", so.address, key, value.Hex())
   291  	}
   292  }
   293  
   294  // AddBalance adds amount to so's balance.
   295  // It is used to add funds to the destination account of a transfer.
   296  func (so *stateObject) AddBalance(amount *uint256.Int) {
   297  	// EIP161: We must check emptiness for the objects such that the account
   298  	// clearing (0,0,0 objects) can take effect.
   299  	if amount.IsZero() {
   300  		if so.empty() {
   301  			so.touch()
   302  		}
   303  
   304  		return
   305  	}
   306  
   307  	so.SetBalance(new(uint256.Int).Add(so.Balance(), amount))
   308  }
   309  
   310  // SubBalance removes amount from so's balance.
   311  // It is used to remove funds from the origin account of a transfer.
   312  func (so *stateObject) SubBalance(amount *uint256.Int) {
   313  	if amount.IsZero() {
   314  		return
   315  	}
   316  	so.SetBalance(new(uint256.Int).Sub(so.Balance(), amount))
   317  }
   318  
   319  func (so *stateObject) SetBalance(amount *uint256.Int) {
   320  	so.db.journal.append(balanceChange{
   321  		account: &so.address,
   322  		prev:    so.data.Balance,
   323  	})
   324  	so.setBalance(amount)
   325  }
   326  
   327  func (so *stateObject) setBalance(amount *uint256.Int) {
   328  	so.data.Balance.Set(amount)
   329  	so.data.Initialised = true
   330  }
   331  
   332  // Return the gas back to the origin. Used by the Virtual machine or Closures
   333  func (so *stateObject) ReturnGas(gas *big.Int) {}
   334  
   335  func (so *stateObject) setIncarnation(incarnation uint16) {
   336  	so.data.SetIncarnation(incarnation)
   337  }
   338  
   339  //
   340  // Attribute accessors
   341  //
   342  
   343  // Returns the address of the contract/account
   344  func (so *stateObject) Address() types.Address {
   345  	return so.address
   346  }
   347  
   348  // Code returns the contract code associated with this object, if any.
   349  func (so *stateObject) Code() []byte {
   350  	if so.code != nil {
   351  		return so.code
   352  	}
   353  	if bytes.Equal(so.CodeHash(), emptyCodeHash) {
   354  		return nil
   355  	}
   356  	code, err := so.db.stateReader.ReadAccountCode(so.Address(), so.data.Incarnation, types.BytesToHash(so.CodeHash()))
   357  	if err != nil {
   358  		so.setError(fmt.Errorf("can't load code hash %x: %w", so.CodeHash(), err))
   359  	}
   360  	so.code = code
   361  	return code
   362  }
   363  
   364  func (so *stateObject) SetCode(codeHash types.Hash, code []byte) {
   365  	prevcode := so.Code()
   366  	so.db.journal.append(codeChange{
   367  		account:  &so.address,
   368  		prevhash: so.data.CodeHash,
   369  		prevcode: prevcode,
   370  	})
   371  	so.setCode(codeHash, code)
   372  }
   373  
   374  func (so *stateObject) setCode(codeHash types.Hash, code []byte) {
   375  	so.code = code
   376  	so.data.CodeHash = codeHash
   377  	so.dirtyCode = true
   378  }
   379  
   380  func (so *stateObject) SetNonce(nonce uint64) {
   381  	so.db.journal.append(nonceChange{
   382  		account: &so.address,
   383  		prev:    so.data.Nonce,
   384  	})
   385  	so.setNonce(nonce)
   386  }
   387  
   388  func (so *stateObject) setNonce(nonce uint64) {
   389  	so.data.Nonce = nonce
   390  }
   391  
   392  func (so *stateObject) CodeHash() []byte {
   393  	return so.data.CodeHash[:]
   394  }
   395  
   396  func (so *stateObject) Balance() *uint256.Int {
   397  	return &so.data.Balance
   398  }
   399  
   400  func (so *stateObject) Nonce() uint64 {
   401  	return so.data.Nonce
   402  }
   403  
   404  // Never called, but must be present to allow stateObject to be used
   405  // as a vm.Account interface that also satisfies the vm.ContractRef
   406  // interface. Interfaces are awesome.
   407  func (so *stateObject) Value() *big.Int {
   408  	panic("Value on stateObject should never be called")
   409  }