mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-26 19:21:44 +00:00
* tendermint/binary handles fixed-length arrays
* log-event tests
This commit is contained in:
@ -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
|
||||
|
@ -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
vm/test/log_event_test.go
Normal file
87
vm/test/log_event_test.go
Normal 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)
|
||||
}
|
||||
}
|
8
vm/vm.go
8
vm/vm.go
@ -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) {
|
||||
|
Reference in New Issue
Block a user