Browse Source

* tendermint/binary handles fixed-length arrays

* log-event tests
pull/113/head
androlo 10 years ago
committed by Jae Kwon
parent
commit
0a72c1ee50
4 changed files with 204 additions and 18 deletions
  1. +106
    -1
      binary/reflect.go
  2. +4
    -16
      types/events.go
  3. +87
    -0
      vm/test/log_event_test.go
  4. +7
    -1
      vm/vm.go

+ 106
- 1
binary/reflect.go View File

@ -250,6 +250,33 @@ func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Rea
}
switch rt.Kind() {
case reflect.Array:
elemRt := rt.Elem()
length := rt.Len()
if elemRt.Kind() == reflect.Uint8 {
// Special case: Bytearrays
buf := make([]byte, length)
ReadFull(buf, r, n, err)
if *err != nil {
return
}
log.Debug("Read bytearray", "bytes", buf)
reflect.Copy(rv, reflect.ValueOf(buf))
} else {
for i := 0; i < length; i++ {
elemRv := rv.Index(i)
readReflectBinary(elemRv, elemRt, opts, r, n, err)
if *err != nil {
return
}
if MaxBinaryReadSize < *n {
*err = ErrBinaryReadSizeOverflow
return
}
}
log.Debug(Fmt("Read %v-array", elemRt), "length", length)
}
case reflect.Slice:
elemRt := rt.Elem()
if elemRt.Kind() == reflect.Uint8 {
@ -438,6 +465,27 @@ func writeReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, w io.Wr
// All other types
switch rt.Kind() {
case reflect.Array:
elemRt := rt.Elem()
length := rt.Len()
if elemRt.Kind() == reflect.Uint8 {
// Special case: Bytearrays
if rv.CanAddr() {
byteslice := rv.Slice(0, length).Bytes()
WriteTo(byteslice, w, n, err)
} else {
buf := make([]byte, length)
reflect.Copy(reflect.ValueOf(buf), rv)
WriteTo(buf, w, n, err)
}
} else {
// Write elems
for i := 0; i < length; i++ {
elemRv := rv.Index(i)
writeReflectBinary(elemRv, elemRt, opts, w, n, err)
}
}
case reflect.Slice:
elemRt := rt.Elem()
if elemRt.Kind() == reflect.Uint8 {
@ -602,6 +650,44 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro
}
switch rt.Kind() {
case reflect.Array:
elemRt := rt.Elem()
length := rt.Len()
if elemRt.Kind() == reflect.Uint8 {
// Special case: Bytearrays
oString, ok := o.(string)
if !ok {
*err = errors.New(Fmt("Expected string but got type %v", reflect.TypeOf(o)))
return
}
buf, err_ := hex.DecodeString(oString)
if err_ != nil {
*err = err_
return
}
if len(buf) != length {
*err = errors.New(Fmt("Expected bytearray of length %v but got %v", length, len(buf)))
return
}
log.Debug("Read bytearray", "bytes", buf)
rv.Set(reflect.ValueOf(buf))
} else {
oSlice, ok := o.([]interface{})
if !ok {
*err = errors.New(Fmt("Expected array of %v but got type %v", rt, reflect.TypeOf(o)))
return
}
if len(oSlice) != length {
*err = errors.New(Fmt("Expected array of length %v but got %v", length, len(oSlice)))
return
}
for i := 0; i < length; i++ {
elemRv := rv.Index(i)
readReflectJSON(elemRv, elemRt, oSlice[i], err)
}
log.Debug(Fmt("Read %v-array", elemRt), "length", length)
}
case reflect.Slice:
elemRt := rt.Elem()
if elemRt.Kind() == reflect.Uint8 {
@ -773,13 +859,32 @@ func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64,
// All other types
switch rt.Kind() {
case reflect.Array:
elemRt := rt.Elem()
length := rt.Len()
if elemRt.Kind() == reflect.Uint8 {
// Special case: Bytearray
bytearray := rv.Interface()
WriteTo([]byte(Fmt("\"%X\"", bytearray)), w, n, err)
} else {
WriteTo([]byte("["), w, n, err)
// Write elems
for i := 0; i < length; i++ {
elemRv := rv.Index(i)
writeReflectJSON(elemRv, elemRt, w, n, err)
if i < length-1 {
WriteTo([]byte(","), w, n, err)
}
}
WriteTo([]byte("]"), w, n, err)
}
case reflect.Slice:
elemRt := rt.Elem()
if elemRt.Kind() == reflect.Uint8 {
// Special case: Byteslices
byteslice := rv.Bytes()
WriteTo([]byte(Fmt("\"%X\"", byteslice)), w, n, err)
//WriteByteSlice(byteslice, w, n, err)
} else {
WriteTo([]byte("["), w, n, err)
// Write elems


+ 4
- 16
types/events.go View File

@ -18,6 +18,10 @@ func EventStringAccReceive(addr []byte) string {
return fmt.Sprintf("Acc/%X/Receive", addr)
}
func EventStringLogEvent(addr []byte) string {
return fmt.Sprintf("Log/%X", addr)
}
func EventStringBond() string {
return "Bond"
}
@ -66,19 +70,3 @@ type EventMsgCall struct {
Return []byte `json:"return"`
Exception string `json:"exception"`
}
/*
Acc/XYZ/Input -> full tx or {full tx, return value, exception}
Acc/XYZ/Output -> full tx
Acc/XYZ/Receive -> full tx, return value, exception, (optionally?) calldata
Bond -> full tx
Unbond -> full tx
Rebond -> full tx
Dupeout -> full tx
NewBlock -> full block
Fork -> block A, block B
Log -> Fuck this
NewPeer -> peer
Alert -> alert msg
*/

+ 87
- 0
vm/test/log_event_test.go View File

@ -0,0 +1,87 @@
package vm
import (
"bytes"
"reflect"
"testing"
. "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/events"
"github.com/tendermint/tendermint/types"
. "github.com/tendermint/tendermint/vm"
)
var expectedData = []byte{0x10}
var expectedHeight int64 = 0
var expectedTopics = []Word256{
Int64ToWord256(1),
Int64ToWord256(2),
Int64ToWord256(3),
Int64ToWord256(4)}
// 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.EventSwitch{}
eventSwitch.Start()
eventId := types.EventStringLogEvent(account2.Address.Postfix(20))
doneChan := make(chan struct{}, 1)
eventSwitch.AddListenerForEvent("test", eventId, func(event interface{}) {
logEvent := event.(*Log)
// 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)
}
}

+ 7
- 1
vm/vm.go View File

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


Loading…
Cancel
Save