Commit 8fa24ff0 authored by George Hotz's avatar George Hotz

add state object

parent d01b4d7b
package state
import (
"bytes"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
var emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
var emptyCodeHash = crypto.Keccak256(nil)
type Code []byte
func (c Code) String() string {
return string(c) //strings.Join(Disassemble(c), " ")
}
type Storage map[common.Hash]common.Hash
func (s Storage) String() (str string) {
for key, value := range s {
str += fmt.Sprintf("%X : %X\n", key, value)
}
return
}
func (s Storage) Copy() Storage {
cpy := make(Storage)
for key, value := range s {
cpy[key] = value
}
return cpy
}
// stateObject represents an Ethereum account which is being modified.
//
// The usage pattern is as follows:
// First you need to obtain a state object.
// Account values can be accessed and modified through the object.
// Finally, call CommitTrie to write the modified storage trie into a database.
type stateObject struct {
address common.Address
addrHash common.Hash // hash of ethereum address of the account
data Account
db *StateDB
// DB error.
// State objects are used by the consensus core and VM which are
// unable to deal with database-level errors. Any error that occurs
// during a database read is memoized here and will eventually be returned
// by StateDB.Commit.
dbErr error
// Write caches.
//trie Trie // storage trie, which becomes non-nil on first access
code Code // contract bytecode, which gets set when code is loaded
originStorage Storage // Storage cache of original entries to dedup rewrites, reset for every transaction
pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution
fakeStorage Storage // Fake storage which constructed by caller for debugging purpose.
// Cache flags.
// When an object is marked suicided it will be delete from the trie
// during the "update" phase of the state transition.
dirtyCode bool // true if the code was updated
suicided bool
deleted bool
}
// empty returns whether the account is considered empty.
func (s *stateObject) empty() bool {
return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
}
// Account is the Ethereum consensus representation of accounts.
// These objects are stored in the main account trie.
type Account struct {
Nonce uint64
Balance *big.Int
Root common.Hash // merkle root of the storage trie
CodeHash []byte
}
func (s *stateObject) Nonce() uint64 {
return s.data.Nonce
}
// Returns the address of the contract/account
func (s *stateObject) Address() common.Address {
return s.address
}
// newObject creates a state object.
func newObject(db *StateDB, address common.Address, data Account) *stateObject {
if data.Balance == nil {
data.Balance = new(big.Int)
}
if data.CodeHash == nil {
data.CodeHash = emptyCodeHash
}
if data.Root == (common.Hash{}) {
data.Root = emptyRoot
}
return &stateObject{
db: db,
address: address,
addrHash: crypto.Keccak256Hash(address[:]),
data: data,
originStorage: make(Storage),
pendingStorage: make(Storage),
dirtyStorage: make(Storage),
}
}
......@@ -6,10 +6,13 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
type StateDB struct {
// TODO: write stub StateDB
// This map holds 'live' objects, which will get modified while processing a state transition.
stateObjects map[common.Address]*stateObject
}
// AddAddressToAccessList adds the given address to the access list
......@@ -48,15 +51,18 @@ func (s *StateDB) GetLogs(hash common.Hash, blockHash common.Hash) []*types.Log
// AddPreimage records a SHA3 preimage seen by the VM.
func (s *StateDB) AddPreimage(hash common.Hash, preimage []byte) {
fmt.Println("AddPreimage", hash)
}
// AddRefund adds gas to the refund counter
func (s *StateDB) AddRefund(gas uint64) {
fmt.Println("AddRefund", gas)
}
// SubRefund removes gas from the refund counter.
// This method will panic if the refund counter goes below zero
func (s *StateDB) SubRefund(gas uint64) {
fmt.Println("SubRefund", gas)
}
// AddSlotToAccessList adds the given (address, slot)-tuple to the access list
......@@ -133,7 +139,14 @@ func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
func (s *StateDB) GetNonce(addr common.Address) uint64 {
fmt.Println("GetNonce", addr)
return 2122
//return 2122
stateObject := s.getStateObject(addr)
if stateObject != nil {
return stateObject.Nonce()
}
return 0
}
// GetRefund returns the current value of the refund counter.
......@@ -184,3 +197,51 @@ func (s *StateDB) Snapshot() int {
// used when the EVM emits new state logs.
func (s *StateDB) Prepare(thash common.Hash, ti int) {
}
// lower level
func (s *StateDB) setStateObject(object *stateObject) {
s.stateObjects[object.Address()] = object
}
// getStateObject retrieves a state object given by the address, returning nil if
// the object is not found or was deleted in this execution context. If you need
// to differentiate between non-existent/just-deleted, use getDeletedStateObject.
func (s *StateDB) getStateObject(addr common.Address) *stateObject {
if obj := s.getDeletedStateObject(addr); obj != nil && !obj.deleted {
return obj
}
return nil
}
// getDeletedStateObject is similar to getStateObject, but instead of returning
// nil for a deleted state object, it returns the actual object with the deleted
// flag set. This is needed by the state journal to revert to the correct s-
// destructed object instead of wiping all knowledge about the state object.
func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
// Prefer live objects if any is available
if obj := s.stateObjects[addr]; obj != nil {
return obj
}
fmt.Println("getDeletedStateObject:", addr)
// If snapshot unavailable or reading from it failed, load from the database
/*enc, err := s.trie.TryGet(addr.Bytes())
if err != nil {
fmt.Printf("getDeleteStateObject (%x) error: %v\n", addr.Bytes(), err)
return nil
}*/
enc := []byte("12")
if len(enc) == 0 {
return nil
}
data := new(Account)
if err := rlp.DecodeBytes(enc, data); err != nil {
log.Error("Failed to decode state object", "addr", addr, "err", err)
return nil
}
// Insert into the live set
obj := newObject(s, addr, *data)
s.setStateObject(obj)
return obj
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment