diff options
Diffstat (limited to 'ethstate')
-rw-r--r-- | ethstate/dump.go | 47 | ||||
-rw-r--r-- | ethstate/manifest.go | 55 | ||||
-rw-r--r-- | ethstate/state.go | 56 | ||||
-rw-r--r-- | ethstate/state_object.go | 63 | ||||
-rw-r--r-- | ethstate/state_test.go | 5 |
5 files changed, 137 insertions, 89 deletions
diff --git a/ethstate/dump.go b/ethstate/dump.go new file mode 100644 index 000000000..be60a05fc --- /dev/null +++ b/ethstate/dump.go @@ -0,0 +1,47 @@ +package ethstate + +import ( + "encoding/json" + "fmt" + + "github.com/ethereum/eth-go/ethutil" +) + +type Account struct { + Balance string `json:"balance"` + Nonce uint64 `json:"nonce"` + CodeHash string `json:"codeHash"` + Storage map[string]string `json:"storage"` +} + +type World struct { + Root string `json:"root"` + Accounts map[string]Account `json:"accounts"` +} + +func (self *State) Dump() []byte { + world := World{ + Root: ethutil.Bytes2Hex(self.Trie.Root.([]byte)), + Accounts: make(map[string]Account), + } + + self.Trie.NewIterator().Each(func(key string, value *ethutil.Value) { + stateObject := NewStateObjectFromBytes([]byte(key), value.Bytes()) + + account := Account{Balance: stateObject.Balance.String(), Nonce: stateObject.Nonce, CodeHash: ethutil.Bytes2Hex(stateObject.CodeHash)} + account.Storage = make(map[string]string) + + stateObject.EachStorage(func(key string, value *ethutil.Value) { + value.Decode() + account.Storage[ethutil.Bytes2Hex([]byte(key))] = ethutil.Bytes2Hex(value.Bytes()) + }) + world.Accounts[ethutil.Bytes2Hex([]byte(key))] = account + }) + + json, err := json.MarshalIndent(world, "", " ") + if err != nil { + fmt.Println("dump err", err) + } + + return json +} diff --git a/ethstate/manifest.go b/ethstate/manifest.go new file mode 100644 index 000000000..945de22ab --- /dev/null +++ b/ethstate/manifest.go @@ -0,0 +1,55 @@ +package ethstate + +import ( + "fmt" + "math/big" +) + +// Object manifest +// +// The object manifest is used to keep changes to the state so we can keep track of the changes +// that occurred during a state transitioning phase. +type Manifest struct { + Messages Messages +} + +func NewManifest() *Manifest { + m := &Manifest{} + m.Reset() + + return m +} + +func (m *Manifest) Reset() { + m.Messages = nil +} + +func (self *Manifest) AddMessage(msg *Message) *Message { + self.Messages = append(self.Messages, msg) + + return msg +} + +type Messages []*Message +type Message struct { + To, From []byte + Input []byte + Output []byte + Path int + Origin []byte + Timestamp int64 + Coinbase []byte + Block []byte + Number *big.Int + Value *big.Int + + ChangedAddresses [][]byte +} + +func (self *Message) AddStorageChange(addr []byte) { + self.ChangedAddresses = append(self.ChangedAddresses, addr) +} + +func (self *Message) String() string { + return fmt.Sprintf("Message{to: %x from: %x input: %x output: %x origin: %x coinbase: %x block: %x number: %v timestamp: %d path: %d value: %v", self.To, self.From, self.Input, self.Output, self.Origin, self.Coinbase, self.Block, self.Number, self.Timestamp, self.Path, self.Value) +} diff --git a/ethstate/state.go b/ethstate/state.go index 51b585d4d..cf060e795 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -1,11 +1,12 @@ package ethstate import ( + "math/big" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" - "math/big" ) var statelogger = ethlog.NewLogger("STATE") @@ -25,7 +26,7 @@ type State struct { } // Create a new state from a given trie -func NewState(trie *ethtrie.Trie) *State { +func New(trie *ethtrie.Trie) *State { return &State{Trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } @@ -33,7 +34,7 @@ func NewState(trie *ethtrie.Trie) *State { func (self *State) GetBalance(addr []byte) *big.Int { stateObject := self.GetStateObject(addr) if stateObject != nil { - return stateObject.Amount + return stateObject.Balance } return ethutil.Big0 @@ -59,8 +60,6 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Code), stateObject.Code) self.Trie.Update(string(addr), string(stateObject.RlpEncode())) - - self.manifest.AddObjectChange(stateObject) } // Delete the given state object and delete it from the state trie @@ -127,7 +126,7 @@ func (s *State) Cmp(other *State) bool { func (self *State) Copy() *State { if self.Trie != nil { - state := NewState(self.Trie.Copy()) + state := New(self.Trie.Copy()) for k, stateObject := range self.stateObjects { state.stateObjects[k] = stateObject.Copy() } @@ -210,50 +209,13 @@ func (self *State) Update() { } } -// Debug stuff -func (self *State) CreateOutputForDiff() { - for _, stateObject := range self.stateObjects { - stateObject.CreateOutputForDiff() - } -} - func (self *State) Manifest() *Manifest { return self.manifest } -// Object manifest -// -// The object manifest is used to keep changes to the state so we can keep track of the changes -// that occurred during a state transitioning phase. -type Manifest struct { - // XXX These will be handy in the future. Not important for now. - objectAddresses map[string]bool - storageAddresses map[string]map[string]bool - - ObjectChanges map[string]*StateObject - StorageChanges map[string]map[string]*big.Int -} - -func NewManifest() *Manifest { - m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} - m.Reset() - - return m -} - -func (m *Manifest) Reset() { - m.ObjectChanges = make(map[string]*StateObject) - m.StorageChanges = make(map[string]map[string]*big.Int) -} - -func (m *Manifest) AddObjectChange(stateObject *StateObject) { - m.ObjectChanges[string(stateObject.Address())] = stateObject -} - -func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { - if m.StorageChanges[string(stateObject.Address())] == nil { - m.StorageChanges[string(stateObject.Address())] = make(map[string]*big.Int) +// Debug stuff +func (self *State) CreateOutputForDiff() { + for _, stateObject := range self.stateObjects { + stateObject.CreateOutputForDiff() } - - m.StorageChanges[string(stateObject.Address())][string(storageAddr)] = storage } diff --git a/ethstate/state_object.go b/ethstate/state_object.go index ab14b8604..67d09edd8 100644 --- a/ethstate/state_object.go +++ b/ethstate/state_object.go @@ -2,10 +2,11 @@ package ethstate import ( "fmt" + "math/big" + "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" - "math/big" ) type Code []byte @@ -30,7 +31,7 @@ type StateObject struct { // Address of the object address []byte // Shared attributes - Amount *big.Int + Balance *big.Int CodeHash []byte Nonce uint64 // Contract related attributes @@ -56,40 +57,22 @@ func (self *StateObject) Reset() { self.State.Reset() } -/* -// Converts an transaction in to a state object -func MakeContract(tx *Transaction, state *State) *StateObject { - // Create contract if there's no recipient - if tx.IsContract() { - addr := tx.CreationAddress() - - contract := state.NewStateObject(addr) - contract.initCode = tx.Data - contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) - - return contract - } - - return nil -} -*/ - func NewStateObject(addr []byte) *StateObject { // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. address := ethutil.Address(addr) - object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} - object.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) + object := &StateObject{address: address, Balance: new(big.Int), gasPool: new(big.Int)} + object.State = New(ethtrie.New(ethutil.Config.Db, "")) object.storage = make(Storage) object.gasPool = new(big.Int) return object } -func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { +func NewContract(address []byte, balance *big.Int, root []byte) *StateObject { contract := NewStateObject(address) - contract.Amount = Amount - contract.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root))) + contract.Balance = balance + contract.State = New(ethtrie.New(ethutil.Config.Db, string(root))) return contract } @@ -103,7 +86,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject { func (self *StateObject) MarkForDeletion() { self.remove = true - statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) + statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Balance) } func (c *StateObject) GetAddr(addr []byte) *ethutil.Value { @@ -190,19 +173,19 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { } func (c *StateObject) AddAmount(amount *big.Int) { - c.SetAmount(new(big.Int).Add(c.Amount, amount)) + c.SetBalance(new(big.Int).Add(c.Balance, amount)) - statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Balance, amount) } func (c *StateObject) SubAmount(amount *big.Int) { - c.SetAmount(new(big.Int).Sub(c.Amount, amount)) + c.SetBalance(new(big.Int).Sub(c.Balance, amount)) - statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Balance, amount) } -func (c *StateObject) SetAmount(amount *big.Int) { - c.Amount = amount +func (c *StateObject) SetBalance(amount *big.Int) { + c.Balance = amount } // @@ -213,8 +196,8 @@ func (c *StateObject) SetAmount(amount *big.Int) { func (c *StateObject) ReturnGas(gas, price *big.Int) {} func (c *StateObject) ConvertGas(gas, price *big.Int) error { total := new(big.Int).Mul(gas, price) - if total.Cmp(c.Amount) > 0 { - return fmt.Errorf("insufficient amount: %v, %v", c.Amount, total) + if total.Cmp(c.Balance) > 0 { + return fmt.Errorf("insufficient amount: %v, %v", c.Balance, total) } c.SubAmount(total) @@ -247,12 +230,12 @@ func (self *StateObject) RefundGas(gas, price *big.Int) { rGas := new(big.Int).Set(gas) rGas.Mul(rGas, price) - self.Amount.Sub(self.Amount, rGas) + self.Balance.Sub(self.Balance, rGas) } func (self *StateObject) Copy() *StateObject { stateObject := NewStateObject(self.Address()) - stateObject.Amount.Set(self.Amount) + stateObject.Balance.Set(self.Balance) stateObject.CodeHash = ethutil.CopyBytes(self.CodeHash) stateObject.Nonce = self.Nonce if self.State != nil { @@ -290,7 +273,7 @@ func (c *StateObject) Init() Code { // Debug stuff func (self *StateObject) CreateOutputForDiff() { - fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.Amount.Bytes(), self.Nonce) + fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.Balance.Bytes(), self.Nonce) self.EachStorage(func(addr string, value *ethutil.Value) { fmt.Printf("%x %x\n", addr, value.Bytes()) }) @@ -309,15 +292,15 @@ func (c *StateObject) RlpEncode() []byte { root = "" } - return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethcrypto.Sha3Bin(c.Code)}) + return ethutil.Encode([]interface{}{c.Nonce, c.Balance, root, ethcrypto.Sha3Bin(c.Code)}) } func (c *StateObject) RlpDecode(data []byte) { decoder := ethutil.NewValueFromBytes(data) c.Nonce = decoder.Get(0).Uint() - c.Amount = decoder.Get(1).BigInt() - c.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + c.Balance = decoder.Get(1).BigInt() + c.State = New(ethtrie.New(ethutil.Config.Db, decoder.Get(2).Interface())) c.storage = make(map[string]*ethutil.Value) c.gasPool = new(big.Int) diff --git a/ethstate/state_test.go b/ethstate/state_test.go index cd13e80bc..00c9de9d6 100644 --- a/ethstate/state_test.go +++ b/ethstate/state_test.go @@ -1,10 +1,11 @@ package ethstate import ( + "testing" + "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" - "testing" ) var ZeroHash256 = make([]byte, 32) @@ -14,7 +15,7 @@ func TestSnapshot(t *testing.T) { ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") ethutil.Config.Db = db - state := NewState(ethtrie.NewTrie(db, "")) + state := New(ethtrie.New(db, "")) stateObject := state.GetOrNewStateObject([]byte("aa")) |