RegisterInterface() so we can implement custom JSON codec

This commit is contained in:
Jae Kwon 2015-01-04 17:33:18 -08:00
parent 7a8a0fefc7
commit 13ca6fb241
9 changed files with 446 additions and 178 deletions

View File

@ -2,11 +2,9 @@ package account
import (
"errors"
"reflect"
"github.com/tendermint/go-ed25519"
. "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common"
)
// PrivKey is part of PrivAccount and state.PrivValidator.
@ -19,23 +17,11 @@ const (
PrivKeyTypeEd25519 = byte(0x01)
)
//-------------------------------------
// For binary.readReflect
func PrivKeyDecoder(r Unreader, n *int64, err *error) interface{} {
switch t := PeekByte(r, n, err); t {
case PrivKeyTypeEd25519:
return ReadBinary(PrivKeyEd25519{}, r, n, err)
default:
*err = Errorf("Unknown PrivKey type %X", t)
return nil
}
}
var _ = RegisterType(&TypeInfo{
Type: reflect.TypeOf((*PrivKey)(nil)).Elem(),
Decoder: PrivKeyDecoder,
})
// for binary.readReflect
var _ = RegisterInterface(
struct{ PrivKey }{},
ConcreteType{PrivKeyEd25519{}},
)
//-------------------------------------

View File

@ -2,11 +2,9 @@ package account
import (
"errors"
"reflect"
"github.com/tendermint/go-ed25519"
. "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common"
)
// PubKey is part of Account and Validator.
@ -22,25 +20,12 @@ const (
PubKeyTypeEd25519 = byte(0x01)
)
//-------------------------------------
// for binary.readReflect
func PubKeyDecoder(r Unreader, n *int64, err *error) interface{} {
switch t := PeekByte(r, n, err); t {
case PubKeyTypeNil:
return PubKeyNil{}
case PubKeyTypeEd25519:
return ReadBinary(PubKeyEd25519{}, r, n, err)
default:
*err = Errorf("Unknown PubKey type %X", t)
return nil
}
}
var _ = RegisterType(&TypeInfo{
Type: reflect.TypeOf((*PubKey)(nil)).Elem(),
Decoder: PubKeyDecoder,
})
var _ = RegisterInterface(
struct{ PubKey }{},
ConcreteType{PubKeyNil{}},
ConcreteType{PubKeyEd25519{}},
)
//-------------------------------------

View File

@ -3,7 +3,6 @@ package account
import (
"errors"
"fmt"
"reflect"
"github.com/tendermint/go-ed25519"
. "github.com/tendermint/tendermint/binary"
@ -19,23 +18,11 @@ const (
SignatureTypeEd25519 = byte(0x01)
)
//-------------------------------------
// for binary.readReflect
func SignatureDecoder(r Unreader, n *int64, err *error) interface{} {
switch t := PeekByte(r, n, err); t {
case SignatureTypeEd25519:
return ReadBinary(SignatureEd25519{}, r, n, err)
default:
*err = Errorf("Unknown Signature type %X", t)
return nil
}
}
var _ = RegisterType(&TypeInfo{
Type: reflect.TypeOf((*Signature)(nil)).Elem(),
Decoder: SignatureDecoder,
})
var _ = RegisterInterface(
struct{ Signature }{},
ConcreteType{SignatureEd25519{}},
)
//-------------------------------------

View File

@ -96,62 +96,15 @@ foo := Foo{Dog{}}
buf, n, err := new(bytes.Buffer), new(int64), new(error)
WriteBinary(foo, buf, n, err)
// This errors with "Unknown field type interface"
// This errors because we don't know whether to read a Dog or Cat.
foo2 := ReadBinary(Foo{}, buf, n, err)
```
In the above example, `ReadBinary()` fails because the `Greeter` field for `Foo{}`
is ambiguous -- it could be either a `Dog{}` or a `Cat{}`, like a union structure.
In this case, the user must define a custom encoder/decoder as follows:
The solution is to declare the concrete implementation types for interfaces:
```go
const (
GreeterTypeDog = byte(0x01)
GreeterTypeCat = byte(0x02)
)
func GreeterEncoder(o interface{}, w io.Writer, n *int64, err *error) {
switch o.(type) {
case Dog:
WriteByte(GreeterTypeDog, w, n, err)
WriteBinary(o, w, n, err)
case Cat:
WriteByte(GreeterTypeCat, w, n, err)
WriteBinary(o, w, n, err)
default:
*err = errors.New(fmt.Sprintf("Unknown greeter type %v", o))
}
}
func GreeterDecoder(r Unreader, n *int64, err *error) interface{} {
switch t := ReadByte(r, n, err); t {
case GreeterTypeDog:
return ReadBinary(Dog{}, r, n, err)
case GreeterTypeCat:
return ReadBinary(Cat{}, r, n, err)
default:
*err = errors.New(fmt.Sprintf("Unknown greeter type byte %X", t))
return nil
}
}
// This tells the reflection system to use the custom encoder/decoder functions
// for encoding/decoding interface struct-field types.
var _ = RegisterType(&TypeInfo{
Type: reflect.TypeOf((*Greeter)(nil)).Elem(),
Encoder: GreeterEncoder,
Decoder: GreeterDecoder,
})
```
Sometimes you want to always prefix a globally unique type byte while encoding,
whether or not the declared type is an interface or concrete type.
In this case, you can declare a "TypeByte() byte" function on the struct (as
a value receiver, not a pointer receiver!), and you can skip the declaration of
a custom encoder. The decoder must "peek" the byte instead of consuming it.
```go
type Dog struct{}
func (d Dog) TypeByte() byte { return GreeterTypeDog }
func (d Dog) Greet() string { return "Woof!" }
@ -160,21 +113,18 @@ type Cat struct{}
func (c Cat) TypeByte() byte { return GreeterTypeCat }
func (c Cat) Greet() string { return "Meow!" }
func GreeterDecoder(r Unreader, n *int64, err *error) interface{} {
// We must peek the type byte because ReadBinary() expects it.
switch t := PeekByte(r, n, err); t {
case GreeterTypeDog:
return ReadBinary(Dog{}, r, n, err)
case GreeterTypeCat:
return ReadBinary(Cat{}, r, n, err)
default:
*err = errors.New(fmt.Sprintf("Unknown greeter type byte %X", t))
return nil
}
}
var _ = RegisterType(&TypeInfo{
Type: reflect.TypeOf((*Greeter)(nil)).Elem(),
Decoder: GreeterDecoder,
var _ = RegisterInterface(
struct{Greeter}{},
ConcreteType{Dog{}},
ConcreteType{Cat{}},
})
```
NOTE: The TypeByte() is written and expected to be read even when the struct
is encoded or decoded directly:
```go
WriteBinary(Dog{}, buf, n, err) // Writes GreeterTypeDog byte
dog_ := ReadBinary(Dog{}, buf, n, err) // Expects to read GreeterTypeDog byte
dog := dog_.(Dog) // ok if *err != nil, otherwise dog_ == nil.
```

View File

@ -11,21 +11,42 @@ import (
)
type TypeInfo struct {
Type reflect.Type // The type
Encoder Encoder // Optional custom encoder function
Decoder Decoder // Optional custom decoder function
Type reflect.Type // The type
// Custom encoder/decoder
Encoder Encoder
Decoder Decoder
// If Type is kind reflect.Interface
ConcreteTypes map[byte]reflect.Type
// If Type is concrete
HasTypeByte bool
TypeByte byte
}
// e.g. If o is struct{Foo}{}, return is the Foo interface type.
func GetTypeFromStructDeclaration(o interface{}) reflect.Type {
rt := reflect.TypeOf(o)
if rt.NumField() != 1 {
panic("Unexpected number of fields in struct-wrapped declaration of type")
}
return rt.Field(0).Type
}
// If o implements HasTypeByte, returns (true, typeByte)
func GetTypeByteFromStruct(o interface{}) (hasTypeByte bool, typeByte byte) {
if _, ok := o.(HasTypeByte); ok {
return true, o.(HasTypeByte).TypeByte()
} else {
return false, byte(0x00)
}
}
// If a type implements TypeByte, the byte is included
// as the first byte for encoding. This is used to encode
// interfaces/union types. In this case the decoding should
// be done manually with a switch statement, and so the
// reflection-based decoder provided here does not expect this
// prefix byte.
// See the reactor implementations for use-cases.
// as the first byte for encoding and decoding.
// This is primarily used to encode interfaces types.
// The interface should be declared with RegisterInterface()
type HasTypeByte interface {
TypeByte() byte
}
@ -45,11 +66,50 @@ func GetTypeInfo(rt reflect.Type) *TypeInfo {
return info
}
// For use with the RegisterInterface declaration
type ConcreteType struct {
O interface{}
}
// Must use this to register an interface to properly decode the
// underlying concrete type.
func RegisterInterface(o interface{}, args ...interface{}) *TypeInfo {
it := GetTypeFromStructDeclaration(o)
if it.Kind() != reflect.Interface {
panic("RegisterInterface expects an interface")
}
concreteTypes := make(map[byte]reflect.Type, 0)
for _, arg := range args {
switch arg.(type) {
case ConcreteType:
concreteTypeInfo := arg.(ConcreteType)
concreteType := reflect.TypeOf(concreteTypeInfo.O)
hasTypeByte, typeByte := GetTypeByteFromStruct(concreteTypeInfo.O)
//fmt.Println(Fmt("HasTypeByte: %v typeByte: %X type: %X", hasTypeByte, typeByte, concreteType))
if !hasTypeByte {
panic(Fmt("Expected concrete type %v to implement HasTypeByte", concreteType))
}
if concreteTypes[typeByte] != nil {
panic(Fmt("Duplicate TypeByte for type %v and %v", concreteType, concreteTypes[typeByte]))
}
concreteTypes[typeByte] = concreteType
default:
panic(Fmt("Unexpected argument type %v", reflect.TypeOf(arg)))
}
}
typeInfo := &TypeInfo{
Type: it,
ConcreteTypes: concreteTypes,
}
typeInfos[it] = typeInfo
return typeInfo
}
// Registers and possibly modifies the TypeInfo.
// NOTE: not goroutine safe, so only call upon program init.
func RegisterType(info *TypeInfo) *TypeInfo {
// Also register the underlying struct's info, if info.Type is a pointer.
// Also register the dereferenced struct if info.Type is a pointer.
// Or, if info.Type is not a pointer, register the pointer.
var rt, ptrRt reflect.Type
if info.Type.Kind() == reflect.Ptr {
@ -96,8 +156,6 @@ func readReflect(rv reflect.Value, rt reflect.Type, r Unreader, n *int64, err *e
// Custom decoder
if typeInfo.Decoder != nil {
decoded := typeInfo.Decoder(r, n, err)
//decodedRv := reflect.Indirect(reflect.ValueOf(decoded))
//rv.Set(decodedRv)
rv.Set(reflect.ValueOf(decoded))
return
}
@ -126,6 +184,19 @@ func readReflect(rv reflect.Value, rt reflect.Type, r Unreader, n *int64, err *e
}
switch rt.Kind() {
case reflect.Interface:
typeByte := PeekByte(r, n, err)
if *err != nil {
return
}
concreteType, ok := typeInfo.ConcreteTypes[typeByte]
if !ok {
panic(Fmt("TypeByte %X not registered for interface %v", typeByte, rt))
}
newRv := reflect.New(concreteType)
readReflect(newRv.Elem(), concreteType, r, n, err)
rv.Set(newRv.Elem())
case reflect.Slice:
elemRt := rt.Elem()
if elemRt.Kind() == reflect.Uint8 {

317
binary/reflect_test.go Normal file
View File

@ -0,0 +1,317 @@
package binary
import (
"bytes"
"reflect"
"testing"
)
type SimpleStruct struct {
String string
Bytes []byte
}
//-------------------------------------
type Animal interface{}
const (
AnimalTypeCat = byte(0x01)
AnimalTypeDog = byte(0x02)
AnimalTypeSnake = byte(0x03)
AnimalTypeViper = byte(0x04)
)
// Implements Animal
type Cat struct {
SimpleStruct
}
func (cat Cat) TypeByte() byte { return AnimalTypeCat }
// Implements Animal
type Dog struct {
SimpleStruct
}
func (dog Dog) TypeByte() byte { return AnimalTypeDog }
// Implements Animal
type Snake []byte
func (snake Snake) TypeByte() byte { return AnimalTypeSnake }
// Implements Animal
type Viper struct {
Bytes []byte
}
func (viper *Viper) TypeByte() byte { return AnimalTypeViper }
var _ = RegisterInterface(
struct{ Animal }{},
ConcreteType{Cat{}},
ConcreteType{Dog{}},
ConcreteType{Snake{}},
ConcreteType{&Viper{}},
)
//-------------------------------------
func TestBasic(t *testing.T) {
cat := Cat{
SimpleStruct{
String: "String",
Bytes: []byte("Bytes"),
},
}
buf, n, err := new(bytes.Buffer), new(int64), new(error)
WriteBinary(cat, buf, n, err)
if *err != nil {
t.Fatalf("Failed to write cat: %v", *err)
}
t.Logf("Wrote bytes: %X", buf.Bytes())
bufBytes := buf.Bytes()
// Read onto a struct
cat2_ := ReadBinary(Cat{}, buf, n, err)
if *err != nil {
t.Fatalf("Failed to read cat: %v", *err)
}
cat2 := cat2_.(Cat)
if cat2.String != "String" {
t.Errorf("Expected cat2.String == 'String', got %v", cat2.String)
}
if string(cat2.Bytes) != "Bytes" {
t.Errorf("Expected cat2.Bytes == 'Bytes', got %X", cat2.Bytes)
}
// Read onto a ptr
r := bytes.NewReader(bufBytes)
cat3_ := ReadBinary(&Cat{}, r, n, err)
if *err != nil {
t.Fatalf("Failed to read cat: %v", *err)
}
cat3 := cat3_.(*Cat)
if cat3.String != "String" {
t.Errorf("Expected cat3.String == 'String', got %v", cat3.String)
}
if string(cat3.Bytes) != "Bytes" {
t.Errorf("Expected cat3.Bytes == 'Bytes', got %X", cat3.Bytes)
}
}
//-------------------------------------
type ComplexStruct struct {
Name string
Animal Animal
}
func TestComplexStruct(t *testing.T) {
c := ComplexStruct{
Name: "Complex",
Animal: Cat{
SimpleStruct{
String: "String",
Bytes: []byte("Bytes"),
},
},
}
buf, n, err := new(bytes.Buffer), new(int64), new(error)
WriteBinary(c, buf, n, err)
if *err != nil {
t.Fatalf("Failed to write c: %v", *err)
}
t.Logf("Wrote bytes: %X", buf.Bytes())
c2_ := ReadBinary(&ComplexStruct{}, buf, n, err)
if *err != nil {
t.Fatalf("Failed to read c: %v", *err)
}
c2 := c2_.(*ComplexStruct)
if cat, ok := c2.Animal.(Cat); ok {
if cat.String != "String" {
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
}
if string(cat.Bytes) != "Bytes" {
t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes)
}
} else {
t.Errorf("Expected c2.Animal to be of type cat, got %v", reflect.ValueOf(c2.Animal).Elem().Type())
}
}
//-------------------------------------
type ComplexArrayStruct struct {
Animals []Animal
}
func TestComplexArrayStruct(t *testing.T) {
c := ComplexArrayStruct{
Animals: []Animal{
Cat{
SimpleStruct{
String: "String",
Bytes: []byte("Bytes"),
},
},
&Dog{ // Even though it's a *Dog, we'll get a Dog{} back.
SimpleStruct{
String: "Woof",
Bytes: []byte("Bark"),
},
},
Snake([]byte("hiss")),
&Viper{
Bytes: []byte("hizz"),
},
},
}
buf, n, err := new(bytes.Buffer), new(int64), new(error)
WriteBinary(c, buf, n, err)
if *err != nil {
t.Fatalf("Failed to write c: %v", *err)
}
t.Logf("Wrote bytes: %X", buf.Bytes())
c2_ := ReadBinary(&ComplexArrayStruct{}, buf, n, err)
if *err != nil {
t.Fatalf("Failed to read c: %v", *err)
}
c2 := c2_.(*ComplexArrayStruct)
if cat, ok := c2.Animals[0].(Cat); ok {
if cat.String != "String" {
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
}
if string(cat.Bytes) != "Bytes" {
t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes)
}
} else {
t.Errorf("Expected c2.Animals[0] to be of type cat, got %v", reflect.ValueOf(c2.Animals[0]).Elem().Type())
}
if dog, ok := c2.Animals[1].(Dog); ok {
if dog.String != "Woof" {
t.Errorf("Expected dog.String == 'Woof', got %v", dog.String)
}
if string(dog.Bytes) != "Bark" {
t.Errorf("Expected dog.Bytes == 'Bark', got %X", dog.Bytes)
}
} else {
t.Errorf("Expected c2.Animals[1] to be of type dog, got %v", reflect.ValueOf(c2.Animals[1]).Elem().Type())
}
if snake, ok := c2.Animals[2].(Snake); ok {
if string(snake) != "hiss" {
t.Errorf("Expected string(snake) == 'hiss', got %v", string(snake))
}
} else {
t.Errorf("Expected c2.Animals[2] to be of type Snake, got %v", reflect.ValueOf(c2.Animals[2]).Elem().Type())
}
if viper, ok := c2.Animals[3].(*Viper); ok {
if string(viper.Bytes) != "hizz" {
t.Errorf("Expected string(viper.Bytes) == 'hizz', got %v", string(viper.Bytes))
}
} else {
t.Errorf("Expected c2.Animals[3] to be of type *Viper, got %v", reflect.ValueOf(c2.Animals[3]).Elem().Type())
}
}
//-------------------------------------
type ComplexStruct2 struct {
Cat Cat
Dog *Dog
Snake Snake
Snake2 *Snake
Viper Viper
Viper2 *Viper
}
func TestComplexStruct2(t *testing.T) {
snake_ := Snake([]byte("hiss"))
snakePtr_ := &snake_
c := ComplexStruct2{
Cat: Cat{
SimpleStruct{
String: "String",
Bytes: []byte("Bytes"),
},
},
Dog: &Dog{
SimpleStruct{
String: "Woof",
Bytes: []byte("Bark"),
},
},
Snake: Snake([]byte("hiss")),
Snake2: snakePtr_,
Viper: Viper{Bytes: []byte("hizz")},
Viper2: &Viper{Bytes: []byte("hizz")},
}
buf, n, err := new(bytes.Buffer), new(int64), new(error)
WriteBinary(c, buf, n, err)
if *err != nil {
t.Fatalf("Failed to write c: %v", *err)
}
t.Logf("Wrote bytes: %X", buf.Bytes())
c2_ := ReadBinary(&ComplexStruct2{}, buf, n, err)
if *err != nil {
t.Fatalf("Failed to read c: %v", *err)
}
c2 := c2_.(*ComplexStruct2)
cat := c2.Cat
if cat.String != "String" {
t.Errorf("Expected cat.String == 'String', got %v", cat.String)
}
if string(cat.Bytes) != "Bytes" {
t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes)
}
dog := c2.Dog
if dog.String != "Woof" {
t.Errorf("Expected dog.String == 'Woof', got %v", dog.String)
}
if string(dog.Bytes) != "Bark" {
t.Errorf("Expected dog.Bytes == 'Bark', got %X", dog.Bytes)
}
snake := c2.Snake
if string(snake) != "hiss" {
t.Errorf("Expected string(snake) == 'hiss', got %v", string(snake))
}
snake2 := c2.Snake2
if string(*snake2) != "hiss" {
t.Errorf("Expected string(snake2) == 'hiss', got %v", string(*snake2))
}
viper := c2.Viper
if string(viper.Bytes) != "hizz" {
t.Errorf("Expected string(viper.Bytes) == 'hizz', got %v", string(viper.Bytes))
}
viper2 := c2.Viper2
if string(viper2.Bytes) != "hizz" {
t.Errorf("Expected string(viper2.Bytes) == 'hizz', got %v", string(viper2.Bytes))
}
}

View File

@ -3,11 +3,9 @@ package block
import (
"errors"
"io"
"reflect"
. "github.com/tendermint/tendermint/account"
. "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common"
)
var (
@ -49,31 +47,15 @@ const (
TxTypeDupeout = byte(0x14)
)
//-------------------------------------
// for binary.readReflect
func TxDecoder(r Unreader, n *int64, err *error) interface{} {
switch t := PeekByte(r, n, err); t {
case TxTypeSend:
return ReadBinary(&SendTx{}, r, n, err)
case TxTypeBond:
return ReadBinary(&BondTx{}, r, n, err)
case TxTypeUnbond:
return ReadBinary(&UnbondTx{}, r, n, err)
case TxTypeRebond:
return ReadBinary(&RebondTx{}, r, n, err)
case TxTypeDupeout:
return ReadBinary(&DupeoutTx{}, r, n, err)
default:
*err = Errorf("Unknown Tx type %X", t)
return nil
}
}
var _ = RegisterType(&TypeInfo{
Type: reflect.TypeOf((*Tx)(nil)).Elem(),
Decoder: TxDecoder,
})
var _ = RegisterInterface(
struct{ Tx }{},
ConcreteType{&SendTx{}},
ConcreteType{&BondTx{}},
ConcreteType{&UnbondTx{}},
ConcreteType{&RebondTx{}},
ConcreteType{&DupeoutTx{}},
)
//-----------------------------------------------------------------------------

View File

@ -23,20 +23,11 @@ func getString(prompt string) string {
return input[:len(input)-1]
}
func getByteSliceFromBase64(prompt string) []byte {
input := getString(prompt)
bytes, err := hex.DecodeString(input)
if err != nil {
Exit(Fmt("Not in hexadecimal format: %v\nError: %v\n", input, err))
}
return bytes
}
func getByteSliceFromHex(prompt string) []byte {
input := getString(prompt)
bytes, err := hex.DecodeString(input)
if err != nil {
Exit(Fmt("Not in hexadecimal format: %v\nError: %v\n", input, err))
Exit(Fmt("Not in hex format: %v\nError: %v\n", input, err))
}
return bytes
}
@ -57,13 +48,12 @@ func gen_tx() {
state := state_.LoadState(stateDB)
// Get source pubkey
srcPubKeyBytes := getByteSliceFromBase64("Enter source pubkey: ")
srcPubKeyBytes := getByteSliceFromHex("Enter source pubkey: ")
r, n, err := bytes.NewReader(srcPubKeyBytes), new(int64), new(error)
srcPubKey_ := account_.PubKeyDecoder(r, n, err)
srcPubKey := binary.ReadBinary(struct{ account_.PubKey }{}, r, n, err).(struct{ account_.PubKey }).PubKey
if *err != nil {
Exit(Fmt("Invalid PubKey. Error: %v", err))
}
srcPubKey := srcPubKey_.(account_.PubKey)
// Get the state of the account.
var srcAccount *account_.Account
@ -112,13 +102,12 @@ func gen_tx() {
fmt.Printf("Generated tx: %X\n", binary.BinaryBytes(tx))
// Get source privkey (for signing)
srcPrivKeyBytes := getByteSliceFromBase64("Enter source privkey (for signing): ")
srcPrivKeyBytes := getByteSliceFromHex("Enter source privkey (for signing): ")
r, n, err = bytes.NewReader(srcPrivKeyBytes), new(int64), new(error)
srcPrivKey_ := account_.PrivKeyDecoder(r, n, err)
srcPrivKey := binary.ReadBinary(struct{ account_.PrivKey }{}, r, n, err).(struct{ account_.PrivKey }).PrivKey
if *err != nil {
Exit(Fmt("Invalid PrivKey. Error: %v", err))
}
srcPrivKey := srcPrivKey_.(account_.PrivKey)
// Sign
tx.Inputs[0].Signature = srcPrivKey.Sign(account_.SignBytes(tx))

View File

@ -6,7 +6,8 @@ import (
"fmt"
"net/http"
"github.com/tendermint/tendermint/block"
. "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/block"
. "github.com/tendermint/tendermint/common"
)
@ -19,11 +20,11 @@ func MempoolHandler(w http.ResponseWriter, r *http.Request) {
}
reader, n := bytes.NewReader(txBytes), new(int64)
tx_ := block.TxDecoder(reader, n, &err)
tx_ := ReadBinary(struct{ Tx }{}, reader, n, &err).(struct{ Tx })
if err != nil {
ReturnJSON(API_INVALID_PARAM, Fmt("Invalid tx_bytes: %v", err))
}
tx := tx_.(block.Tx)
tx := tx_.Tx
err = mempoolReactor.BroadcastTx(tx)
if err != nil {