dcrd/wire/common_test.go
Matheus Degiovani 1869aea8e5 wire: Introduce InitState messages
This adds the GetInitState and InitState messages along with appropriate
tests. It also adds a new protocol version (version 8) and bumps the
current wire version to it.

This set of messages will be used to allow peers to exchange ephemeral
startup information in a more general manner than the current existing
GetMiningState/MiningState pair.

In particular, peers will be able to selectively request only the
specific startup info they're insterested in so that different types of
nodes (such as SPV clients) may only request relevant startup
information.

Compared to the existing MiningState message, the InitState message
already offers a new type of data: tspend hashes, that nodes may use to
fetch tspend transactions for inspecting, generating templates and
voting on their approval.
2020-09-23 14:01:30 -05:00

910 lines
26 KiB
Go

// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"bytes"
"errors"
"fmt"
"io"
"reflect"
"strings"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/decred/dcrd/chaincfg/chainhash"
)
// mainNetGenesisHash is the hash of the first block in the block chain for the
// main network (genesis block).
var mainNetGenesisHash = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72,
0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f,
0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c,
0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
})
// mainNetGenesisMerkleRoot is the hash of the first transaction in the genesis
// block for the main network.
var mainNetGenesisMerkleRoot = chainhash.Hash([chainhash.HashSize]byte{ // Make go vet happy.
0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2,
0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61,
0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32,
0x3a, 0x9f, 0xb8, 0xaa, 0x4b, 0x1e, 0x5e, 0x4a,
})
// fakeRandReader implements the io.Reader interface and is used to force
// errors in the RandomUint64 function.
type fakeRandReader struct {
n int
err error
}
// Read returns the fake reader error and the lesser of the fake reader value
// and the length of p.
func (r *fakeRandReader) Read(p []byte) (int, error) {
n := r.n
if n > len(p) {
n = len(p)
}
return n, r.err
}
// TestElementWire tests wire encode and decode for various element types. This
// is mainly to test the "fast" paths in readElement and writeElement which use
// type assertions to avoid reflection when possible.
func TestElementWire(t *testing.T) {
type writeElementReflect int32
tests := []struct {
in interface{} // Value to encode
buf []byte // Wire encoding
}{
{int32(1), []byte{0x01, 0x00, 0x00, 0x00}},
{uint32(256), []byte{0x00, 0x01, 0x00, 0x00}},
{
int64(65536),
[]byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00},
},
{
uint64(4294967296),
[]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00},
},
{
true,
[]byte{0x01},
},
{
false,
[]byte{0x00},
},
{
[4]byte{0x01, 0x02, 0x03, 0x04},
[]byte{0x01, 0x02, 0x03, 0x04},
},
{
[CommandSize]byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c,
},
[]byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c,
},
},
{
[16]byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
},
[]byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
},
},
{
(*chainhash.Hash)(&[chainhash.HashSize]byte{ // Make go vet happy.
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
}),
[]byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
},
},
{
SFNodeNetwork,
[]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
},
{
InvTypeTx,
[]byte{0x01, 0x00, 0x00, 0x00},
},
{
MainNet,
[]byte{0xf9, 0x00, 0xb4, 0xd9},
},
// Type not supported by the "fast" path and requires reflection.
{
writeElementReflect(1),
[]byte{0x01, 0x00, 0x00, 0x00},
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Write to wire format.
var buf bytes.Buffer
err := writeElement(&buf, test.in)
if err != nil {
t.Errorf("writeElement #%d error %v", i, err)
continue
}
if !bytes.Equal(buf.Bytes(), test.buf) {
t.Errorf("writeElement #%d\n got: %s want: %s", i,
spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
continue
}
// Read from wire format.
rbuf := bytes.NewReader(test.buf)
val := test.in
if reflect.ValueOf(test.in).Kind() != reflect.Ptr {
val = reflect.New(reflect.TypeOf(test.in)).Interface()
}
err = readElement(rbuf, val)
if err != nil {
t.Errorf("readElement #%d error %v", i, err)
continue
}
ival := val
if reflect.ValueOf(test.in).Kind() != reflect.Ptr {
ival = reflect.Indirect(reflect.ValueOf(val)).Interface()
}
if !reflect.DeepEqual(ival, test.in) {
t.Errorf("readElement #%d\n got: %s want: %s", i,
spew.Sdump(ival), spew.Sdump(test.in))
continue
}
}
}
// TestElementWireErrors performs negative tests against wire encode and decode
// of various element types to confirm error paths work correctly.
func TestElementWireErrors(t *testing.T) {
tests := []struct {
in interface{} // Value to encode
max int // Max size of fixed buffer to induce errors
writeErr error // Expected write error
readErr error // Expected read error
}{
{int32(1), 0, io.ErrShortWrite, io.EOF},
{uint32(256), 0, io.ErrShortWrite, io.EOF},
{int64(65536), 0, io.ErrShortWrite, io.EOF},
{true, 0, io.ErrShortWrite, io.EOF},
{[4]byte{0x01, 0x02, 0x03, 0x04}, 0, io.ErrShortWrite, io.EOF},
{
[CommandSize]byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c,
},
0, io.ErrShortWrite, io.EOF,
},
{
[16]byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
},
0, io.ErrShortWrite, io.EOF,
},
{
(*chainhash.Hash)(&[chainhash.HashSize]byte{ // Make go vet happy.
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
}),
0, io.ErrShortWrite, io.EOF,
},
{SFNodeNetwork, 0, io.ErrShortWrite, io.EOF},
{InvTypeTx, 0, io.ErrShortWrite, io.EOF},
{MainNet, 0, io.ErrShortWrite, io.EOF},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
w := newFixedWriter(test.max)
err := writeElement(w, test.in)
if !errors.Is(err, test.writeErr) {
t.Errorf("writeElement #%d wrong error got: %v, want: %v",
i, err, test.writeErr)
continue
}
// Decode from wire format.
r := newFixedReader(test.max, nil)
val := test.in
if reflect.ValueOf(test.in).Kind() != reflect.Ptr {
val = reflect.New(reflect.TypeOf(test.in)).Interface()
}
err = readElement(r, val)
if !errors.Is(err, test.readErr) {
t.Errorf("readElement #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
}
}
// TestVarIntWire tests wire encode and decode for variable length integers.
func TestVarIntWire(t *testing.T) {
pver := ProtocolVersion
tests := []struct {
in uint64 // Value to encode
out uint64 // Expected decoded value
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
}{
// Latest protocol version.
// Single byte
{0, 0, []byte{0x00}, pver},
// Max single byte
{0xfc, 0xfc, []byte{0xfc}, pver},
// Min 2-byte
{0xfd, 0xfd, []byte{0xfd, 0x0fd, 0x00}, pver},
// Max 2-byte
{0xffff, 0xffff, []byte{0xfd, 0xff, 0xff}, pver},
// Min 4-byte
{0x10000, 0x10000, []byte{0xfe, 0x00, 0x00, 0x01, 0x00}, pver},
// Max 4-byte
{0xffffffff, 0xffffffff, []byte{0xfe, 0xff, 0xff, 0xff, 0xff}, pver},
// Min 8-byte
{
0x100000000, 0x100000000,
[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00},
pver,
},
// Max 8-byte
{
0xffffffffffffffff, 0xffffffffffffffff,
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
pver,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
var buf bytes.Buffer
err := WriteVarInt(&buf, test.pver, test.in)
if err != nil {
t.Errorf("WriteVarInt #%d error %v", i, err)
continue
}
if !bytes.Equal(buf.Bytes(), test.buf) {
t.Errorf("WriteVarInt #%d\n got: %s want: %s", i,
spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
continue
}
// Decode from wire format.
rbuf := bytes.NewReader(test.buf)
val, err := ReadVarInt(rbuf, test.pver)
if err != nil {
t.Errorf("ReadVarInt #%d error %v", i, err)
continue
}
if val != test.out {
t.Errorf("ReadVarInt #%d\n got: %d want: %d", i,
val, test.out)
continue
}
}
}
// TestVarIntWireErrors performs negative tests against wire encode and decode
// of variable length integers to confirm error paths work correctly.
func TestVarIntWireErrors(t *testing.T) {
pver := ProtocolVersion
tests := []struct {
in uint64 // Value to encode
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
max int // Max size of fixed buffer to induce errors
writeErr error // Expected write error
readErr error // Expected read error
}{
// Force errors on discriminant.
{0, []byte{0x00}, pver, 0, io.ErrShortWrite, io.EOF},
// Force errors on 2-byte read/write.
{0xfd, []byte{0xfd}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF},
// Force errors on 4-byte read/write.
{0x10000, []byte{0xfe}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF},
// Force errors on 8-byte read/write.
{0x100000000, []byte{0xff}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
w := newFixedWriter(test.max)
err := WriteVarInt(w, test.pver, test.in)
if !errors.Is(err, test.writeErr) {
t.Errorf("WriteVarInt #%d wrong error got: %v, want: %v",
i, err, test.writeErr)
continue
}
// Decode from wire format.
r := newFixedReader(test.max, test.buf)
_, err = ReadVarInt(r, test.pver)
if !errors.Is(err, test.readErr) {
t.Errorf("ReadVarInt #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
}
}
// TestVarIntNonCanonical ensures variable length integers that are not encoded
// canonically return the expected error.
func TestVarIntNonCanonical(t *testing.T) {
pver := ProtocolVersion
tests := []struct {
name string // Test name for easier identification
in []byte // Value to decode
pver uint32 // Protocol version for wire encoding
}{
{
"0 encoded with 3 bytes",
[]byte{0xfd, 0x00, 0x00},
pver,
},
{
"max single-byte value encoded with 3 bytes",
[]byte{0xfd, 0xfc, 0x00},
pver,
},
{
"0 encoded with 5 bytes",
[]byte{0xfe, 0x00, 0x00, 0x00, 0x00},
pver,
},
{
"max three-byte value encoded with 5 bytes",
[]byte{0xfe, 0xff, 0xff, 0x00, 0x00},
pver,
},
{
"0 encoded with 9 bytes",
[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
pver,
},
{
"max five-byte value encoded with 9 bytes",
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
pver,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Decode from wire format.
rbuf := bytes.NewReader(test.in)
val, err := ReadVarInt(rbuf, test.pver)
var merr *MessageError
if !errors.As(err, &merr) {
t.Errorf("ReadVarInt #%d (%s) unexpected error %v", i,
test.name, err)
continue
}
if val != 0 {
t.Errorf("ReadVarInt #%d (%s)\n got: %d want: 0", i,
test.name, val)
continue
}
}
}
// TestVarIntWire tests the serialize size for variable length integers.
func TestVarIntSerializeSize(t *testing.T) {
tests := []struct {
val uint64 // Value to get the serialized size for
size int // Expected serialized size
}{
// Single byte
{0, 1},
// Max single byte
{0xfc, 1},
// Min 2-byte
{0xfd, 3},
// Max 2-byte
{0xffff, 3},
// Min 4-byte
{0x10000, 5},
// Max 4-byte
{0xffffffff, 5},
// Min 8-byte
{0x100000000, 9},
// Max 8-byte
{0xffffffffffffffff, 9},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
serializedSize := VarIntSerializeSize(test.val)
if serializedSize != test.size {
t.Errorf("VarIntSerializeSize #%d got: %d, want: %d", i,
serializedSize, test.size)
continue
}
}
}
// TestVarStringWire tests wire encode and decode for variable length strings.
func TestVarStringWire(t *testing.T) {
pver := ProtocolVersion
// str256 is a string that takes a 2-byte varint to encode.
str256 := strings.Repeat("test", 64)
tests := []struct {
in string // String to encode
out string // String to decoded value
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
}{
// Latest protocol version.
// Empty string
{"", "", []byte{0x00}, pver},
// Single byte varint + string
{"Test", "Test", append([]byte{0x04}, []byte("Test")...), pver},
// 2-byte varint + string
{str256, str256, append([]byte{0xfd, 0x00, 0x01}, []byte(str256)...), pver},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
var buf bytes.Buffer
err := WriteVarString(&buf, test.pver, test.in)
if err != nil {
t.Errorf("WriteVarString #%d error %v", i, err)
continue
}
if !bytes.Equal(buf.Bytes(), test.buf) {
t.Errorf("WriteVarString #%d\n got: %s want: %s", i,
spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
continue
}
// Decode from wire format.
rbuf := bytes.NewReader(test.buf)
val, err := ReadVarString(rbuf, test.pver)
if err != nil {
t.Errorf("ReadVarString #%d error %v", i, err)
continue
}
if val != test.out {
t.Errorf("ReadVarString #%d\n got: %s want: %s", i,
val, test.out)
continue
}
}
}
// TestVarStringWireErrors performs negative tests against wire encode and
// decode of variable length strings to confirm error paths work correctly.
func TestVarStringWireErrors(t *testing.T) {
pver := ProtocolVersion
// str256 is a string that takes a 2-byte varint to encode.
str256 := strings.Repeat("test", 64)
tests := []struct {
in string // Value to encode
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
max int // Max size of fixed buffer to induce errors
writeErr error // Expected write error
readErr error // Expected read error
}{
// Latest protocol version with intentional read/write errors.
// Force errors on empty string.
{"", []byte{0x00}, pver, 0, io.ErrShortWrite, io.EOF},
// Force error on single byte varint + string.
{"Test", []byte{0x04}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF},
// Force errors on 2-byte varint + string.
{str256, []byte{0xfd}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
w := newFixedWriter(test.max)
err := WriteVarString(w, test.pver, test.in)
if !errors.Is(err, test.writeErr) {
t.Errorf("WriteVarString #%d wrong error got: %v, want: %v",
i, err, test.writeErr)
continue
}
// Decode from wire format.
r := newFixedReader(test.max, test.buf)
_, err = ReadVarString(r, test.pver)
if !errors.Is(err, test.readErr) {
t.Errorf("ReadVarString #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
}
}
// TestVarStringOverflowErrors performs tests to ensure deserializing variable
// length strings intentionally crafted to use large values for the string
// length are handled properly. This could otherwise potentially be used as an
// attack vector.
func TestVarStringOverflowErrors(t *testing.T) {
pver := ProtocolVersion
tests := []struct {
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
err error // Expected error
}{
{
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
pver, &MessageError{},
},
{
[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
pver, &MessageError{},
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Decode from wire format.
rbuf := bytes.NewReader(test.buf)
_, err := ReadVarString(rbuf, test.pver)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("ReadVarString #%d wrong error got: %v, "+
"want: %v", i, err, reflect.TypeOf(test.err))
continue
}
}
}
// TestAsciiVarStringWire tests wire decode for variable length ascii strings.
func TestAsciiVarStringWire(t *testing.T) {
pver := ProtocolVersion
// str256 is a string that takes a 2-byte varint to encode.
str256 := strings.Repeat("test", 64)
// maxStr is a string with the maximum allowed length.
maxStr := strings.Repeat("a", MaxMessagePayload)
maxStrEncoded := append([]byte{0xfe, 0x00, 0x00, 0x00, 0x02}, []byte(maxStr)...)
tests := []struct {
out string // String to decoded value
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
maxsz uint64 // Max allowed size during decoding
}{
// Latest protocol version.
// Empty string, zero allowed
{"", []byte{0x00}, pver, 0},
// Empty string, more than needed allowed
{"", []byte{0x00}, pver, 256},
// Single byte varint + string exact needed allowed
{"Test", append([]byte{0x04}, []byte("Test")...), pver, 4},
// Single byte varint + string more than needed allowed
{"Test", append([]byte{0x04}, []byte("Test")...), pver, 256},
// 2-byte varint + string
{str256, append([]byte{0xfd, 0x00, 0x01}, []byte(str256)...), pver, 256},
// Max allowable string exact needed.
{maxStr, maxStrEncoded, pver, MaxMessagePayload},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Decode from wire format.
rbuf := bytes.NewReader(test.buf)
val, err := ReadAsciiVarString(rbuf, test.pver, test.maxsz)
if err != nil {
t.Errorf("ReadVarString #%d error %v", i, err)
continue
}
if val != test.out {
t.Errorf("ReadVarString #%d\n got: %s want: %s", i,
val, test.out)
continue
}
}
}
// TestAsciiVarStringWireErrors performs negative tests against wire decode of
// variable length ascii strings to confirm error paths work correctly.
func TestAsciiVarStringWireErrors(t *testing.T) {
pver := ProtocolVersion
tests := []struct {
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
max int // Max size of fixed buffer to induce errors
maxsz uint64 // Max allowed size during decoding
readErr error // Expected read error
}{
// Latest protocol version with intentional read/write errors.
// Force errors on empty string.
{[]byte{0x00}, pver, 0, 256, io.EOF},
// Force error on single byte varint + string.
{[]byte{0x04}, pver, 2, 256, io.ErrUnexpectedEOF},
// Force errors on 2-byte varint + string.
{[]byte{0xfd}, pver, 2, 65536, io.ErrUnexpectedEOF},
// Force errors on larger than allowed string.
{[]byte{0x04, 't', 'e', 's', 't'}, pver, 5, 3, ErrVarStringTooLong},
// Force errors on non-ascii string.
{[]byte{0x04, 't', 'é', 's', 't'}, pver, 5, 4, ErrMalformedStrictString},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Decode from wire format.
r := newFixedReader(test.max, test.buf)
_, err := ReadAsciiVarString(r, test.pver, test.maxsz)
if !errors.Is(err, test.readErr) {
t.Errorf("ReadAsciiVarString #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
}
}
// TestAsciiVarStringOverflowErrors performs tests to ensure deserializing
// variable length ascii strings intentionally crafted to use large values for
// the string length are handled properly. This could otherwise potentially be
// used as an attack vector.
func TestAsciiVarStringOverflowErrors(t *testing.T) {
pver := ProtocolVersion
tests := []struct {
buf []byte // Wire encoding
maxsz uint64 // Max allowed size during decoding
pver uint32 // Protocol version for wire encoding
err error // Expected error
}{
{ // Max varint, max allowed.
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
^uint64(0), pver, ErrVarStringTooLong,
},
{ // 2^56 after decoding (LSB of upper byte of decoded varint).
[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
^uint64(0), pver, ErrVarStringTooLong,
},
{ // One more than max payload, max allowed.
[]byte{0xfe, 0x01, 0x00, 0x00, 0x02},
^uint64(0), pver, ErrVarStringTooLong,
},
{ // Max payload, one less than max payload allowed.
[]byte{0xfe, 0x00, 0x00, 0x00, 0x02},
MaxMessagePayload - 1, pver, ErrVarStringTooLong,
},
{ // Single byte payload, zero allowed.
[]byte{0x01},
0, pver, ErrVarStringTooLong,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Decode from wire format.
rbuf := bytes.NewReader(test.buf)
_, err := ReadAsciiVarString(rbuf, test.pver, test.maxsz)
if !errors.Is(err, test.err) {
t.Errorf("ReadAsciiVarString #%d wrong error. want=%v, "+
"got=%v", i, test.err, err)
continue
}
}
}
// TestVarBytesWire tests wire encode and decode for variable length byte array.
func TestVarBytesWire(t *testing.T) {
pver := ProtocolVersion
// bytes256 is a byte array that takes a 2-byte varint to encode.
bytes256 := bytes.Repeat([]byte{0x01}, 256)
tests := []struct {
in []byte // Byte Array to write
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
}{
// Latest protocol version.
// Empty byte array
{[]byte{}, []byte{0x00}, pver},
// Single byte varint + byte array
{[]byte{0x01}, []byte{0x01, 0x01}, pver},
// 2-byte varint + byte array
{bytes256, append([]byte{0xfd, 0x00, 0x01}, bytes256...), pver},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
var buf bytes.Buffer
err := WriteVarBytes(&buf, test.pver, test.in)
if err != nil {
t.Errorf("WriteVarBytes #%d error %v", i, err)
continue
}
if !bytes.Equal(buf.Bytes(), test.buf) {
t.Errorf("WriteVarBytes #%d\n got: %s want: %s", i,
spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
continue
}
// Decode from wire format.
rbuf := bytes.NewReader(test.buf)
val, err := ReadVarBytes(rbuf, test.pver, MaxMessagePayload,
"test payload")
if err != nil {
t.Errorf("ReadVarBytes #%d error %v", i, err)
continue
}
if !bytes.Equal(buf.Bytes(), test.buf) {
t.Errorf("ReadVarBytes #%d\n got: %s want: %s", i,
val, test.buf)
continue
}
}
}
// TestVarBytesWireErrors performs negative tests against wire encode and
// decode of variable length byte arrays to confirm error paths work correctly.
func TestVarBytesWireErrors(t *testing.T) {
pver := ProtocolVersion
// bytes256 is a byte array that takes a 2-byte varint to encode.
bytes256 := bytes.Repeat([]byte{0x01}, 256)
tests := []struct {
in []byte // Byte Array to write
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
max int // Max size of fixed buffer to induce errors
writeErr error // Expected write error
readErr error // Expected read error
}{
// Latest protocol version with intentional read/write errors.
// Force errors on empty byte array.
{[]byte{}, []byte{0x00}, pver, 0, io.ErrShortWrite, io.EOF},
// Force error on single byte varint + byte array.
{[]byte{0x01, 0x02, 0x03}, []byte{0x04}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF},
// Force errors on 2-byte varint + byte array.
{bytes256, []byte{0xfd}, pver, 2, io.ErrShortWrite, io.ErrUnexpectedEOF},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
w := newFixedWriter(test.max)
err := WriteVarBytes(w, test.pver, test.in)
if !errors.Is(err, test.writeErr) {
t.Errorf("WriteVarBytes #%d wrong error got: %v, want: %v",
i, err, test.writeErr)
continue
}
// Decode from wire format.
r := newFixedReader(test.max, test.buf)
_, err = ReadVarBytes(r, test.pver, MaxMessagePayload,
"test payload")
if !errors.Is(err, test.readErr) {
t.Errorf("ReadVarBytes #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
}
}
// TestVarBytesOverflowErrors performs tests to ensure deserializing variable
// length byte arrays intentionally crafted to use large values for the array
// length are handled properly. This could otherwise potentially be used as an
// attack vector.
func TestVarBytesOverflowErrors(t *testing.T) {
pver := ProtocolVersion
tests := []struct {
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
err error // Expected error
}{
{
[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
pver,
&MessageError{},
},
{
[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
pver,
&MessageError{},
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Decode from wire format.
rbuf := bytes.NewReader(test.buf)
_, err := ReadVarBytes(rbuf, test.pver, MaxMessagePayload,
"test payload")
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("ReadVarBytes #%d wrong error got: %v, "+
"want: %v", i, err, reflect.TypeOf(test.err))
continue
}
}
}
// TestRandomUint64 exercises the randomness of the random number generator on
// the system by ensuring the probability of the generated numbers. If the RNG
// is evenly distributed as a proper cryptographic RNG should be, there really
// should only be 1 number < 2^56 in 2^8 tries for a 64-bit number. However,
// use a higher number of 5 to really ensure the test doesn't fail unless the
// RNG is just horrendous.
func TestRandomUint64(t *testing.T) {
tries := 1 << 8 // 2^8
watermark := uint64(1 << 56) // 2^56
maxHits := 5
badRNG := "The random number generator on this system is clearly " +
"terrible since we got %d values less than %d in %d runs " +
"when only %d was expected"
numHits := 0
for i := 0; i < tries; i++ {
nonce, err := RandomUint64()
if err != nil {
t.Errorf("RandomUint64 iteration %d failed - err %v",
i, err)
return
}
if nonce < watermark {
numHits++
}
if numHits > maxHits {
str := fmt.Sprintf(badRNG, numHits, watermark, tries, maxHits)
t.Errorf("Random Uint64 iteration %d failed - %v %v", i,
str, numHits)
return
}
}
}
// TestRandomUint64Errors uses a fake reader to force error paths to be executed
// and checks the results accordingly.
func TestRandomUint64Errors(t *testing.T) {
// Test short reads.
fr := &fakeRandReader{n: 2, err: io.EOF}
nonce, err := randomUint64(fr)
if !errors.Is(err, io.ErrUnexpectedEOF) {
t.Errorf("Error not expected value of %v [%v]",
io.ErrUnexpectedEOF, err)
}
if nonce != 0 {
t.Errorf("Nonce is not 0 [%v]", nonce)
}
}