|
|
@ -21,22 +21,18 @@ func TestStreamKind(t *testing.T) { |
|
|
|
{"7F", Byte, 0}, |
|
|
|
{"7F", Byte, 0}, |
|
|
|
{"80", String, 0}, |
|
|
|
{"80", String, 0}, |
|
|
|
{"B7", String, 55}, |
|
|
|
{"B7", String, 55}, |
|
|
|
{"B800", String, 0}, |
|
|
|
|
|
|
|
{"B90400", String, 1024}, |
|
|
|
{"B90400", String, 1024}, |
|
|
|
{"BA000400", String, 1024}, |
|
|
|
|
|
|
|
{"BB00000400", String, 1024}, |
|
|
|
|
|
|
|
{"BFFFFFFFFFFFFFFFFF", String, ^uint64(0)}, |
|
|
|
{"BFFFFFFFFFFFFFFFFF", String, ^uint64(0)}, |
|
|
|
{"C0", List, 0}, |
|
|
|
{"C0", List, 0}, |
|
|
|
{"C8", List, 8}, |
|
|
|
{"C8", List, 8}, |
|
|
|
{"F7", List, 55}, |
|
|
|
{"F7", List, 55}, |
|
|
|
{"F800", List, 0}, |
|
|
|
|
|
|
|
{"F804", List, 4}, |
|
|
|
|
|
|
|
{"F90400", List, 1024}, |
|
|
|
{"F90400", List, 1024}, |
|
|
|
{"FFFFFFFFFFFFFFFFFF", List, ^uint64(0)}, |
|
|
|
{"FFFFFFFFFFFFFFFFFF", List, ^uint64(0)}, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for i, test := range tests { |
|
|
|
for i, test := range tests { |
|
|
|
s := NewStream(bytes.NewReader(unhex(test.input))) |
|
|
|
// using plainReader to inhibit input limit errors.
|
|
|
|
|
|
|
|
s := NewStream(newPlainReader(unhex(test.input)), 0) |
|
|
|
kind, len, err := s.Kind() |
|
|
|
kind, len, err := s.Kind() |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
t.Errorf("test %d: Kind returned error: %v", i, err) |
|
|
|
t.Errorf("test %d: Kind returned error: %v", i, err) |
|
|
@ -70,29 +66,85 @@ func TestNewListStream(t *testing.T) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestStreamErrors(t *testing.T) { |
|
|
|
func TestStreamErrors(t *testing.T) { |
|
|
|
|
|
|
|
withoutInputLimit := func(b []byte) *Stream { |
|
|
|
|
|
|
|
return NewStream(newPlainReader(b), 0) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
withCustomInputLimit := func(limit uint64) func([]byte) *Stream { |
|
|
|
|
|
|
|
return func(b []byte) *Stream { |
|
|
|
|
|
|
|
return NewStream(bytes.NewReader(b), limit) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type calls []string |
|
|
|
type calls []string |
|
|
|
tests := []struct { |
|
|
|
tests := []struct { |
|
|
|
string |
|
|
|
string |
|
|
|
calls |
|
|
|
calls |
|
|
|
error |
|
|
|
newStream func([]byte) *Stream // uses bytes.Reader if nil
|
|
|
|
|
|
|
|
error error |
|
|
|
}{ |
|
|
|
}{ |
|
|
|
{"", calls{"Kind"}, io.EOF}, |
|
|
|
{"C0", calls{"Bytes"}, nil, ErrExpectedString}, |
|
|
|
{"", calls{"List"}, io.EOF}, |
|
|
|
{"C0", calls{"Uint"}, nil, ErrExpectedString}, |
|
|
|
{"", calls{"Uint"}, io.EOF}, |
|
|
|
{"89000000000000000001", calls{"Uint"}, nil, errUintOverflow}, |
|
|
|
{"C0", calls{"Bytes"}, ErrExpectedString}, |
|
|
|
{"00", calls{"List"}, nil, ErrExpectedList}, |
|
|
|
{"C0", calls{"Uint"}, ErrExpectedString}, |
|
|
|
{"80", calls{"List"}, nil, ErrExpectedList}, |
|
|
|
{"81", calls{"Bytes"}, io.ErrUnexpectedEOF}, |
|
|
|
{"C0", calls{"List", "Uint"}, nil, EOL}, |
|
|
|
{"81", calls{"Uint"}, io.ErrUnexpectedEOF}, |
|
|
|
{"C8C9010101010101010101", calls{"List", "Kind"}, nil, ErrElemTooLarge}, |
|
|
|
{"BFFFFFFFFFFFFFFF", calls{"Bytes"}, io.ErrUnexpectedEOF}, |
|
|
|
{"C3C2010201", calls{"List", "List", "Uint", "Uint", "ListEnd", "Uint"}, nil, EOL}, |
|
|
|
{"89000000000000000001", calls{"Uint"}, errUintOverflow}, |
|
|
|
{"00", calls{"ListEnd"}, nil, errNotInList}, |
|
|
|
{"00", calls{"List"}, ErrExpectedList}, |
|
|
|
{"C401020304", calls{"List", "Uint", "ListEnd"}, nil, errNotAtEOL}, |
|
|
|
{"80", calls{"List"}, ErrExpectedList}, |
|
|
|
|
|
|
|
{"C0", calls{"List", "Uint"}, EOL}, |
|
|
|
// Non-canonical integers (e.g. leading zero bytes).
|
|
|
|
{"C801", calls{"List", "Uint", "Uint"}, io.ErrUnexpectedEOF}, |
|
|
|
{"00", calls{"Uint"}, nil, ErrCanonInt}, |
|
|
|
{"C8C9", calls{"List", "Kind"}, ErrElemTooLarge}, |
|
|
|
{"820002", calls{"Uint"}, nil, ErrCanonInt}, |
|
|
|
{"C3C2010201", calls{"List", "List", "Uint", "Uint", "ListEnd", "Uint"}, EOL}, |
|
|
|
{"8133", calls{"Uint"}, nil, ErrCanonSize}, |
|
|
|
{"00", calls{"ListEnd"}, errNotInList}, |
|
|
|
{"8156", calls{"Uint"}, nil, nil}, |
|
|
|
{"C40102", calls{"List", "Uint", "ListEnd"}, errNotAtEOL}, |
|
|
|
|
|
|
|
|
|
|
|
// Size tags must use the smallest possible encoding.
|
|
|
|
|
|
|
|
// Leading zero bytes in the size tag are also rejected.
|
|
|
|
|
|
|
|
{"8100", calls{"Uint"}, nil, ErrCanonSize}, |
|
|
|
|
|
|
|
{"8100", calls{"Bytes"}, nil, ErrCanonSize}, |
|
|
|
|
|
|
|
{"B800", calls{"Kind"}, withoutInputLimit, ErrCanonSize}, |
|
|
|
|
|
|
|
{"B90000", calls{"Kind"}, withoutInputLimit, ErrCanonSize}, |
|
|
|
|
|
|
|
{"B90055", calls{"Kind"}, withoutInputLimit, ErrCanonSize}, |
|
|
|
|
|
|
|
{"BA0002FFFF", calls{"Bytes"}, withoutInputLimit, ErrCanonSize}, |
|
|
|
|
|
|
|
{"F800", calls{"Kind"}, withoutInputLimit, ErrCanonSize}, |
|
|
|
|
|
|
|
{"F90000", calls{"Kind"}, withoutInputLimit, ErrCanonSize}, |
|
|
|
|
|
|
|
{"F90055", calls{"Kind"}, withoutInputLimit, ErrCanonSize}, |
|
|
|
|
|
|
|
{"FA0002FFFF", calls{"List"}, withoutInputLimit, ErrCanonSize}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Expected EOF
|
|
|
|
|
|
|
|
{"", calls{"Kind"}, nil, io.EOF}, |
|
|
|
|
|
|
|
{"", calls{"Uint"}, nil, io.EOF}, |
|
|
|
|
|
|
|
{"", calls{"List"}, nil, io.EOF}, |
|
|
|
|
|
|
|
{"8158", calls{"Uint", "Uint"}, nil, io.EOF}, |
|
|
|
|
|
|
|
{"C0", calls{"List", "ListEnd", "List"}, nil, io.EOF}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Input limit errors.
|
|
|
|
|
|
|
|
{"81", calls{"Bytes"}, nil, ErrValueTooLarge}, |
|
|
|
|
|
|
|
{"81", calls{"Uint"}, nil, ErrValueTooLarge}, |
|
|
|
|
|
|
|
{"81", calls{"Raw"}, nil, ErrValueTooLarge}, |
|
|
|
|
|
|
|
{"BFFFFFFFFFFFFFFFFFFF", calls{"Bytes"}, nil, ErrValueTooLarge}, |
|
|
|
|
|
|
|
{"C801", calls{"List"}, nil, ErrValueTooLarge}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Test for list element size check overflow.
|
|
|
|
|
|
|
|
{"CD04040404FFFFFFFFFFFFFFFFFF0303", calls{"List", "Uint", "Uint", "Uint", "Uint", "List"}, nil, ErrElemTooLarge}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Test for input limit overflow. Since we are counting the limit
|
|
|
|
|
|
|
|
// down toward zero in Stream.remaining, reading too far can overflow
|
|
|
|
|
|
|
|
// remaining to a large value, effectively disabling the limit.
|
|
|
|
|
|
|
|
{"C40102030401", calls{"Raw", "Uint"}, withCustomInputLimit(5), io.EOF}, |
|
|
|
|
|
|
|
{"C4010203048158", calls{"Raw", "Uint"}, withCustomInputLimit(6), ErrValueTooLarge}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check that the same calls are fine without a limit.
|
|
|
|
|
|
|
|
{"C40102030401", calls{"Raw", "Uint"}, withoutInputLimit, nil}, |
|
|
|
|
|
|
|
{"C4010203048158", calls{"Raw", "Uint"}, withoutInputLimit, nil}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Unexpected EOF. This only happens when there is
|
|
|
|
|
|
|
|
// no input limit, so the reader needs to be 'dumbed down'.
|
|
|
|
|
|
|
|
{"81", calls{"Bytes"}, withoutInputLimit, io.ErrUnexpectedEOF}, |
|
|
|
|
|
|
|
{"81", calls{"Uint"}, withoutInputLimit, io.ErrUnexpectedEOF}, |
|
|
|
|
|
|
|
{"BFFFFFFFFFFFFFFF", calls{"Bytes"}, withoutInputLimit, io.ErrUnexpectedEOF}, |
|
|
|
|
|
|
|
{"C801", calls{"List", "Uint", "Uint"}, withoutInputLimit, io.ErrUnexpectedEOF}, |
|
|
|
|
|
|
|
|
|
|
|
// This test verifies that the input position is advanced
|
|
|
|
// This test verifies that the input position is advanced
|
|
|
|
// correctly when calling Bytes for empty strings. Kind can be called
|
|
|
|
// correctly when calling Bytes for empty strings. Kind can be called
|
|
|
@ -109,12 +161,15 @@ func TestStreamErrors(t *testing.T) { |
|
|
|
|
|
|
|
|
|
|
|
"Bytes", // past final element
|
|
|
|
"Bytes", // past final element
|
|
|
|
"Bytes", // this one should fail
|
|
|
|
"Bytes", // this one should fail
|
|
|
|
}, EOL}, |
|
|
|
}, nil, EOL}, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
testfor: |
|
|
|
testfor: |
|
|
|
for i, test := range tests { |
|
|
|
for i, test := range tests { |
|
|
|
s := NewStream(bytes.NewReader(unhex(test.string))) |
|
|
|
if test.newStream == nil { |
|
|
|
|
|
|
|
test.newStream = func(b []byte) *Stream { return NewStream(bytes.NewReader(b), 0) } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
s := test.newStream(unhex(test.string)) |
|
|
|
rs := reflect.ValueOf(s) |
|
|
|
rs := reflect.ValueOf(s) |
|
|
|
for j, call := range test.calls { |
|
|
|
for j, call := range test.calls { |
|
|
|
fval := rs.MethodByName(call) |
|
|
|
fval := rs.MethodByName(call) |
|
|
@ -124,11 +179,17 @@ testfor: |
|
|
|
err = lastret.(error).Error() |
|
|
|
err = lastret.(error).Error() |
|
|
|
} |
|
|
|
} |
|
|
|
if j == len(test.calls)-1 { |
|
|
|
if j == len(test.calls)-1 { |
|
|
|
if err != test.error.Error() { |
|
|
|
want := "<nil>" |
|
|
|
t.Errorf("test %d: last call (%s) error mismatch\ngot: %s\nwant: %v", |
|
|
|
if test.error != nil { |
|
|
|
|
|
|
|
want = test.error.Error() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if err != want { |
|
|
|
|
|
|
|
t.Log(test) |
|
|
|
|
|
|
|
t.Errorf("test %d: last call (%s) error mismatch\ngot: %s\nwant: %s", |
|
|
|
i, call, err, test.error) |
|
|
|
i, call, err, test.error) |
|
|
|
} |
|
|
|
} |
|
|
|
} else if err != "<nil>" { |
|
|
|
} else if err != "<nil>" { |
|
|
|
|
|
|
|
t.Log(test) |
|
|
|
t.Errorf("test %d: call %d (%s) unexpected error: %q", i, j, call, err) |
|
|
|
t.Errorf("test %d: call %d (%s) unexpected error: %q", i, j, call, err) |
|
|
|
continue testfor |
|
|
|
continue testfor |
|
|
|
} |
|
|
|
} |
|
|
@ -137,7 +198,7 @@ testfor: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestStreamList(t *testing.T) { |
|
|
|
func TestStreamList(t *testing.T) { |
|
|
|
s := NewStream(bytes.NewReader(unhex("C80102030405060708"))) |
|
|
|
s := NewStream(bytes.NewReader(unhex("C80102030405060708")), 0) |
|
|
|
|
|
|
|
|
|
|
|
len, err := s.List() |
|
|
|
len, err := s.List() |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
@ -166,7 +227,7 @@ func TestStreamList(t *testing.T) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestStreamRaw(t *testing.T) { |
|
|
|
func TestStreamRaw(t *testing.T) { |
|
|
|
s := NewStream(bytes.NewReader(unhex("C58401010101"))) |
|
|
|
s := NewStream(bytes.NewReader(unhex("C58401010101")), 0) |
|
|
|
s.List() |
|
|
|
s.List() |
|
|
|
|
|
|
|
|
|
|
|
want := unhex("8401010101") |
|
|
|
want := unhex("8401010101") |
|
|
@ -219,7 +280,7 @@ type simplestruct struct { |
|
|
|
|
|
|
|
|
|
|
|
type recstruct struct { |
|
|
|
type recstruct struct { |
|
|
|
I uint |
|
|
|
I uint |
|
|
|
Child *recstruct |
|
|
|
Child *recstruct `rlp:"nil"` |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
@ -229,78 +290,58 @@ var ( |
|
|
|
) |
|
|
|
) |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
sharedByteArray [5]byte |
|
|
|
|
|
|
|
sharedPtr = new(*uint) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var decodeTests = []decodeTest{ |
|
|
|
var decodeTests = []decodeTest{ |
|
|
|
// integers
|
|
|
|
// integers
|
|
|
|
{input: "05", ptr: new(uint32), value: uint32(5)}, |
|
|
|
{input: "05", ptr: new(uint32), value: uint32(5)}, |
|
|
|
{input: "80", ptr: new(uint32), value: uint32(0)}, |
|
|
|
{input: "80", ptr: new(uint32), value: uint32(0)}, |
|
|
|
{input: "8105", ptr: new(uint32), value: uint32(5)}, |
|
|
|
|
|
|
|
{input: "820505", ptr: new(uint32), value: uint32(0x0505)}, |
|
|
|
{input: "820505", ptr: new(uint32), value: uint32(0x0505)}, |
|
|
|
{input: "83050505", ptr: new(uint32), value: uint32(0x050505)}, |
|
|
|
{input: "83050505", ptr: new(uint32), value: uint32(0x050505)}, |
|
|
|
{input: "8405050505", ptr: new(uint32), value: uint32(0x05050505)}, |
|
|
|
{input: "8405050505", ptr: new(uint32), value: uint32(0x05050505)}, |
|
|
|
{input: "850505050505", ptr: new(uint32), error: "rlp: input string too long for uint32"}, |
|
|
|
{input: "850505050505", ptr: new(uint32), error: "rlp: input string too long for uint32"}, |
|
|
|
{input: "C0", ptr: new(uint32), error: "rlp: expected input string or byte for uint32"}, |
|
|
|
{input: "C0", ptr: new(uint32), error: "rlp: expected input string or byte for uint32"}, |
|
|
|
|
|
|
|
{input: "00", ptr: new(uint32), error: "rlp: non-canonical integer (leading zero bytes) for uint32"}, |
|
|
|
|
|
|
|
{input: "8105", ptr: new(uint32), error: "rlp: non-canonical size information for uint32"}, |
|
|
|
|
|
|
|
{input: "820004", ptr: new(uint32), error: "rlp: non-canonical integer (leading zero bytes) for uint32"}, |
|
|
|
|
|
|
|
{input: "B8020004", ptr: new(uint32), error: "rlp: non-canonical size information for uint32"}, |
|
|
|
|
|
|
|
|
|
|
|
// slices
|
|
|
|
// slices
|
|
|
|
{input: "C0", ptr: new([]uint), value: []uint{}}, |
|
|
|
{input: "C0", ptr: new([]uint), value: []uint{}}, |
|
|
|
{input: "C80102030405060708", ptr: new([]uint), value: []uint{1, 2, 3, 4, 5, 6, 7, 8}}, |
|
|
|
{input: "C80102030405060708", ptr: new([]uint), value: []uint{1, 2, 3, 4, 5, 6, 7, 8}}, |
|
|
|
|
|
|
|
{input: "F8020004", ptr: new([]uint), error: "rlp: non-canonical size information for []uint"}, |
|
|
|
|
|
|
|
|
|
|
|
// arrays
|
|
|
|
// arrays
|
|
|
|
{input: "C0", ptr: new([5]uint), value: [5]uint{}}, |
|
|
|
|
|
|
|
{input: "C50102030405", ptr: new([5]uint), value: [5]uint{1, 2, 3, 4, 5}}, |
|
|
|
{input: "C50102030405", ptr: new([5]uint), value: [5]uint{1, 2, 3, 4, 5}}, |
|
|
|
|
|
|
|
{input: "C0", ptr: new([5]uint), error: "rlp: input list has too few elements for [5]uint"}, |
|
|
|
|
|
|
|
{input: "C102", ptr: new([5]uint), error: "rlp: input list has too few elements for [5]uint"}, |
|
|
|
{input: "C6010203040506", ptr: new([5]uint), error: "rlp: input list has too many elements for [5]uint"}, |
|
|
|
{input: "C6010203040506", ptr: new([5]uint), error: "rlp: input list has too many elements for [5]uint"}, |
|
|
|
|
|
|
|
{input: "F8020004", ptr: new([5]uint), error: "rlp: non-canonical size information for [5]uint"}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// zero sized arrays
|
|
|
|
|
|
|
|
{input: "C0", ptr: new([0]uint), value: [0]uint{}}, |
|
|
|
|
|
|
|
{input: "C101", ptr: new([0]uint), error: "rlp: input list has too many elements for [0]uint"}, |
|
|
|
|
|
|
|
|
|
|
|
// byte slices
|
|
|
|
// byte slices
|
|
|
|
{input: "01", ptr: new([]byte), value: []byte{1}}, |
|
|
|
{input: "01", ptr: new([]byte), value: []byte{1}}, |
|
|
|
{input: "80", ptr: new([]byte), value: []byte{}}, |
|
|
|
{input: "80", ptr: new([]byte), value: []byte{}}, |
|
|
|
{input: "8D6162636465666768696A6B6C6D", ptr: new([]byte), value: []byte("abcdefghijklm")}, |
|
|
|
{input: "8D6162636465666768696A6B6C6D", ptr: new([]byte), value: []byte("abcdefghijklm")}, |
|
|
|
{input: "C0", ptr: new([]byte), value: []byte{}}, |
|
|
|
{input: "C0", ptr: new([]byte), error: "rlp: expected input string or byte for []uint8"}, |
|
|
|
{input: "C3010203", ptr: new([]byte), value: []byte{1, 2, 3}}, |
|
|
|
{input: "8105", ptr: new([]byte), error: "rlp: non-canonical size information for []uint8"}, |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
input: "C3820102", |
|
|
|
|
|
|
|
ptr: new([]byte), |
|
|
|
|
|
|
|
error: "rlp: input string too long for uint8, decoding into ([]uint8)[0]", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// byte arrays
|
|
|
|
// byte arrays
|
|
|
|
{input: "01", ptr: new([5]byte), value: [5]byte{1}}, |
|
|
|
{input: "02", ptr: new([1]byte), value: [1]byte{2}}, |
|
|
|
{input: "80", ptr: new([5]byte), value: [5]byte{}}, |
|
|
|
|
|
|
|
{input: "850102030405", ptr: new([5]byte), value: [5]byte{1, 2, 3, 4, 5}}, |
|
|
|
{input: "850102030405", ptr: new([5]byte), value: [5]byte{1, 2, 3, 4, 5}}, |
|
|
|
{input: "C0", ptr: new([5]byte), value: [5]byte{}}, |
|
|
|
|
|
|
|
{input: "C3010203", ptr: new([5]byte), value: [5]byte{1, 2, 3, 0, 0}}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
// byte array errors
|
|
|
|
input: "C3820102", |
|
|
|
{input: "02", ptr: new([5]byte), error: "rlp: input string too short for [5]uint8"}, |
|
|
|
ptr: new([5]byte), |
|
|
|
{input: "80", ptr: new([5]byte), error: "rlp: input string too short for [5]uint8"}, |
|
|
|
error: "rlp: input string too long for uint8, decoding into ([5]uint8)[0]", |
|
|
|
{input: "820000", ptr: new([5]byte), error: "rlp: input string too short for [5]uint8"}, |
|
|
|
}, |
|
|
|
{input: "C0", ptr: new([5]byte), error: "rlp: expected input string or byte for [5]uint8"}, |
|
|
|
{ |
|
|
|
{input: "C3010203", ptr: new([5]byte), error: "rlp: expected input string or byte for [5]uint8"}, |
|
|
|
input: "86010203040506", |
|
|
|
{input: "86010203040506", ptr: new([5]byte), error: "rlp: input string too long for [5]uint8"}, |
|
|
|
ptr: new([5]byte), |
|
|
|
{input: "8105", ptr: new([1]byte), error: "rlp: non-canonical size information for [1]uint8"}, |
|
|
|
error: "rlp: input string too long for [5]uint8", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
input: "850101", |
|
|
|
|
|
|
|
ptr: new([5]byte), |
|
|
|
|
|
|
|
error: io.ErrUnexpectedEOF.Error(), |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// byte array reuse (should be zeroed)
|
|
|
|
|
|
|
|
{input: "850102030405", ptr: &sharedByteArray, value: [5]byte{1, 2, 3, 4, 5}}, |
|
|
|
|
|
|
|
{input: "8101", ptr: &sharedByteArray, value: [5]byte{1}}, // kind: String
|
|
|
|
|
|
|
|
{input: "850102030405", ptr: &sharedByteArray, value: [5]byte{1, 2, 3, 4, 5}}, |
|
|
|
|
|
|
|
{input: "01", ptr: &sharedByteArray, value: [5]byte{1}}, // kind: Byte
|
|
|
|
|
|
|
|
{input: "C3010203", ptr: &sharedByteArray, value: [5]byte{1, 2, 3, 0, 0}}, |
|
|
|
|
|
|
|
{input: "C101", ptr: &sharedByteArray, value: [5]byte{1}}, // kind: List
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// zero sized byte arrays
|
|
|
|
// zero sized byte arrays
|
|
|
|
{input: "80", ptr: new([0]byte), value: [0]byte{}}, |
|
|
|
{input: "80", ptr: new([0]byte), value: [0]byte{}}, |
|
|
|
{input: "C0", ptr: new([0]byte), value: [0]byte{}}, |
|
|
|
|
|
|
|
{input: "01", ptr: new([0]byte), error: "rlp: input string too long for [0]uint8"}, |
|
|
|
{input: "01", ptr: new([0]byte), error: "rlp: input string too long for [0]uint8"}, |
|
|
|
{input: "8101", ptr: new([0]byte), error: "rlp: input string too long for [0]uint8"}, |
|
|
|
{input: "8101", ptr: new([0]byte), error: "rlp: input string too long for [0]uint8"}, |
|
|
|
|
|
|
|
|
|
|
@ -312,20 +353,44 @@ var decodeTests = []decodeTest{ |
|
|
|
// big ints
|
|
|
|
// big ints
|
|
|
|
{input: "01", ptr: new(*big.Int), value: big.NewInt(1)}, |
|
|
|
{input: "01", ptr: new(*big.Int), value: big.NewInt(1)}, |
|
|
|
{input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*big.Int), value: veryBigInt}, |
|
|
|
{input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*big.Int), value: veryBigInt}, |
|
|
|
{input: "820001", ptr: new(big.Int), error: "rlp: canon int error appends zero's for *big.Int"}, |
|
|
|
|
|
|
|
{input: "10", ptr: new(big.Int), value: *big.NewInt(16)}, // non-pointer also works
|
|
|
|
{input: "10", ptr: new(big.Int), value: *big.NewInt(16)}, // non-pointer also works
|
|
|
|
{input: "C0", ptr: new(*big.Int), error: "rlp: expected input string or byte for *big.Int"}, |
|
|
|
{input: "C0", ptr: new(*big.Int), error: "rlp: expected input string or byte for *big.Int"}, |
|
|
|
|
|
|
|
{input: "820001", ptr: new(big.Int), error: "rlp: non-canonical integer (leading zero bytes) for *big.Int"}, |
|
|
|
|
|
|
|
{input: "8105", ptr: new(big.Int), error: "rlp: non-canonical size information for *big.Int"}, |
|
|
|
|
|
|
|
|
|
|
|
// structs
|
|
|
|
// structs
|
|
|
|
{input: "C0", ptr: new(simplestruct), value: simplestruct{0, ""}}, |
|
|
|
|
|
|
|
{input: "C105", ptr: new(simplestruct), value: simplestruct{5, ""}}, |
|
|
|
|
|
|
|
{input: "C50583343434", ptr: new(simplestruct), value: simplestruct{5, "444"}}, |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
input: "C501C302C103", |
|
|
|
input: "C50583343434", |
|
|
|
|
|
|
|
ptr: new(simplestruct), |
|
|
|
|
|
|
|
value: simplestruct{5, "444"}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
input: "C601C402C203C0", |
|
|
|
ptr: new(recstruct), |
|
|
|
ptr: new(recstruct), |
|
|
|
value: recstruct{1, &recstruct{2, &recstruct{3, nil}}}, |
|
|
|
value: recstruct{1, &recstruct{2, &recstruct{3, nil}}}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// struct errors
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
input: "C0", |
|
|
|
|
|
|
|
ptr: new(simplestruct), |
|
|
|
|
|
|
|
error: "rlp: too few elements for rlp.simplestruct", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
input: "C105", |
|
|
|
|
|
|
|
ptr: new(simplestruct), |
|
|
|
|
|
|
|
error: "rlp: too few elements for rlp.simplestruct", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
input: "C7C50583343434C0", |
|
|
|
|
|
|
|
ptr: new([]*simplestruct), |
|
|
|
|
|
|
|
error: "rlp: too few elements for rlp.simplestruct, decoding into ([]*rlp.simplestruct)[1]", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
input: "83222222", |
|
|
|
|
|
|
|
ptr: new(simplestruct), |
|
|
|
|
|
|
|
error: "rlp: expected input list for rlp.simplestruct", |
|
|
|
|
|
|
|
}, |
|
|
|
{ |
|
|
|
{ |
|
|
|
input: "C3010101", |
|
|
|
input: "C3010101", |
|
|
|
ptr: new(simplestruct), |
|
|
|
ptr: new(simplestruct), |
|
|
@ -338,20 +403,16 @@ var decodeTests = []decodeTest{ |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
// pointers
|
|
|
|
// pointers
|
|
|
|
{input: "00", ptr: new(*uint), value: (*uint)(nil)}, |
|
|
|
{input: "00", ptr: new(*[]byte), value: &[]byte{0}}, |
|
|
|
{input: "80", ptr: new(*uint), value: (*uint)(nil)}, |
|
|
|
{input: "80", ptr: new(*uint), value: uintp(0)}, |
|
|
|
{input: "C0", ptr: new(*uint), value: (*uint)(nil)}, |
|
|
|
{input: "C0", ptr: new(*uint), error: "rlp: expected input string or byte for uint"}, |
|
|
|
{input: "07", ptr: new(*uint), value: uintp(7)}, |
|
|
|
{input: "07", ptr: new(*uint), value: uintp(7)}, |
|
|
|
{input: "8108", ptr: new(*uint), value: uintp(8)}, |
|
|
|
{input: "8158", ptr: new(*uint), value: uintp(0x58)}, |
|
|
|
{input: "C109", ptr: new(*[]uint), value: &[]uint{9}}, |
|
|
|
{input: "C109", ptr: new(*[]uint), value: &[]uint{9}}, |
|
|
|
{input: "C58403030303", ptr: new(*[][]byte), value: &[][]byte{{3, 3, 3, 3}}}, |
|
|
|
{input: "C58403030303", ptr: new(*[][]byte), value: &[][]byte{{3, 3, 3, 3}}}, |
|
|
|
|
|
|
|
|
|
|
|
// check that input position is advanced also for empty values.
|
|
|
|
// check that input position is advanced also for empty values.
|
|
|
|
{input: "C3808005", ptr: new([]*uint), value: []*uint{nil, nil, uintp(5)}}, |
|
|
|
{input: "C3808005", ptr: new([]*uint), value: []*uint{uintp(0), uintp(0), uintp(5)}}, |
|
|
|
|
|
|
|
|
|
|
|
// pointer should be reset to nil
|
|
|
|
|
|
|
|
{input: "05", ptr: sharedPtr, value: uintp(5)}, |
|
|
|
|
|
|
|
{input: "80", ptr: sharedPtr, value: (*uint)(nil)}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// interface{}
|
|
|
|
// interface{}
|
|
|
|
{input: "00", ptr: new(interface{}), value: []byte{0}}, |
|
|
|
{input: "00", ptr: new(interface{}), value: []byte{0}}, |
|
|
@ -401,11 +462,17 @@ func TestDecodeWithByteReader(t *testing.T) { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// dumbReader reads from a byte slice but does not
|
|
|
|
// plainReader reads from a byte slice but does not
|
|
|
|
// implement ReadByte.
|
|
|
|
// implement ReadByte. It is also not recognized by the
|
|
|
|
type dumbReader []byte |
|
|
|
// size validation. This is useful to test how the decoder
|
|
|
|
|
|
|
|
// behaves on a non-buffered input stream.
|
|
|
|
|
|
|
|
type plainReader []byte |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func newPlainReader(b []byte) io.Reader { |
|
|
|
|
|
|
|
return (*plainReader)(&b) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (r *dumbReader) Read(buf []byte) (n int, err error) { |
|
|
|
func (r *plainReader) Read(buf []byte) (n int, err error) { |
|
|
|
if len(*r) == 0 { |
|
|
|
if len(*r) == 0 { |
|
|
|
return 0, io.EOF |
|
|
|
return 0, io.EOF |
|
|
|
} |
|
|
|
} |
|
|
@ -416,15 +483,14 @@ func (r *dumbReader) Read(buf []byte) (n int, err error) { |
|
|
|
|
|
|
|
|
|
|
|
func TestDecodeWithNonByteReader(t *testing.T) { |
|
|
|
func TestDecodeWithNonByteReader(t *testing.T) { |
|
|
|
runTests(t, func(input []byte, into interface{}) error { |
|
|
|
runTests(t, func(input []byte, into interface{}) error { |
|
|
|
r := dumbReader(input) |
|
|
|
return Decode(newPlainReader(input), into) |
|
|
|
return Decode(&r, into) |
|
|
|
|
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func TestDecodeStreamReset(t *testing.T) { |
|
|
|
func TestDecodeStreamReset(t *testing.T) { |
|
|
|
s := NewStream(nil) |
|
|
|
s := NewStream(nil, 0) |
|
|
|
runTests(t, func(input []byte, into interface{}) error { |
|
|
|
runTests(t, func(input []byte, into interface{}) error { |
|
|
|
s.Reset(bytes.NewReader(input)) |
|
|
|
s.Reset(bytes.NewReader(input), 0) |
|
|
|
return s.Decode(into) |
|
|
|
return s.Decode(into) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
@ -516,9 +582,36 @@ func ExampleDecode() { |
|
|
|
// Decoded value: rlp.example{A:0xa, B:0x14, private:0x0, String:"foobar"}
|
|
|
|
// Decoded value: rlp.example{A:0xa, B:0x14, private:0x0, String:"foobar"}
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func ExampleDecode_structTagNil() { |
|
|
|
|
|
|
|
// In this example, we'll use the "nil" struct tag to change
|
|
|
|
|
|
|
|
// how a pointer-typed field is decoded. The input contains an RLP
|
|
|
|
|
|
|
|
// list of one element, an empty string.
|
|
|
|
|
|
|
|
input := []byte{0xC1, 0x80} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This type uses the normal rules.
|
|
|
|
|
|
|
|
// The empty input string is decoded as a pointer to an empty Go string.
|
|
|
|
|
|
|
|
var normalRules struct { |
|
|
|
|
|
|
|
String *string |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Decode(bytes.NewReader(input), &normalRules) |
|
|
|
|
|
|
|
fmt.Printf("normal: String = %q\n", *normalRules.String) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This type uses the struct tag.
|
|
|
|
|
|
|
|
// The empty input string is decoded as a nil pointer.
|
|
|
|
|
|
|
|
var withEmptyOK struct { |
|
|
|
|
|
|
|
String *string `rlp:"nil"` |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Decode(bytes.NewReader(input), &withEmptyOK) |
|
|
|
|
|
|
|
fmt.Printf("with nil tag: String = %v\n", withEmptyOK.String) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Output:
|
|
|
|
|
|
|
|
// normal: String = ""
|
|
|
|
|
|
|
|
// with nil tag: String = <nil>
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func ExampleStream() { |
|
|
|
func ExampleStream() { |
|
|
|
input, _ := hex.DecodeString("C90A1486666F6F626172") |
|
|
|
input, _ := hex.DecodeString("C90A1486666F6F626172") |
|
|
|
s := NewStream(bytes.NewReader(input)) |
|
|
|
s := NewStream(bytes.NewReader(input), 0) |
|
|
|
|
|
|
|
|
|
|
|
// Check what kind of value lies ahead
|
|
|
|
// Check what kind of value lies ahead
|
|
|
|
kind, size, _ := s.Kind() |
|
|
|
kind, size, _ := s.Kind() |
|
|
|