mirror of
https://github.com/btcsuite/btcd.git
synced 2024-11-19 18:00:11 +01:00
bd4e64d1d4
This is mostly a backport of some of the same modifications made in Decred along with a few additional things cleaned up. In particular, this updates the code to make use of the new chainhash package. Also, since this required API changes anyways and the hash algorithm is no longer tied specifically to SHA, all other functions throughout the code base which had "Sha" in their name have been changed to Hash so they are not incorrectly implying the hash algorithm. The following is an overview of the changes: - Remove the wire.ShaHash type - Update all references to wire.ShaHash to the new chainhash.Hash type - Rename the following functions and update all references: - wire.BlockHeader.BlockSha -> BlockHash - wire.MsgBlock.BlockSha -> BlockHash - wire.MsgBlock.TxShas -> TxHashes - wire.MsgTx.TxSha -> TxHash - blockchain.ShaHashToBig -> HashToBig - peer.ShaFunc -> peer.HashFunc - Rename all variables that included sha in their name to include hash instead - Update for function name changes in other dependent packages such as btcutil - Update copyright dates on all modified files - Update glide.lock file to use the required version of btcutil
760 lines
22 KiB
Go
760 lines
22 KiB
Go
// Copyright (c) 2013-2016 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package wire
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/davecgh/go-spew/spew"
|
|
)
|
|
|
|
// 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,
|
|
},
|
|
},
|
|
{
|
|
ServiceFlag(SFNodeNetwork),
|
|
[]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
},
|
|
{
|
|
InvType(InvTypeTx),
|
|
[]byte{0x01, 0x00, 0x00, 0x00},
|
|
},
|
|
{
|
|
BitcoinNet(MainNet),
|
|
[]byte{0xf9, 0xbe, 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,
|
|
},
|
|
{ServiceFlag(SFNodeNetwork), 0, io.ErrShortWrite, io.EOF},
|
|
{InvType(InvTypeTx), 0, io.ErrShortWrite, io.EOF},
|
|
{BitcoinNet(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 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 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 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 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)
|
|
if _, ok := err.(*MessageError); !ok {
|
|
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 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 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
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// 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 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 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 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)
|
|
}
|
|
}
|