diff --git a/ethchain/filter.go b/ethchain/filter.go index 4f3160b901..c4c403cf77 100644 --- a/ethchain/filter.go +++ b/ethchain/filter.go @@ -6,8 +6,13 @@ import ( "github.com/ethereum/eth-go/ethstate" "github.com/ethereum/eth-go/ethutil" + "gopkg.in/qml.v1" ) +type data struct { + id, address []byte +} + // Filtering interface type Filter struct { eth EthManager @@ -16,6 +21,8 @@ type Filter struct { skip int from, to [][]byte max int + + altered []data } // Create a new filter which uses a bloom filter on blocks to figure out whether a particular block @@ -61,9 +68,19 @@ func NewFilterFromMap(object map[string]interface{}, eth EthManager) *Filter { filter.SetSkip(object["skip"].(int)) } + if object["altered"] != nil { + filter.altered = makeAltered(object["altered"]) + } + + fmt.Println("ALTERED", filter.altered) + return filter } +func (self *Filter) AddAltered(id, address []byte) { + self.altered = append(self.altered, data{id, address}) +} + // Set the earliest and latest block for filtering. // -1 = latest block (i.e., the current block) // hash = particular hash from-to @@ -158,17 +175,19 @@ func (self *Filter) Find() []*ethstate.Message { return messages } +func includes(addresses [][]byte, a []byte) (found bool) { + for _, addr := range addresses { + if bytes.Compare(addr, a) == 0 { + return true + } + } + + return +} + func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message { var messages []*ethstate.Message - includes := func(addresses [][]byte, a []byte) (found bool) { - for _, addr := range addresses { - if bytes.Compare(addr, a) == 0 { - return true - } - } - return - } // Filter the messages for interesting stuff for _, message := range msgs { if len(self.to) > 0 && !includes(self.to, message.To) { @@ -179,6 +198,28 @@ func (self *Filter) FilterMessages(msgs []*ethstate.Message) []*ethstate.Message continue } + var match bool + if len(self.altered) == 0 { + match = true + } + + for _, item := range self.altered { + if len(item.id) > 0 && bytes.Compare(message.To, item.id) != 0 { + continue + } + + if len(item.address) > 0 && !includes(message.ChangedAddresses, item.address) { + continue + } + + match = true + break + } + + if !match { + continue + } + messages = append(messages, message) } @@ -219,3 +260,47 @@ func (self *Filter) bloomFilter(block *Block) bool { return fromIncluded && toIncluded } + +// Conversion methodn +func mapToData(m map[string]interface{}) (d data) { + if str, ok := m["id"].(string); ok { + d.id = ethutil.Hex2Bytes(str) + } + + if str, ok := m["at"].(string); ok { + d.address = ethutil.Hex2Bytes(str) + } + + return +} + +// data can come in in the following formats: +// ["aabbccdd", {id: "ccddee", at: "11223344"}], "aabbcc", {id: "ccddee", at: "1122"} +func makeAltered(v interface{}) (d []data) { + if str, ok := v.(string); ok { + d = append(d, data{ethutil.Hex2Bytes(str), nil}) + } else if obj, ok := v.(map[string]interface{}); ok { + d = append(d, mapToData(obj)) + } else if slice, ok := v.([]interface{}); ok { + for _, item := range slice { + d = append(d, makeAltered(item)...) + } + } else if qList, ok := v.(*qml.List); ok { + var s []interface{} + qList.Convert(&s) + + fmt.Println(s) + + d = makeAltered(s) + } else if qMap, ok := v.(*qml.Map); ok { + var m map[string]interface{} + qMap.Convert(&m) + fmt.Println(m) + + d = makeAltered(m) + } else { + panic(fmt.Sprintf("makeAltered err (unknown conversion): %T\n", v)) + } + + return +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 1f47a2e0b8..08bd22d299 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -373,11 +373,17 @@ func (sm *StateManager) Stop() { func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter { bloomf := NewBloomFilter(nil) - for addr, stateObject := range state.Manifest().ObjectChanges { - // Set the bloom filter's bin - bloomf.Set([]byte(addr)) + /* + for addr, stateObject := range state.Manifest().ObjectChanges { + // Set the bloom filter's bin + bloomf.Set([]byte(addr)) - sm.Ethereum.Reactor().Post("object:"+addr, stateObject) + sm.Ethereum.Reactor().Post("object:"+addr, stateObject) + } + */ + for _, msg := range state.Manifest().Messages { + bloomf.Set(msg.To) + bloomf.Set(msg.From) } sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 489ff2b6a2..f8452cdb31 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -225,7 +225,7 @@ func (self *StateTransition) TransitionState() (err error) { // script section for the state object. self.data = nil - code, err := self.Eval(receiver.Init(), receiver, "init") + code, err := self.Eval(msg, receiver.Init(), receiver, "init") if err != nil { self.state.Set(snapshot) @@ -236,7 +236,7 @@ func (self *StateTransition) TransitionState() (err error) { msg.Output = code } else { if len(receiver.Code) > 0 { - ret, err := self.Eval(receiver.Code, receiver, "code") + ret, err := self.Eval(msg, receiver.Code, receiver, "code") if err != nil { self.state.Set(snapshot) @@ -263,12 +263,12 @@ func (self *StateTransition) transferValue(sender, receiver *ethstate.StateObjec return nil } -func (self *StateTransition) Eval(script []byte, context *ethstate.StateObject, typ string) (ret []byte, err error) { +func (self *StateTransition) Eval(msg *ethstate.Message, script []byte, context *ethstate.StateObject, typ string) (ret []byte, err error) { var ( transactor = self.Sender() state = self.state env = NewEnv(state, self.tx, self.block) - callerClosure = ethvm.NewClosure(transactor, context, script, self.gas, self.gasPrice) + callerClosure = ethvm.NewClosure(msg, transactor, context, script, self.gas, self.gasPrice) ) vm := ethvm.New(env) diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go index a9da66ab8b..8a81734cd7 100644 --- a/ethpipe/pipe.go +++ b/ethpipe/pipe.go @@ -61,7 +61,7 @@ func (self *Pipe) ExecuteObject(object *Object, data []byte, value, gas, price * vm := ethvm.New(NewEnv(self.Vm.State, block, value.BigInt(), initiator.Address())) - closure := ethvm.NewClosure(initiator, stateObject, object.Code, gas.BigInt(), price.BigInt()) + closure := ethvm.NewClosure(ðstate.Message{}, initiator, stateObject, object.Code, gas.BigInt(), price.BigInt()) ret, _, err := closure.Call(vm, data) return ret, err diff --git a/ethstate/manifest.go b/ethstate/manifest.go index 88ce673b9a..604f77b892 100644 --- a/ethstate/manifest.go +++ b/ethstate/manifest.go @@ -10,38 +10,18 @@ import ( // 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 - Messages Messages } func NewManifest() *Manifest { - m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} + m := &Manifest{} 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 + m.Messages = nil } func (self *Manifest) AddMessage(msg *Message) *Message { @@ -61,6 +41,12 @@ type Message struct { Coinbase []byte Block []byte Number *big.Int + + ChangedAddresses [][]byte +} + +func (self *Message) AddStorageChange(addr []byte) { + self.ChangedAddresses = append(self.ChangedAddresses, addr) } func (self *Message) String() string { diff --git a/ethstate/state.go b/ethstate/state.go index 19210916ee..cf060e7950 100644 --- a/ethstate/state.go +++ b/ethstate/state.go @@ -60,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 diff --git a/ethvm/closure.go b/ethvm/closure.go index f9be952d4e..54bfd05f4f 100644 --- a/ethvm/closure.go +++ b/ethvm/closure.go @@ -18,9 +18,10 @@ type ClosureRef interface { // Basic inline closure object which implement the 'closure' interface type Closure struct { - caller ClosureRef - object *ethstate.StateObject - Code []byte + caller ClosureRef + object *ethstate.StateObject + Code []byte + message *ethstate.Message Gas, UsedGas, Price *big.Int @@ -28,8 +29,8 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(caller ClosureRef, object *ethstate.StateObject, code []byte, gas, price *big.Int) *Closure { - c := &Closure{caller: caller, object: object, Code: code, Args: nil} +func NewClosure(msg *ethstate.Message, caller ClosureRef, object *ethstate.StateObject, code []byte, gas, price *big.Int) *Closure { + c := &Closure{message: msg, caller: caller, object: object, Code: code, Args: nil} // Gas should be a pointer so it can safely be reduced through the run // This pointer will be off the state transition diff --git a/ethvm/vm.go b/ethvm/vm.go index a0d4db5913..7896978656 100644 --- a/ethvm/vm.go +++ b/ethvm/vm.go @@ -645,8 +645,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { val, loc := stack.Popn() closure.SetStorage(loc, ethutil.NewValue(val)) - // Add the change to manifest - self.env.State().Manifest().AddStorageChange(closure.Object(), loc.Bytes(), val) + closure.message.AddStorageChange(loc.Bytes()) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: @@ -719,7 +718,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { closure.UseGas(closure.Gas) // Create the closure - c := NewClosure(closure, contract, initCode, gas, closure.Price) + c := NewClosure(msg, closure, contract, initCode, gas, closure.Price) // Call the closure and set the return value as // main script. contract.Code, _, err = c.Call(self, nil) @@ -783,7 +782,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { stateObject.AddAmount(value) // Create a new callable closure - c := NewClosure(closure, stateObject, stateObject.Code, gas, closure.Price) + c := NewClosure(msg, closure, stateObject, stateObject.Code, gas, closure.Price) // Executer the closure and get the return value (if any) ret, _, err := c.Call(self, args) if err != nil {