Support nil pointers for Binary.

If the thing does not already have a typebyte declared,
a fake one will be given (0x01).
A TypeByte of 0x00 is reserved for nil things.
No nil-dogs.
This commit is contained in:
Jae Kwon
2015-04-12 17:46:16 -07:00
parent 1364770cbe
commit 6d6f061f19
20 changed files with 299 additions and 178 deletions

View File

@ -2,7 +2,6 @@ package account
import ( import (
"errors" "errors"
"github.com/tendermint/ed25519" "github.com/tendermint/ed25519"
"github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
@ -18,47 +17,17 @@ type PubKey interface {
// Types of PubKey implementations // Types of PubKey implementations
const ( const (
PubKeyTypeNil = byte(0x00)
PubKeyTypeEd25519 = byte(0x01) PubKeyTypeEd25519 = byte(0x01)
) )
// for binary.readReflect // for binary.readReflect
var _ = binary.RegisterInterface( var _ = binary.RegisterInterface(
struct{ PubKey }{}, struct{ PubKey }{},
binary.ConcreteType{PubKeyNil{}},
binary.ConcreteType{PubKeyEd25519{}}, binary.ConcreteType{PubKeyEd25519{}},
) )
//------------------------------------- //-------------------------------------
// Implements PubKey
type PubKeyNil struct{}
func (key PubKeyNil) TypeByte() byte { return PubKeyTypeNil }
func (key PubKeyNil) IsNil() bool { return true }
func (key PubKeyNil) Address() []byte {
panic("PubKeyNil has no address")
}
func (key PubKeyNil) VerifyBytes(msg []byte, sig_ Signature) bool {
panic("PubKeyNil cannot verify messages")
}
func (key PubKeyEd25519) ValidateBasic() error {
if len(key) != ed25519.PublicKeySize {
return errors.New("Invalid PubKeyEd25519 key size")
}
return nil
}
func (key PubKeyNil) String() string {
return "PubKeyNil{}"
}
//-------------------------------------
// Implements PubKey // Implements PubKey
type PubKeyEd25519 []byte type PubKeyEd25519 []byte
@ -81,6 +50,13 @@ func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ Signature) bool {
return ed25519.Verify(pubKeyBytes, msg, sigBytes) return ed25519.Verify(pubKeyBytes, msg, sigBytes)
} }
func (pubKey PubKeyEd25519) ValidateBasic() error {
if len(pubKey) != ed25519.PublicKeySize {
return errors.New("Invalid PubKeyEd25519 key size")
}
return nil
}
func (pubKey PubKeyEd25519) String() string { func (pubKey PubKeyEd25519) String() string {
return Fmt("PubKeyEd25519{%X}", []byte(pubKey)) return Fmt("PubKeyEd25519{%X}", []byte(pubKey))
} }

View File

@ -14,30 +14,17 @@ type Signature interface {
// Types of Signature implementations // Types of Signature implementations
const ( const (
SignatureTypeNil = byte(0x00)
SignatureTypeEd25519 = byte(0x01) SignatureTypeEd25519 = byte(0x01)
) )
// for binary.readReflect // for binary.readReflect
var _ = binary.RegisterInterface( var _ = binary.RegisterInterface(
struct{ Signature }{}, struct{ Signature }{},
binary.ConcreteType{SignatureNil{}},
binary.ConcreteType{SignatureEd25519{}}, binary.ConcreteType{SignatureEd25519{}},
) )
//------------------------------------- //-------------------------------------
// Implements Signature
type SignatureNil struct{}
func (sig SignatureNil) TypeByte() byte { return SignatureTypeNil }
func (sig SignatureNil) IsNil() bool { return true }
func (sig SignatureNil) String() string { return "SignatureNil{}" }
//-------------------------------------
// Implements Signature // Implements Signature
type SignatureEd25519 []byte type SignatureEd25519 []byte

View File

@ -21,6 +21,9 @@ func ReadBinary(o interface{}, r io.Reader, n *int64, err *error) interface{} {
func WriteBinary(o interface{}, w io.Writer, n *int64, err *error) { func WriteBinary(o interface{}, w io.Writer, n *int64, err *error) {
rv := reflect.ValueOf(o) rv := reflect.ValueOf(o)
rt := reflect.TypeOf(o) rt := reflect.TypeOf(o)
if rv.Kind() == reflect.Ptr {
rv, rt = rv.Elem(), rt.Elem()
}
writeReflect(rv, rt, w, n, err) writeReflect(rv, rt, w, n, err)
} }
@ -49,6 +52,9 @@ func ReadJSONFromObject(o interface{}, object interface{}, err *error) interface
func WriteJSON(o interface{}, w io.Writer, n *int64, err *error) { func WriteJSON(o interface{}, w io.Writer, n *int64, err *error) {
rv := reflect.ValueOf(o) rv := reflect.ValueOf(o)
rt := reflect.TypeOf(o) rt := reflect.TypeOf(o)
if rv.Kind() == reflect.Ptr {
rv, rt = rv.Elem(), rt.Elem()
}
writeReflectJSON(rv, rt, w, n, err) writeReflectJSON(rv, rt, w, n, err)
} }

View File

@ -15,13 +15,10 @@ import (
type TypeInfo struct { type TypeInfo struct {
Type reflect.Type // The type Type reflect.Type // The type
// Custom encoder/decoder // If Type is kind reflect.Interface, is registered
// NOTE: Not used. IsRegisteredInterface bool
BinaryEncoder Encoder ConcreteTypes map[byte]reflect.Type
BinaryDecoder Decoder ConcreteTypeBytes map[reflect.Type]byte
// If Type is kind reflect.Interface
ConcreteTypes map[byte]reflect.Type
// If Type is concrete // If Type is concrete
HasTypeByte bool HasTypeByte bool
@ -104,6 +101,7 @@ func RegisterInterface(o interface{}, args ...interface{}) *TypeInfo {
panic("RegisterInterface expects an interface") panic("RegisterInterface expects an interface")
} }
concreteTypes := make(map[byte]reflect.Type, 0) concreteTypes := make(map[byte]reflect.Type, 0)
concreteTypesReversed := make(map[reflect.Type]byte, 0)
for _, arg := range args { for _, arg := range args {
switch arg.(type) { switch arg.(type) {
case ConcreteType: case ConcreteType:
@ -114,17 +112,23 @@ func RegisterInterface(o interface{}, args ...interface{}) *TypeInfo {
if !hasTypeByte { if !hasTypeByte {
panic(Fmt("Expected concrete type %v to implement HasTypeByte", concreteType)) panic(Fmt("Expected concrete type %v to implement HasTypeByte", concreteType))
} }
if typeByte == 0x00 {
panic(Fmt("TypeByte of 0x00 is reserved for nil (%v)", concreteType))
}
if concreteTypes[typeByte] != nil { if concreteTypes[typeByte] != nil {
panic(Fmt("Duplicate TypeByte for type %v and %v", concreteType, concreteTypes[typeByte])) panic(Fmt("Duplicate TypeByte for type %v and %v", concreteType, concreteTypes[typeByte]))
} }
concreteTypes[typeByte] = concreteType concreteTypes[typeByte] = concreteType
concreteTypesReversed[concreteType] = typeByte
default: default:
panic(Fmt("Unexpected argument type %v", reflect.TypeOf(arg))) panic(Fmt("Unexpected argument type %v", reflect.TypeOf(arg)))
} }
} }
typeInfo := &TypeInfo{ typeInfo := &TypeInfo{
Type: it, Type: it,
ConcreteTypes: concreteTypes, IsRegisteredInterface: true,
ConcreteTypes: concreteTypes,
ConcreteTypeBytes: concreteTypesReversed,
} }
typeInfos[it] = typeInfo typeInfos[it] = typeInfo
return typeInfo return typeInfo
@ -148,7 +152,8 @@ func RegisterType(info *TypeInfo) *TypeInfo {
typeInfos[ptrRt] = info typeInfos[ptrRt] = info
// See if the type implements HasTypeByte // See if the type implements HasTypeByte
if rt.Kind() != reflect.Interface && rt.Implements(reflect.TypeOf((*HasTypeByte)(nil)).Elem()) { if rt.Kind() != reflect.Interface &&
rt.Implements(reflect.TypeOf((*HasTypeByte)(nil)).Elem()) {
zero := reflect.Zero(rt) zero := reflect.Zero(rt)
typeByte := zero.Interface().(HasTypeByte).TypeByte() typeByte := zero.Interface().(HasTypeByte).TypeByte()
if info.HasTypeByte && info.TypeByte != typeByte { if info.HasTypeByte && info.TypeByte != typeByte {
@ -197,35 +202,60 @@ func RegisterType(info *TypeInfo) *TypeInfo {
func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err *error) { func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err *error) {
log.Debug("Read reflect", "type", rt)
// Get typeInfo // Get typeInfo
typeInfo := GetTypeInfo(rt) typeInfo := GetTypeInfo(rt)
// Custom decoder if rt.Kind() == reflect.Interface {
if typeInfo.BinaryDecoder != nil { if !typeInfo.IsRegisteredInterface {
decoded := typeInfo.BinaryDecoder(r, n, err) // There's no way we can read such a thing.
rv.Set(reflect.ValueOf(decoded)) *err = errors.New(Fmt("Cannot read unregistered interface type %v", rt))
return
}
typeByte := ReadByte(r, n, err)
if *err != nil {
return
}
if typeByte == 0x00 {
return // nil
}
crt, ok := typeInfo.ConcreteTypes[typeByte]
if !ok {
*err = errors.New(Fmt("Unexpected type byte %X for type %v", typeByte, crt))
return
}
crv := reflect.New(crt).Elem()
r = NewPrefixedReader([]byte{typeByte}, r)
readReflect(crv, crt, r, n, err)
rv.Set(crv) // NOTE: orig rv is ignored.
return return
} }
// Create a new struct if rv is nil pointer. if rt.Kind() == reflect.Ptr {
if rt.Kind() == reflect.Ptr && rv.IsNil() { typeByte := ReadByte(r, n, err)
newRv := reflect.New(rt.Elem()) if *err != nil {
rv.Set(newRv) return
rv = newRv }
} if typeByte == 0x00 {
return // nil
// Dereference pointer }
// Still addressable, thus settable! // Create new if rv is nil.
if rv.Kind() == reflect.Ptr { if rv.IsNil() {
newRv := reflect.New(rt.Elem())
rv.Set(newRv)
rv = newRv
}
// Dereference pointer
rv, rt = rv.Elem(), rt.Elem() rv, rt = rv.Elem(), rt.Elem()
typeInfo = GetTypeInfo(rt)
if typeInfo.HasTypeByte {
r = NewPrefixedReader([]byte{typeByte}, r)
}
// continue...
} }
// Read TypeByte prefix // Read TypeByte prefix
if typeInfo.HasTypeByte { if typeInfo.HasTypeByte {
typeByte := ReadByte(r, n, err) typeByte := ReadByte(r, n, err)
log.Debug("Read typebyte", "typeByte", typeByte)
if typeByte != typeInfo.TypeByte { if typeByte != typeInfo.TypeByte {
*err = errors.New(Fmt("Expected TypeByte of %X but got %X", typeInfo.TypeByte, typeByte)) *err = errors.New(Fmt("Expected TypeByte of %X but got %X", typeInfo.TypeByte, typeByte))
return return
@ -233,19 +263,6 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err *
} }
switch rt.Kind() { switch rt.Kind() {
case reflect.Interface:
typeByte := ReadByte(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, NewPrefixedReader([]byte{typeByte}, r), n, err)
rv.Set(newRv.Elem())
case reflect.Slice: case reflect.Slice:
elemRt := rt.Elem() elemRt := rt.Elem()
if elemRt.Kind() == reflect.Uint8 { if elemRt.Kind() == reflect.Uint8 {
@ -349,36 +366,66 @@ func readReflect(rv reflect.Value, rt reflect.Type, r io.Reader, n *int64, err *
} }
} }
// rv: the reflection value of the thing to write
// rt: the type of rv as declared in the container, not necessarily rv.Type().
func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err *error) { func writeReflect(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err *error) {
// Get typeInfo // Get typeInfo
typeInfo := GetTypeInfo(rt) typeInfo := GetTypeInfo(rt)
// Custom encoder, say for an interface type rt. if rt.Kind() == reflect.Interface {
if typeInfo.BinaryEncoder != nil { if rv.IsNil() {
typeInfo.BinaryEncoder(rv.Interface(), w, n, err) // XXX ensure that typeByte 0 is reserved.
WriteByte(0x00, w, n, err)
return
}
crv := rv.Elem() // concrete reflection value
crt := crv.Type() // concrete reflection type
if typeInfo.IsRegisteredInterface {
// See if the crt is registered.
// If so, we're more restrictive.
_, ok := typeInfo.ConcreteTypeBytes[crt]
if !ok {
switch crt.Kind() {
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))
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))
default:
*err = errors.New(Fmt("Unexpected type %v.", crt))
}
return
}
} else {
// We support writing unsafely for convenience.
}
// We don't have to write the typeByte here,
// the writeReflect() call below will write it.
writeReflect(crv, crt, w, n, err)
return return
} }
// Dereference interface
if rt.Kind() == reflect.Interface {
rv = rv.Elem()
rt = rv.Type()
// If interface type, get typeInfo of underlying type.
typeInfo = GetTypeInfo(rt)
}
// Dereference pointer
if rt.Kind() == reflect.Ptr { if rt.Kind() == reflect.Ptr {
rt = rt.Elem() // Dereference pointer
rv = rv.Elem() rv, rt = rv.Elem(), rt.Elem()
if !rv.IsValid() {
WriteByte(0x00, w, n, err)
return
}
if !typeInfo.HasTypeByte {
WriteByte(0x01, w, n, err)
// continue...
} else {
// continue...
}
} }
// Write TypeByte prefix // Write type byte
if typeInfo.HasTypeByte { if typeInfo.HasTypeByte {
WriteByte(typeInfo.TypeByte, w, n, err) WriteByte(typeInfo.TypeByte, w, n, err)
} }
// All other types
switch rt.Kind() { switch rt.Kind() {
case reflect.Slice: case reflect.Slice:
elemRt := rt.Elem() elemRt := rt.Elem()
@ -478,22 +525,47 @@ func readTypeByteJSON(o interface{}) (typeByte byte, rest interface{}, err error
func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *error) { func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *error) {
log.Debug("Read reflect json", "type", rt)
// Get typeInfo // Get typeInfo
typeInfo := GetTypeInfo(rt) typeInfo := GetTypeInfo(rt)
// Create a new struct if rv is nil pointer. if rt.Kind() == reflect.Interface {
if rt.Kind() == reflect.Ptr && rv.IsNil() { if !typeInfo.IsRegisteredInterface {
newRv := reflect.New(rt.Elem()) // There's no way we can read such a thing.
rv.Set(newRv) *err = errors.New(Fmt("Cannot read unregistered interface type %v", rt))
rv = newRv return
}
if o == nil {
return // nil
}
typeByte, _, err_ := readTypeByteJSON(o)
if err_ != nil {
*err = err_
return
}
crt, ok := typeInfo.ConcreteTypes[typeByte]
if !ok {
*err = errors.New(Fmt("TypeByte %X not registered for interface %v", typeByte, rt))
return
}
crv := reflect.New(crt).Elem()
readReflectJSON(crv, crt, o, err)
rv.Set(crv) // NOTE: orig rv is ignored.
return
} }
// Dereference pointer if rt.Kind() == reflect.Ptr {
// Still addressable, thus settable! if o == nil {
if rv.Kind() == reflect.Ptr { return // nil
}
// Create new struct if rv is nil.
if rv.IsNil() {
newRv := reflect.New(rt.Elem())
rv.Set(newRv)
rv = newRv
}
// Dereference pointer
rv, rt = rv.Elem(), rt.Elem() rv, rt = rv.Elem(), rt.Elem()
// continue...
} }
// Read TypeByte prefix // Read TypeByte prefix
@ -511,20 +583,6 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro
} }
switch rt.Kind() { switch rt.Kind() {
case reflect.Interface:
typeByte, _, err_ := readTypeByteJSON(o)
if err_ != nil {
*err = err_
return
}
concreteType, ok := typeInfo.ConcreteTypes[typeByte]
if !ok {
panic(Fmt("TypeByte %X not registered for interface %v", typeByte, rt))
}
newRv := reflect.New(concreteType)
readReflectJSON(newRv.Elem(), concreteType, o, err)
rv.Set(newRv.Elem())
case reflect.Slice: case reflect.Slice:
elemRt := rt.Elem() elemRt := rt.Elem()
if elemRt.Kind() == reflect.Uint8 { if elemRt.Kind() == reflect.Uint8 {
@ -643,25 +701,55 @@ func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64,
// Get typeInfo // Get typeInfo
typeInfo := GetTypeInfo(rt) typeInfo := GetTypeInfo(rt)
// Dereference interface
if rt.Kind() == reflect.Interface { if rt.Kind() == reflect.Interface {
rv = rv.Elem() if rv.IsNil() {
rt = rv.Type() // XXX ensure that typeByte 0 is reserved.
// If interface type, get typeInfo of underlying type. WriteTo([]byte("null"), w, n, err)
typeInfo = GetTypeInfo(rt) return
}
crv := rv.Elem() // concrete reflection value
crt := crv.Type() // concrete reflection type
if typeInfo.IsRegisteredInterface {
// See if the crt is registered.
// If so, we're more restrictive.
_, ok := typeInfo.ConcreteTypeBytes[crt]
if !ok {
switch crt.Kind() {
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))
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))
default:
*err = errors.New(Fmt("Unexpected type %v.", crt))
}
return
}
} else {
// We support writing unsafely for convenience.
}
// We don't have to write the typeByte here,
// the writeReflectJSON() call below will write it.
writeReflectJSON(crv, crt, w, n, err)
return
} }
// Dereference pointer
if rt.Kind() == reflect.Ptr { if rt.Kind() == reflect.Ptr {
rt = rt.Elem() // Dereference pointer
rv = rv.Elem() rv, rt = rv.Elem(), rt.Elem()
if !rv.IsValid() {
WriteTo([]byte("null"), w, n, err)
return
}
// continue...
} }
// Write TypeByte prefix // Write TypeByte
if typeInfo.HasTypeByte { if typeInfo.HasTypeByte {
WriteTo([]byte(Fmt("[%v,", typeInfo.TypeByte)), w, n, err) WriteTo([]byte(Fmt("[%v,", typeInfo.TypeByte)), w, n, err)
defer WriteTo([]byte("]"), w, n, err)
} }
// All other types
switch rt.Kind() { switch rt.Kind() {
case reflect.Slice: case reflect.Slice:
elemRt := rt.Elem() elemRt := rt.Elem()
@ -730,10 +818,4 @@ func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64,
panic(Fmt("Unknown field type %v", rt.Kind())) panic(Fmt("Unknown field type %v", rt.Kind()))
} }
// Write TypeByte close bracket
if typeInfo.HasTypeByte {
WriteTo([]byte("]"), w, n, err)
}
} }
//-----------------------------------------------------------------------------

View File

@ -120,13 +120,42 @@ func instantiateBasic() (interface{}, interface{}) {
func validateBasic(o interface{}, t *testing.T) { func validateBasic(o interface{}, t *testing.T) {
cat := o.(Cat) cat := o.(Cat)
if cat.String != "String" { if cat.String != "String" {
t.Errorf("Expected cat2.String == 'String', got %v", cat.String) t.Errorf("Expected cat.String == 'String', got %v", cat.String)
} }
if string(cat.Bytes) != "Bytes" { if string(cat.Bytes) != "Bytes" {
t.Errorf("Expected cat2.Bytes == 'Bytes', got %X", cat.Bytes) t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes)
} }
if cat.Time.Unix() != 123 { if cat.Time.Unix() != 123 {
t.Errorf("Expected cat2.Time == 'Unix(123)', got %v", cat.Time) t.Errorf("Expected cat.Time == 'Unix(123)', got %v", cat.Time)
}
}
//-------------------------------------
type NilTestStruct struct {
IntPtr *int
CatPtr *Cat
Animal Animal
}
func constructNilTestStruct() interface{} {
return NilTestStruct{}
}
func instantiateNilTestStruct() (interface{}, interface{}) {
return NilTestStruct{}, &NilTestStruct{}
}
func validateNilTestStruct(o interface{}, t *testing.T) {
nts := o.(NilTestStruct)
if nts.IntPtr != nil {
t.Errorf("Expected nts.IntPtr to be nil, got %v", nts.IntPtr)
}
if nts.CatPtr != nil {
t.Errorf("Expected nts.CatPtr to be nil, got %v", nts.CatPtr)
}
if nts.Animal != nil {
t.Errorf("Expected nts.Animal to be nil, got %v", nts.Animal)
} }
} }
@ -252,7 +281,7 @@ func constructComplexArray() interface{} {
Bytes: []byte("Bytes"), Bytes: []byte("Bytes"),
}, },
}, },
&Dog{ // Even though it's a *Dog, we'll get a Dog{} back. Dog{
SimpleStruct{ SimpleStruct{
String: "Woof", String: "Woof",
Bytes: []byte("Bark"), Bytes: []byte("Bark"),
@ -321,11 +350,14 @@ func init() {
testCases = append(testCases, TestCase{constructComplex, instantiateComplex, validateComplex}) testCases = append(testCases, TestCase{constructComplex, instantiateComplex, validateComplex})
testCases = append(testCases, TestCase{constructComplex2, instantiateComplex2, validateComplex2}) testCases = append(testCases, TestCase{constructComplex2, instantiateComplex2, validateComplex2})
testCases = append(testCases, TestCase{constructComplexArray, instantiateComplexArray, validateComplexArray}) testCases = append(testCases, TestCase{constructComplexArray, instantiateComplexArray, validateComplexArray})
testCases = append(testCases, TestCase{constructNilTestStruct, instantiateNilTestStruct, validateNilTestStruct})
} }
func TestBinary(t *testing.T) { func TestBinary(t *testing.T) {
for _, testCase := range testCases { for i, testCase := range testCases {
log.Info(fmt.Sprintf("Running test case %v", i))
// Construct an object // Construct an object
o := testCase.Constructor() o := testCase.Constructor()
@ -340,7 +372,7 @@ func TestBinary(t *testing.T) {
n, err := new(int64), new(error) n, err := new(int64), new(error)
res := ReadBinary(instance, bytes.NewReader(data), n, err) res := ReadBinary(instance, bytes.NewReader(data), n, err)
if *err != nil { if *err != nil {
t.Fatalf("Failed to read cat: %v", *err) t.Fatalf("Failed to read into instance: %v", *err)
} }
// Validate object // Validate object
@ -350,7 +382,7 @@ func TestBinary(t *testing.T) {
n, err = new(int64), new(error) n, err = new(int64), new(error)
res = ReadBinary(instancePtr, bytes.NewReader(data), n, err) res = ReadBinary(instancePtr, bytes.NewReader(data), n, err)
if *err != nil { if *err != nil {
t.Fatalf("Failed to read cat: %v", *err) t.Fatalf("Failed to read into instance: %v", *err)
} }
if res != instancePtr { if res != instancePtr {
@ -365,7 +397,9 @@ func TestBinary(t *testing.T) {
func TestJSON(t *testing.T) { func TestJSON(t *testing.T) {
for _, testCase := range testCases { for i, testCase := range testCases {
log.Info(fmt.Sprintf("Running test case %v", i))
// Construct an object // Construct an object
o := testCase.Constructor() o := testCase.Constructor()

View File

@ -10,7 +10,7 @@ func BinaryBytes(o interface{}) []byte {
w, n, err := new(bytes.Buffer), new(int64), new(error) w, n, err := new(bytes.Buffer), new(int64), new(error)
WriteBinary(o, w, n, err) WriteBinary(o, w, n, err)
if *err != nil { if *err != nil {
panic(err) panic(*err)
} }
return w.Bytes() return w.Bytes()
} }
@ -19,7 +19,7 @@ func JSONBytes(o interface{}) []byte {
w, n, err := new(bytes.Buffer), new(int64), new(error) w, n, err := new(bytes.Buffer), new(int64), new(error)
WriteJSON(o, w, n, err) WriteJSON(o, w, n, err)
if *err != nil { if *err != nil {
panic(err) panic(*err)
} }
return w.Bytes() return w.Bytes()
} }
@ -42,7 +42,7 @@ func BinarySha256(o interface{}) []byte {
hasher, n, err := sha256.New(), new(int64), new(error) hasher, n, err := sha256.New(), new(int64), new(error)
WriteBinary(o, hasher, n, err) WriteBinary(o, hasher, n, err)
if *err != nil { if *err != nil {
panic(err) panic(*err)
} }
return hasher.Sum(nil) return hasher.Sum(nil)
} }
@ -51,7 +51,7 @@ func BinaryRipemd160(o interface{}) []byte {
hasher, n, err := ripemd160.New(), new(int64), new(error) hasher, n, err := ripemd160.New(), new(int64), new(error)
WriteBinary(o, hasher, n, err) WriteBinary(o, hasher, n, err)
if *err != nil { if *err != nil {
panic(err) panic(*err)
} }
return hasher.Sum(nil) return hasher.Sum(nil)
} }

View File

@ -202,7 +202,7 @@ func TestReadWrite(t *testing.T) {
// Read from buffer. // Read from buffer.
pol2 := binary.ReadBinary(&POL{}, buf, n, err).(*POL) pol2 := binary.ReadBinary(&POL{}, buf, n, err).(*POL)
if *err != nil { if *err != nil {
t.Fatalf("Failed to read POL") t.Fatalf("Failed to read POL: %v", *err)
} }
// Check that validation succeeds. // Check that validation succeeds.

View File

@ -123,7 +123,7 @@ func (memR *MempoolReactor) SetEventSwitch(evsw *events.EventSwitch) {
const ( const (
msgTypeUnknown = byte(0x00) msgTypeUnknown = byte(0x00)
msgTypeTx = byte(0x10) msgTypeTx = byte(0x01)
) )
// TODO: check for unnecessary extra bytes at the end. // TODO: check for unnecessary extra bytes at the end.

View File

@ -152,7 +152,8 @@ func (n *Node) StartRPC() {
mux := http.NewServeMux() mux := http.NewServeMux()
rpc.RegisterEventsHandler(mux, n.evsw) rpc.RegisterEventsHandler(mux, n.evsw)
rpc.RegisterRPCFuncs(mux, core.Routes) rpc.RegisterRPCFuncs(mux, core.Routes)
rpc.StartHTTPServer(listenAddr, mux) handler := rpc.AuthenticateHandler(mux)
rpc.StartHTTPServer(listenAddr, handler)
} }
func (n *Node) Switch() *p2p.Switch { func (n *Node) Switch() *p2p.Switch {

View File

@ -588,9 +588,9 @@ func (ch *Channel) updateStats() {
const ( const (
maxMsgPacketSize = 1024 maxMsgPacketSize = 1024
packetTypePing = byte(0x00) packetTypePing = byte(0x01)
packetTypePong = byte(0x01) packetTypePong = byte(0x02)
packetTypeMsg = byte(0x10) packetTypeMsg = byte(0x03)
) )
// Messages in channels are chopped into smaller msgPackets for multiplexing. // Messages in channels are chopped into smaller msgPackets for multiplexing.

View File

@ -17,7 +17,7 @@ func GetAccount(address []byte) (*ctypes.ResponseGetAccount, error) {
if account == nil { if account == nil {
account = &acm.Account{ account = &acm.Account{
Address: address, Address: address,
PubKey: acm.PubKeyNil{}, PubKey: nil,
Sequence: 0, Sequence: 0,
Balance: 0, Balance: 0,
Code: nil, Code: nil,

View File

@ -18,7 +18,7 @@ type Client interface {
BroadcastTx(tx types.Tx) (*ctypes.ResponseBroadcastTx, error) BroadcastTx(tx types.Tx) (*ctypes.ResponseBroadcastTx, error)
Call(address []byte, data []byte) (*ctypes.ResponseCall, error) Call(address []byte, data []byte) (*ctypes.ResponseCall, error)
CallCode(code []byte, data []byte) (*ctypes.ResponseCall, error) CallCode(code []byte, data []byte) (*ctypes.ResponseCall, error)
DumpStorage(addr []byte) (*ctypes.ResponseDumpStorage, error) DumpStorage(address []byte) (*ctypes.ResponseDumpStorage, error)
GenPrivAccount() (*ctypes.ResponseGenPrivAccount, error) GenPrivAccount() (*ctypes.ResponseGenPrivAccount, error)
GetAccount(address []byte) (*ctypes.ResponseGetAccount, error) GetAccount(address []byte) (*ctypes.ResponseGetAccount, error)
GetBlock(height uint) (*ctypes.ResponseGetBlock, error) GetBlock(height uint) (*ctypes.ResponseGetBlock, error)
@ -150,8 +150,8 @@ func (c *ClientHTTP) CallCode(code []byte, data []byte) (*ctypes.ResponseCall, e
return response.Result, nil return response.Result, nil
} }
func (c *ClientHTTP) DumpStorage(addr []byte) (*ctypes.ResponseDumpStorage, error) { func (c *ClientHTTP) DumpStorage(address []byte) (*ctypes.ResponseDumpStorage, error) {
values, err := argsToURLValues([]string{"addr"}, addr) values, err := argsToURLValues([]string{"address"}, address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -558,11 +558,11 @@ func (c *ClientJSON) CallCode(code []byte, data []byte) (*ctypes.ResponseCall, e
return response.Result, nil return response.Result, nil
} }
func (c *ClientJSON) DumpStorage(addr []byte) (*ctypes.ResponseDumpStorage, error) { func (c *ClientJSON) DumpStorage(address []byte) (*ctypes.ResponseDumpStorage, error) {
request := rpc.RPCRequest{ request := rpc.RPCRequest{
JSONRPC: "2.0", JSONRPC: "2.0",
Method: reverseFuncMap["DumpStorage"], Method: reverseFuncMap["DumpStorage"],
Params: []interface{}{addr}, Params: []interface{}{address},
Id: 0, Id: 0,
} }
body, err := c.RequestResponse(request) body, err := c.RequestResponse(request)

View File

@ -101,6 +101,7 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc) http.HandlerFunc {
return return
} }
returns := rpcFunc.f.Call(args) returns := rpcFunc.f.Call(args)
log.Debug("HTTPJSONRPC", "method", request.Method, "args", args, "returns", returns)
response, err := unreflectResponse(returns) response, err := unreflectResponse(returns)
if err != nil { if err != nil {
WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) WriteRPCResponse(w, NewRPCResponse(nil, err.Error()))
@ -148,6 +149,7 @@ func makeHTTPHandler(rpcFunc *RPCFunc) func(http.ResponseWriter, *http.Request)
return return
} }
returns := rpcFunc.f.Call(args) returns := rpcFunc.f.Call(args)
log.Debug("HTTPRestRPC", "method", r.URL.Path, "args", args, "returns", returns)
response, err := unreflectResponse(returns) response, err := unreflectResponse(returns)
if err != nil { if err != nil {
WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) WriteRPCResponse(w, NewRPCResponse(nil, err.Error()))

View File

@ -4,6 +4,7 @@ package rpc
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"runtime/debug" "runtime/debug"
"time" "time"
@ -12,12 +13,12 @@ import (
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
) )
func StartHTTPServer(listenAddr string, mux *http.ServeMux) { func StartHTTPServer(listenAddr string, handler http.Handler) {
log.Info(Fmt("Starting RPC HTTP server on %s", listenAddr)) log.Info(Fmt("Starting RPC HTTP server on %s", listenAddr))
go func() { go func() {
res := http.ListenAndServe( res := http.ListenAndServe(
listenAddr, listenAddr,
RecoverAndLogHandler(mux), RecoverAndLogHandler(handler),
) )
log.Crit("RPC HTTPServer stopped", "result", res) log.Crit("RPC HTTPServer stopped", "result", res)
}() }()
@ -37,8 +38,40 @@ func WriteRPCResponse(w http.ResponseWriter, res RPCResponse) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func AuthenticateHandler(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// from https://medium.com/@xoen/golang-read-from-an-io-readwriter-without-loosing-its-content-2c6911805361
// Read the content
var bodyBytes []byte
if r.Body != nil {
bodyBytes, _ = ioutil.ReadAll(r.Body)
}
// Restore the io.ReadCloser to its original state
r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
// Get body string
bodyString := string(bodyBytes)
// Also read the path+"?"+query
pathQuery := Fmt("%v?%v", r.URL.Path, r.URL.RawQuery)
// Concatenate into tuple
tuple := struct {
Body string
Path string
}{bodyString, pathQuery}
// Get sign bytes
signBytes := binary.BinaryBytes(tuple)
// Validate the sign bytes.
// XXX
log.Debug("Should sign", "bytes", signBytes)
// If validation fails
// XXX
// If validation passes
handler.ServeHTTP(w, r)
})
}
//-----------------------------------------------------------------------------
// Wraps an HTTP handler, adding error logging. // Wraps an HTTP handler, adding error logging.
//
// If the inner function panics, the outer function recovers, logs, sends an // If the inner function panics, the outer function recovers, logs, sends an
// HTTP 500 error response. // HTTP 500 error response.
func RecoverAndLogHandler(handler http.Handler) http.Handler { func RecoverAndLogHandler(handler http.Handler) http.Handler {

View File

@ -258,7 +258,7 @@ func checkTx(t *testing.T, fromAddr []byte, priv *account.PrivAccount, tx *types
} }
// Check signatures // Check signatures
// acc := getAccount(t, byteAddr) // acc := getAccount(t, byteAddr)
// NOTE: using the acc here instead of the in fails; its PubKeyNil ... ? // NOTE: using the acc here instead of the in fails; it is nil.
if !in.PubKey.VerifyBytes(signBytes, in.Signature) { if !in.PubKey.VerifyBytes(signBytes, in.Signature) {
t.Fatal(types.ErrTxInvalidSignature) t.Fatal(types.ErrTxInvalidSignature)
} }

View File

@ -159,9 +159,9 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade
} }
// The accounts from the TxInputs must either already have // The accounts from the TxInputs must either already have
// account.PubKey.(type) != PubKeyNil, (it must be known), // account.PubKey.(type) != nil, (it must be known),
// or it must be specified in the TxInput. If redeclared, // or it must be specified in the TxInput. If redeclared,
// the TxInput is modified and input.PubKey set to PubKeyNil. // the TxInput is modified and input.PubKey set to nil.
func getOrMakeAccounts(state AccountGetter, ins []*types.TxInput, outs []*types.TxOutput) (map[string]*account.Account, error) { func getOrMakeAccounts(state AccountGetter, ins []*types.TxInput, outs []*types.TxOutput) (map[string]*account.Account, error) {
accounts := map[string]*account.Account{} accounts := map[string]*account.Account{}
for _, in := range ins { for _, in := range ins {
@ -189,7 +189,7 @@ func getOrMakeAccounts(state AccountGetter, ins []*types.TxInput, outs []*types.
if acc == nil { if acc == nil {
acc = &account.Account{ acc = &account.Account{
Address: out.Address, Address: out.Address,
PubKey: account.PubKeyNil{}, PubKey: nil,
Sequence: 0, Sequence: 0,
Balance: 0, Balance: 0,
} }
@ -200,8 +200,8 @@ func getOrMakeAccounts(state AccountGetter, ins []*types.TxInput, outs []*types.
} }
func checkInputPubKey(acc *account.Account, in *types.TxInput) error { func checkInputPubKey(acc *account.Account, in *types.TxInput) error {
if _, isNil := acc.PubKey.(account.PubKeyNil); isNil { if acc.PubKey == nil {
if _, isNil := in.PubKey.(account.PubKeyNil); isNil { if in.PubKey == nil {
return types.ErrTxUnknownPubKey return types.ErrTxUnknownPubKey
} }
if !bytes.Equal(in.PubKey.Address(), acc.Address) { if !bytes.Equal(in.PubKey.Address(), acc.Address) {
@ -209,7 +209,7 @@ func checkInputPubKey(acc *account.Account, in *types.TxInput) error {
} }
acc.PubKey = in.PubKey acc.PubKey = in.PubKey
} else { } else {
in.PubKey = account.PubKeyNil{} in.PubKey = nil
} }
return nil return nil
} }

View File

@ -61,7 +61,7 @@ func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State {
for _, genAcc := range genDoc.Accounts { for _, genAcc := range genDoc.Accounts {
acc := &account.Account{ acc := &account.Account{
Address: genAcc.Address, Address: genAcc.Address,
PubKey: account.PubKeyNil{}, PubKey: nil,
Sequence: 0, Sequence: 0,
Balance: genAcc.Amount, Balance: genAcc.Amount,
} }

View File

@ -163,7 +163,7 @@ func toVMAccount(acc *ac.Account) *vm.Account {
func toStateAccount(acc *vm.Account) *ac.Account { func toStateAccount(acc *vm.Account) *ac.Account {
pubKey, ok := acc.Other.(ac.PubKey) pubKey, ok := acc.Other.(ac.PubKey)
if !ok { if !ok {
pubKey = ac.PubKeyNil{} pubKey = nil
} }
var storageRoot []byte var storageRoot []byte
if acc.StorageRoot.IsZero() { if acc.StorageRoot.IsZero() {

View File

@ -76,7 +76,7 @@ type TxInput struct {
Amount uint64 // Must not exceed account balance Amount uint64 // Must not exceed account balance
Sequence uint // Must be 1 greater than the last committed TxInput Sequence uint // Must be 1 greater than the last committed TxInput
Signature account.Signature // Depends on the PubKey type and the whole Tx Signature account.Signature // Depends on the PubKey type and the whole Tx
PubKey account.PubKey // Must not be nil, may be PubKeyNil. PubKey account.PubKey // Must not be nil, may be nil
} }
func (txIn *TxInput) ValidateBasic() error { func (txIn *TxInput) ValidateBasic() error {

View File

@ -40,9 +40,9 @@ type Vote struct {
// Types of votes // Types of votes
const ( const (
VoteTypePrevote = byte(0x00) VoteTypePrevote = byte(0x01)
VoteTypePrecommit = byte(0x01) VoteTypePrecommit = byte(0x02)
VoteTypeCommit = byte(0x02) VoteTypeCommit = byte(0x03)
) )
func (vote *Vote) WriteSignBytes(w io.Writer, n *int64, err *error) { func (vote *Vote) WriteSignBytes(w io.Writer, n *int64, err *error) {