// run ExecTx and wait for the Call event on given addr // returns the msg data and an error/exception func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, eventid string) (interface{}, string) { evsw := events.NewEventSwitch() evsw.Start() ch := make(chan interface{}) evsw.AddListenerForEvent("test", eventid, func(msg types.EventData) { ch <- msg }) evc := events.NewEventCache(evsw) go func() { if err := ExecTx(blockCache, tx, true, evc); err != nil { ch <- err.Error() } evc.Flush() }() ticker := time.NewTicker(5 * time.Second) var msg interface{} select { case msg = <-ch: case <-ticker.C: return nil, ExceptionTimeOut } switch ev := msg.(type) { case types.EventDataTx: return ev, ev.Exception case types.EventDataCall: return ev, ev.Exception case string: return nil, ev default: return ev, "" } }
// subscribes to an AccCall, runs the vm, returns the exception func runVMWaitEvents(t *testing.T, ourVm *VM, caller, callee *Account, subscribeAddr, contractCode []byte, gas int64) string { // we need to catch the event from the CALL to check for exceptions evsw := events.NewEventSwitch() evsw.Start() ch := make(chan interface{}) fmt.Printf("subscribe to %x\n", subscribeAddr) evsw.AddListenerForEvent("test", types.EventStringAccCall(subscribeAddr), func(msg types.EventData) { ch <- msg }) evc := events.NewEventCache(evsw) ourVm.SetFireable(evc) go func() { start := time.Now() output, err := ourVm.Call(caller, callee, contractCode, []byte{}, 0, &gas) fmt.Printf("Output: %v Error: %v\n", output, err) fmt.Println("Call took:", time.Since(start)) if err != nil { ch <- err.Error() } evc.Flush() }() msg := <-ch switch ev := msg.(type) { case types.EventDataTx: return ev.Exception case types.EventDataCall: return ev.Exception case string: return ev } return "" }
// Tests logs and events. func TestLog4(t *testing.T) { st := newAppState() // Create accounts account1 := &Account{ Address: LeftPadWord256(makeBytes(20)), } account2 := &Account{ Address: LeftPadWord256(makeBytes(20)), } st.accounts[account1.Address.String()] = account1 st.accounts[account2.Address.String()] = account2 ourVm := NewVM(st, newParams(), Zero256, nil) eventSwitch := events.NewEventSwitch() _, err := eventSwitch.Start() if err != nil { t.Errorf("Failed to start eventSwitch: %v", err) } eventID := types.EventStringLogEvent(account2.Address.Postfix(20)) doneChan := make(chan struct{}, 1) eventSwitch.AddListenerForEvent("test", eventID, func(event types.EventData) { logEvent := event.(types.EventDataLog) // No need to test address as this event would not happen if it wasn't correct if !reflect.DeepEqual(logEvent.Topics, expectedTopics) { t.Errorf("Event topics are wrong. Got: %v. Expected: %v", logEvent.Topics, expectedTopics) } if !bytes.Equal(logEvent.Data, expectedData) { t.Errorf("Event data is wrong. Got: %s. Expected: %s", logEvent.Data, expectedData) } if logEvent.Height != expectedHeight { t.Errorf("Event block height is wrong. Got: %d. Expected: %d", logEvent.Height, expectedHeight) } doneChan <- struct{}{} }) ourVm.SetFireable(eventSwitch) var gas int64 = 100000 mstore8 := byte(MSTORE8) push1 := byte(PUSH1) log4 := byte(LOG4) stop := byte(STOP) code := []byte{ push1, 16, // data value push1, 0, // memory slot mstore8, push1, 4, // topic 4 push1, 3, // topic 3 push1, 2, // topic 2 push1, 1, // topic 1 push1, 1, // size of data push1, 0, // data starts at this offset log4, stop, } _, err = ourVm.Call(account1, account2, code, []byte{}, 0, &gas) <-doneChan if err != nil { t.Fatal(err) } }