event listeners take EventData, not interface{}; EventData type assertions

This commit is contained in:
Jae Kwon
2015-08-11 12:46:33 -07:00
parent b37ff75f7a
commit ffcc657be6
16 changed files with 62 additions and 73 deletions

View File

@ -181,7 +181,7 @@ func (c *Crawler) readLoop(node *Node) {
} }
func (c *Crawler) consumeMessage(eventMsg ctypes.ResultEvent, node *Node) error { func (c *Crawler) consumeMessage(eventMsg ctypes.ResultEvent, node *Node) error {
block := eventMsg.Data.(*types.Block) block := eventMsg.Data.(*types.EventDataNewBlock).Block
node.LastSeen = time.Now() node.LastSeen = time.Now()
node.BlockHeight = block.Height node.BlockHeight = block.Height
node.BlockHistory[block.Height] = node.LastSeen node.BlockHistory[block.Height] = node.LastSeen

View File

@ -30,7 +30,7 @@ type eventInfo struct {
} }
// Cache an event to be fired upon finality. // Cache an event to be fired upon finality.
func (evc *EventCache) FireEvent(event string, data interface{}) { func (evc *EventCache) FireEvent(event string, data types.EventData) {
// append to list // append to list
evc.events = append(evc.events, eventInfo{event, data}) evc.events = append(evc.events, eventInfo{event, data})
} }

View File

@ -4,6 +4,7 @@ import (
"sync" "sync"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/types"
) )
// reactors and other modules should export // reactors and other modules should export
@ -14,7 +15,7 @@ type Eventable interface {
// an event switch or cache implements fireable // an event switch or cache implements fireable
type Fireable interface { type Fireable interface {
FireEvent(event string, msg interface{}) FireEvent(event string, data types.EventData)
} }
type EventSwitch struct { type EventSwitch struct {
@ -108,7 +109,7 @@ func (evsw *EventSwitch) RemoveListenerForEvent(event string, listenerId string)
} }
} }
func (evsw *EventSwitch) FireEvent(event string, msg interface{}) { func (evsw *EventSwitch) FireEvent(event string, data types.EventData) {
// Get the eventCell // Get the eventCell
evsw.mtx.RLock() evsw.mtx.RLock()
eventCell := evsw.eventCells[event] eventCell := evsw.eventCells[event]
@ -119,7 +120,7 @@ func (evsw *EventSwitch) FireEvent(event string, msg interface{}) {
} }
// Fire event for all listeners in eventCell // Fire event for all listeners in eventCell
eventCell.FireEvent(msg) eventCell.FireEvent(data)
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -150,17 +151,17 @@ func (cell *eventCell) RemoveListener(listenerId string) int {
return numListeners return numListeners
} }
func (cell *eventCell) FireEvent(msg interface{}) { func (cell *eventCell) FireEvent(data types.EventData) {
cell.mtx.RLock() cell.mtx.RLock()
for _, listener := range cell.listeners { for _, listener := range cell.listeners {
listener(msg) listener(data)
} }
cell.mtx.RUnlock() cell.mtx.RUnlock()
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
type eventCallback func(msg interface{}) type eventCallback func(data types.EventData)
type eventListener struct { type eventListener struct {
id string id string

View File

@ -16,6 +16,7 @@ import (
"github.com/tendermint/tendermint/events" "github.com/tendermint/tendermint/events"
ctypes "github.com/tendermint/tendermint/rpc/core/types" ctypes "github.com/tendermint/tendermint/rpc/core/types"
. "github.com/tendermint/tendermint/rpc/types" . "github.com/tendermint/tendermint/rpc/types"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/wire" "github.com/tendermint/tendermint/wire"
) )
@ -54,22 +55,22 @@ func NewRPCFunc(f interface{}, args []string) *RPCFunc {
func funcArgTypes(f interface{}) []reflect.Type { func funcArgTypes(f interface{}) []reflect.Type {
t := reflect.TypeOf(f) t := reflect.TypeOf(f)
n := t.NumIn() n := t.NumIn()
types := make([]reflect.Type, n) typez := make([]reflect.Type, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
types[i] = t.In(i) typez[i] = t.In(i)
} }
return types return typez
} }
// return a function's return types // return a function's return types
func funcReturnTypes(f interface{}) []reflect.Type { func funcReturnTypes(f interface{}) []reflect.Type {
t := reflect.TypeOf(f) t := reflect.TypeOf(f)
n := t.NumOut() n := t.NumOut()
types := make([]reflect.Type, n) typez := make([]reflect.Type, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
types[i] = t.Out(i) typez[i] = t.Out(i)
} }
return types return typez
} }
// function introspection // function introspection
@ -337,7 +338,7 @@ func (wsc *WSConnection) readRoutine() {
continue continue
} else { } else {
log.Notice("Subscribe to event", "id", wsc.id, "event", event) log.Notice("Subscribe to event", "id", wsc.id, "event", event)
wsc.evsw.AddListenerForEvent(wsc.id, event, func(msg interface{}) { wsc.evsw.AddListenerForEvent(wsc.id, event, func(msg types.EventData) {
// NOTE: RPCResponses of subscribed events have id suffix "#event" // NOTE: RPCResponses of subscribed events have id suffix "#event"
wsc.writeRPCResponse(NewRPCResponse(request.Id+"#event", ctypes.ResultEvent{event, msg}, "")) wsc.writeRPCResponse(NewRPCResponse(request.Id+"#event", ctypes.ResultEvent{event, msg}, ""))
}) })

View File

@ -82,7 +82,8 @@ func waitForEvent(t *testing.T, con *websocket.Conn, eventid string, dieOnTimeou
errCh <- err errCh <- err
break break
} }
if response.Result.(*ctypes.ResultEvent).Event == eventid { event, ok := response.Result.(*ctypes.ResultEvent)
if ok && event.Event == eventid {
goodCh <- p goodCh <- p
break break
} }
@ -109,8 +110,8 @@ func waitForEvent(t *testing.T, con *websocket.Conn, eventid string, dieOnTimeou
// run the check // run the check
err := check(eventid, p) err := check(eventid, p)
if err != nil { if err != nil {
panic(err)
t.Fatal(err) t.Fatal(err)
panic(err) // Show the stack trace.
} }
} else { } else {
con.Close() con.Close()
@ -118,6 +119,7 @@ func waitForEvent(t *testing.T, con *websocket.Conn, eventid string, dieOnTimeou
} }
case err := <-errCh: case err := <-errCh:
t.Fatal(err) t.Fatal(err)
panic(err) // Show the stack trace.
} }
} }
@ -140,15 +142,7 @@ func unmarshalResponseNewBlock(b []byte) (*types.Block, error) {
func unmarshalResponseNameReg(b []byte) (*types.NameTx, error) { func unmarshalResponseNameReg(b []byte) (*types.NameTx, error) {
// unmarshall and assert somethings // unmarshall and assert somethings
var response struct { var response ctypes.Response
JSONRPC string `json:"jsonrpc"`
Id string `json:"id"`
Result struct {
Event string `json:"event"`
Data *types.NameTx `json:"data"`
} `json:"result"`
Error string `json:"error"`
}
var err error var err error
wire.ReadJSON(&response, b, &err) wire.ReadJSON(&response, b, &err)
if err != nil { if err != nil {
@ -157,7 +151,7 @@ func unmarshalResponseNameReg(b []byte) (*types.NameTx, error) {
if response.Error != "" { if response.Error != "" {
return nil, fmt.Errorf(response.Error) return nil, fmt.Errorf(response.Error)
} }
tx := response.Result.Data tx := response.Result.(*ctypes.ResultEvent).Data.(types.EventDataTx).Tx.(*types.NameTx)
return tx, nil return tx, nil
} }

View File

@ -15,9 +15,6 @@ type RPCResponse struct {
} }
func NewRPCResponse(id string, res interface{}, err string) RPCResponse { func NewRPCResponse(id string, res interface{}, err string) RPCResponse {
if res == nil {
res = struct{}{}
}
return RPCResponse{ return RPCResponse{
JSONRPC: "2.0", JSONRPC: "2.0",
Id: id, Id: id,

View File

@ -628,8 +628,8 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
// TODO: maybe we want to take funds on error and allow txs in that don't do anythingi? // TODO: maybe we want to take funds on error and allow txs in that don't do anythingi?
if evc != nil { if evc != nil {
evc.FireEvent(types.EventStringAccInput(tx.Input.Address), tx) evc.FireEvent(types.EventStringAccInput(tx.Input.Address), types.EventDataTx{tx, nil, ""})
evc.FireEvent(types.EventStringNameReg(tx.Name), tx) evc.FireEvent(types.EventStringNameReg(tx.Name), types.EventDataTx{tx, nil, ""})
} }
return nil return nil
@ -711,7 +711,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
} }
if evc != nil { if evc != nil {
// TODO: fire for all inputs // TODO: fire for all inputs
evc.FireEvent(types.EventStringBond(), tx) evc.FireEvent(types.EventStringBond(), types.EventDataTx{tx, nil, ""})
} }
return nil return nil
@ -736,7 +736,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
// Good! // Good!
_s.unbondValidator(val) _s.unbondValidator(val)
if evc != nil { if evc != nil {
evc.FireEvent(types.EventStringUnbond(), tx) evc.FireEvent(types.EventStringUnbond(), types.EventDataTx{tx, nil, ""})
} }
return nil return nil
@ -764,7 +764,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
// Good! // Good!
_s.rebondValidator(val) _s.rebondValidator(val)
if evc != nil { if evc != nil {
evc.FireEvent(types.EventStringRebond(), tx) evc.FireEvent(types.EventStringRebond(), types.EventDataTx{tx, nil, ""})
} }
return nil return nil
@ -803,7 +803,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
// Good! (Bad validator!) // Good! (Bad validator!)
_s.destroyValidator(accused) _s.destroyValidator(accused)
if evc != nil { if evc != nil {
evc.FireEvent(types.EventStringDupeout(), tx) evc.FireEvent(types.EventStringDupeout(), types.EventDataTx{tx, nil, ""})
} }
return nil return nil
@ -894,7 +894,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab
if evc != nil { if evc != nil {
evc.FireEvent(types.EventStringAccInput(tx.Input.Address), types.EventDataTx{tx, nil, ""}) evc.FireEvent(types.EventStringAccInput(tx.Input.Address), types.EventDataTx{tx, nil, ""})
evc.FireEvent(types.EventStringPermissions(ptypes.PermFlagToString(permFlag)), tx) evc.FireEvent(types.EventStringPermissions(ptypes.PermFlagToString(permFlag)), types.EventDataTx{tx, nil, ""})
} }
return nil return nil

View File

@ -1055,7 +1055,7 @@ func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, eventid
evsw := events.NewEventSwitch() evsw := events.NewEventSwitch()
evsw.Start() evsw.Start()
ch := make(chan interface{}) ch := make(chan interface{})
evsw.AddListenerForEvent("test", eventid, func(msg interface{}) { evsw.AddListenerForEvent("test", eventid, func(msg types.EventData) {
ch <- msg ch <- msg
}) })
evc := events.NewEventCache(evsw) evc := events.NewEventCache(evsw)

View File

@ -12,7 +12,6 @@ type TxCache struct {
backend *BlockCache backend *BlockCache
accounts map[Word256]vmAccountInfo accounts map[Word256]vmAccountInfo
storages map[Tuple256]Word256 storages map[Tuple256]Word256
logs []types.EventDataLog
} }
func NewTxCache(backend *BlockCache) *TxCache { func NewTxCache(backend *BlockCache) *TxCache {
@ -20,7 +19,6 @@ func NewTxCache(backend *BlockCache) *TxCache {
backend: backend, backend: backend,
accounts: make(map[Word256]vmAccountInfo), accounts: make(map[Word256]vmAccountInfo),
storages: make(map[Tuple256]Word256), storages: make(map[Tuple256]Word256),
logs: make([]types.EventDataLog, 0),
} }
} }
@ -138,10 +136,6 @@ func (cache *TxCache) Sync() {
} }
} }
func (cache *TxCache) AddLog(log types.EventDataLog) {
cache.logs = append(cache.logs, log)
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Convenience function to return address of new contract // Convenience function to return address of new contract

View File

@ -14,6 +14,7 @@ func EventStringAccOutput(addr []byte) string { return fmt.Sprintf("Acc/%X/Out
func EventStringAccCall(addr []byte) string { return fmt.Sprintf("Acc/%X/Call", addr) } func EventStringAccCall(addr []byte) string { return fmt.Sprintf("Acc/%X/Call", addr) }
func EventStringLogEvent(addr []byte) string { return fmt.Sprintf("Log/%X", addr) } func EventStringLogEvent(addr []byte) string { return fmt.Sprintf("Log/%X", addr) }
func EventStringPermissions(name string) string { return fmt.Sprintf("Permissions/%s", name) } func EventStringPermissions(name string) string { return fmt.Sprintf("Permissions/%s", name) }
func EventStringNameReg(name string) string { return fmt.Sprintf("NameReg/%s", name) }
func EventStringBond() string { return "Bond" } func EventStringBond() string { return "Bond" }
func EventStringUnbond() string { return "Unbond" } func EventStringUnbond() string { return "Unbond" }
func EventStringRebond() string { return "Rebond" } func EventStringRebond() string { return "Rebond" }
@ -31,12 +32,14 @@ const (
EventDataTypeLog = byte(0x05) EventDataTypeLog = byte(0x05)
) )
type EventData interface{} type EventData interface {
AssertIsEventData()
}
var _ = wire.RegisterInterface( var _ = wire.RegisterInterface(
struct{ EventData }{}, struct{ EventData }{},
wire.ConcreteType{EventDataNewBlock{}, EventDataTypeNewBlock}, wire.ConcreteType{EventDataNewBlock{}, EventDataTypeNewBlock},
// wire.ConcreteType{EventDataNewBlock{}, EventDataTypeFork }, // wire.ConcreteType{EventDataFork{}, EventDataTypeFork },
wire.ConcreteType{EventDataTx{}, EventDataTypeTx}, wire.ConcreteType{EventDataTx{}, EventDataTypeTx},
wire.ConcreteType{EventDataCall{}, EventDataTypeCall}, wire.ConcreteType{EventDataCall{}, EventDataTypeCall},
wire.ConcreteType{EventDataLog{}, EventDataTypeLog}, wire.ConcreteType{EventDataLog{}, EventDataTypeLog},
@ -80,3 +83,8 @@ type EventDataLog struct {
Data []byte `json:"data"` Data []byte `json:"data"`
Height int64 `json:"height"` Height int64 `json:"height"`
} }
func (_ EventDataNewBlock) AssertIsEventData() {}
func (_ EventDataTx) AssertIsEventData() {}
func (_ EventDataCall) AssertIsEventData() {}
func (_ EventDataLog) AssertIsEventData() {}

View File

@ -2,7 +2,6 @@ package vm
import ( import (
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/types"
. "github.com/tendermint/tendermint/vm" . "github.com/tendermint/tendermint/vm"
"github.com/tendermint/tendermint/vm/sha3" "github.com/tendermint/tendermint/vm/sha3"
) )
@ -10,7 +9,6 @@ import (
type FakeAppState struct { type FakeAppState struct {
accounts map[string]*Account accounts map[string]*Account
storage map[string]Word256 storage map[string]Word256
logs []types.EventDataLog
} }
func (fas *FakeAppState) GetAccount(addr Word256) *Account { func (fas *FakeAppState) GetAccount(addr Word256) *Account {
@ -70,10 +68,6 @@ func (fas *FakeAppState) SetStorage(addr Word256, key Word256, value Word256) {
fas.storage[addr.String()+key.String()] = value fas.storage[addr.String()+key.String()] = value
} }
func (fas *FakeAppState) AddLog(log types.EventDataLog) {
fas.logs = append(fas.logs, log)
}
// Creates a 20 byte address and bumps the nonce. // Creates a 20 byte address and bumps the nonce.
func createAddress(creator *Account) Word256 { func createAddress(creator *Account) Word256 {
nonce := creator.Nonce nonce := creator.Nonce

View File

@ -44,7 +44,7 @@ func TestLog4(t *testing.T) {
doneChan := make(chan struct{}, 1) doneChan := make(chan struct{}, 1)
eventSwitch.AddListenerForEvent("test", eventId, func(event interface{}) { eventSwitch.AddListenerForEvent("test", eventId, func(event types.EventData) {
logEvent := event.(types.EventDataLog) logEvent := event.(types.EventDataLog)
// No need to test address as this event would not happen if it wasn't correct // No need to test address as this event would not happen if it wasn't correct
if !reflect.DeepEqual(logEvent.Topics, expectedTopics) { if !reflect.DeepEqual(logEvent.Topics, expectedTopics) {

View File

@ -19,7 +19,6 @@ func newAppState() *FakeAppState {
fas := &FakeAppState{ fas := &FakeAppState{
accounts: make(map[string]*Account), accounts: make(map[string]*Account),
storage: make(map[string]Word256), storage: make(map[string]Word256),
logs: nil,
} }
// For default permissions // For default permissions
fas.accounts[ptypes.GlobalPermissionsAddress256.String()] = &Account{ fas.accounts[ptypes.GlobalPermissionsAddress256.String()] = &Account{
@ -158,7 +157,7 @@ func runVMWaitEvents(t *testing.T, ourVm *VM, caller, callee *Account, subscribe
evsw.Start() evsw.Start()
ch := make(chan interface{}) ch := make(chan interface{})
fmt.Printf("subscribe to %x\n", subscribeAddr) fmt.Printf("subscribe to %x\n", subscribeAddr)
evsw.AddListenerForEvent("test", types.EventStringAccCall(subscribeAddr), func(msg interface{}) { evsw.AddListenerForEvent("test", types.EventStringAccCall(subscribeAddr), func(msg types.EventData) {
ch <- msg ch <- msg
}) })
evc := events.NewEventCache(evsw) evc := events.NewEventCache(evsw)

View File

@ -3,7 +3,6 @@ package vm
import ( import (
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
ptypes "github.com/tendermint/tendermint/permission/types" ptypes "github.com/tendermint/tendermint/permission/types"
"github.com/tendermint/tendermint/types"
) )
const ( const (
@ -40,8 +39,6 @@ type AppState interface {
GetStorage(Word256, Word256) Word256 GetStorage(Word256, Word256) Word256
SetStorage(Word256, Word256, Word256) // Setting to Zero is deleting. SetStorage(Word256, Word256, Word256) // Setting to Zero is deleting.
// Logs
AddLog(types.EventDataLog)
} }
type Params struct { type Params struct {

View File

@ -694,20 +694,18 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
log := types.EventDataLog{
callee.Address,
topics,
data,
vm.params.BlockHeight,
}
vm.appState.AddLog(log)
if vm.evc != nil { if vm.evc != nil {
eventId := types.EventStringLogEvent(callee.Address.Postfix(20)) eventId := types.EventStringLogEvent(callee.Address.Postfix(20))
fmt.Printf("eventId: %s\n", eventId) fmt.Printf("eventId: %s\n", eventId)
log := types.EventDataLog{
callee.Address,
topics,
data,
vm.params.BlockHeight,
}
vm.evc.FireEvent(eventId, log) vm.evc.FireEvent(eventId, log)
} }
// Using sol-log for this as well since 'log' will print garbage. dbg.Printf(" => T:%X D:%X\n", topics, data)
dbg.Printf(" => T:%X D:%X\n", log.Topics, log.Data)
case CREATE: // 0xF0 case CREATE: // 0xF0
if !HasPermission(vm.appState, callee, ptypes.CreateContract) { if !HasPermission(vm.appState, callee, ptypes.CreateContract) {

View File

@ -419,11 +419,14 @@ func writeReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, w io.Wr
if !ok { if !ok {
switch crt.Kind() { switch crt.Kind() {
case reflect.Ptr: case reflect.Ptr:
*err = errors.New(Fmt("Unexpected pointer type %v. Was it registered as a value receiver rather than as a pointer receiver?", crt)) *err = errors.New(Fmt("Unexpected pointer type %v for registered interface %v. "+
"Was it registered as a value receiver rather than as a pointer receiver?", crt, rt.Name()))
case reflect.Struct: case reflect.Struct:
*err = errors.New(Fmt("Unexpected struct type %v. Was it registered as a pointer receiver rather than as a value receiver?", crt)) *err = errors.New(Fmt("Unexpected struct type %v for registered interface %v. "+
"Was it registered as a pointer receiver rather than as a value receiver?", crt, rt.Name()))
default: default:
*err = errors.New(Fmt("Unexpected type %v.", crt)) *err = errors.New(Fmt("Unexpected type %v for registered interface %v. "+
"If this is intentional, please register it.", crt, rt.Name()))
} }
return return
} }
@ -819,11 +822,14 @@ func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64,
if !ok { if !ok {
switch crt.Kind() { switch crt.Kind() {
case reflect.Ptr: case reflect.Ptr:
*err = errors.New(Fmt("Unexpected pointer type %v. Was it registered as a value receiver rather than as a pointer receiver?", crt)) *err = errors.New(Fmt("Unexpected pointer type %v for registered interface %v. "+
"Was it registered as a value receiver rather than as a pointer receiver?", crt, rt.Name()))
case reflect.Struct: case reflect.Struct:
*err = errors.New(Fmt("Unexpected struct type %v. Was it registered as a pointer receiver rather than as a value receiver?", crt)) *err = errors.New(Fmt("Unexpected struct type %v for registered interface %v. "+
"Was it registered as a pointer receiver rather than as a value receiver?", crt, rt.Name()))
default: default:
*err = errors.New(Fmt("Unexpected type %v.", crt)) *err = errors.New(Fmt("Unexpected type %v for registered interface %v. "+
"If this is intentional, please register it.", crt, rt.Name()))
} }
return return
} }