From 21724f7ef960f0f2df0d2b0f3cccfd030a4aaee8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 30 Apr 2014 14:43:32 +0200 Subject: [PATCH] Added manifest changes and changed closures --- ethchain/closure.go | 17 +++------- ethchain/state_manager.go | 67 ++++++++++++++++++++++++++++----------- ethchain/vm.go | 7 ++-- ethminer/miner.go | 1 - 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/ethchain/closure.go b/ethchain/closure.go index 57abaa91e..7e911ad99 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -7,13 +7,6 @@ import ( "math/big" ) -type Callee interface { -} - -type Reference interface { - Callee -} - type ClosureRef interface { ReturnGas(*big.Int, *big.Int, *State) Address() []byte @@ -24,8 +17,8 @@ type ClosureRef interface { // Basic inline closure object which implement the 'closure' interface type Closure struct { - callee ClosureRef - object ClosureRef + callee *StateObject + object *StateObject Script []byte State *State @@ -37,7 +30,7 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee, object ClosureRef, script []byte, state *State, gas, price, val *big.Int) *Closure { +func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price, val *big.Int) *Closure { c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} // In most cases gas, price and value are pointers to transaction objects @@ -108,11 +101,11 @@ func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { c.Gas.Add(c.Gas, gas) } -func (c *Closure) Object() ClosureRef { +func (c *Closure) Object() *StateObject { return c.object } -func (c *Closure) Callee() ClosureRef { +func (c *Closure) Callee() *StateObject { return c.callee } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 70d4155c3..072fabc0e 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -51,9 +51,7 @@ type StateManager struct { // results compState *State - // It's generally know that a map is faster for small lookups than arrays - // we'll eventually have to make a decision if the map grows too large - watchedAddresses map[string]bool + manifest *Manifest } func NewStateManager(ethereum EthManager) *StateManager { @@ -64,7 +62,7 @@ func NewStateManager(ethereum EthManager) *StateManager { Ethereum: ethereum, stateObjectCache: NewStateObjectCache(), bc: ethereum.BlockChain(), - watchedAddresses: make(map[string]bool), + manifest: NewManifest(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() return sm @@ -112,7 +110,6 @@ func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { - fmt.Printf("Processing Tx: %x\n", tx.Hash()) // If there's no recipient, it's a contract // Check if this is a contract creation traction and if so // create a contract of this tx. @@ -122,7 +119,6 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { contract := sm.MakeContract(tx) if contract != nil { sm.EvalScript(contract.Init(), contract, tx, block) - fmt.Printf("state root of contract %x\n", contract.State().Root()) } else { ethutil.Config.Log.Infoln("[STATE] Unable to create contract") } @@ -214,6 +210,10 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) + + sm.notifyChanges() + + sm.manifest.Reset() } } else { fmt.Println("total diff failed") @@ -337,22 +337,53 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans // Update the account (refunds) sm.procState.UpdateStateObject(account) - sm.Changed(account) + sm.manifest.AddObjectChange(account) + sm.procState.UpdateStateObject(object) - sm.Changed(object) + sm.manifest.AddObjectChange(object) } -// Watch a specific address -func (sm *StateManager) Watch(addr []byte) { - if !sm.watchedAddresses[string(addr)] { - sm.watchedAddresses[string(addr)] = true +func (sm *StateManager) notifyChanges() { + for addr, stateObject := range sm.manifest.objectChanges { + sm.Ethereum.Reactor().Post("object:"+addr, stateObject) + } + + for stateObjectAddr, mappedObjects := range sm.manifest.storageChanges { + for addr, value := range mappedObjects { + sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, value.String()) + } } } -// The following objects are used when changing a value and using the "watched" attribute -// to determine whether the reactor should be used to notify any subscribers on the address -func (sm *StateManager) Changed(stateObject *StateObject) { - if sm.watchedAddresses[string(stateObject.Address())] { - sm.Ethereum.Reactor().Post("addressChanged", stateObject) - } +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) + } + + m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage } diff --git a/ethchain/vm.go b/ethchain/vm.go index b983e88ff..0a3690c41 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -411,6 +411,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(2) val, loc := stack.Popn() closure.SetMem(loc, ethutil.NewValue(val)) + + // Add the change to manifest + vm.stateManager.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) case oJUMP: require(1) pc = stack.Pop() @@ -492,7 +495,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } closure.Gas.Sub(closure.Gas, gas) // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price, value) + closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price, value) // Executer the closure and get the return value (if any) ret, err := closure.Call(vm, args, hook) if err != nil { @@ -502,7 +505,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { stack.Push(ethutil.BigTrue) // Notify of the changes - vm.stateManager.Changed(contract) + vm.stateManager.manifest.AddObjectChange(contract) } mem.Set(retOffset.Int64(), retSize.Int64(), ret) diff --git a/ethminer/miner.go b/ethminer/miner.go index c93267161..3796c873e 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -2,7 +2,6 @@ package ethminer import ( "bytes" - "fmt" "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire"