Complete BIP0037 support started by dhill.

- Correct MsgFilterLoad max payload
- Enforce max flag bytes per merkle block
- Improve and finish tests to include testing all error paths
- Add fast paths for BloomUpdateType
- Convert all byte fields to use read/writeVarBytes
- Style and consistency updates
- README.md and doc.go updates

Closes #12.
This commit is contained in:
Dave Collins 2014-05-05 02:15:18 -05:00
parent cf754d09bf
commit f8ec476691
15 changed files with 737 additions and 277 deletions

View file

@ -103,12 +103,6 @@ from a remote peer is:
}
```
## TODO
- Implement alert message decoding/encoding
- Implement bloom filter messages (filterload, filteradd, filterclear,
merkleblock) as defined in [BIP 0037](https://en.bitcoin.it/wiki/BIP_0037)
## GPG Verification Key
All official release tags are signed by Conformal so users can ensure the code

View file

@ -130,6 +130,15 @@ func readElement(r io.Reader, element interface{}) error {
}
*e = BitcoinNet(binary.LittleEndian.Uint32(b))
return nil
case *BloomUpdateType:
b := scratch[0:1]
_, err := io.ReadFull(r, b)
if err != nil {
return err
}
*e = BloomUpdateType(b[0])
return nil
}
// Fall back to the slower binary.Read if a fast path was not available
@ -262,6 +271,15 @@ func writeElement(w io.Writer, element interface{}) error {
return err
}
return nil
case BloomUpdateType:
b := scratch[0:1]
b[0] = uint8(e)
_, err := w.Write(b)
if err != nil {
return err
}
return nil
}
// Fall back to the slower binary.Write if a fast path was not available

1
doc.go
View file

@ -153,6 +153,7 @@ This package includes spec changes outlined by the following BIPs:
BIP0014 (https://en.bitcoin.it/wiki/BIP_0014)
BIP0031 (https://en.bitcoin.it/wiki/BIP_0031)
BIP0035 (https://en.bitcoin.it/wiki/BIP_0035)
BIP0037 (https://en.bitcoin.it/wiki/BIP_0037)
Other important information

View file

@ -15,21 +15,31 @@ import (
"io"
)
// MaxMessagePayload makes the internal maxMessagePayload constant available to
// the test package.
const MaxMessagePayload uint32 = maxMessagePayload
const (
// MaxMessagePayload makes the internal maxMessagePayload constant
// available to the test package.
MaxMessagePayload uint32 = maxMessagePayload
// MaxCountSetCancel makes the internal maxCountSetCancel constant available to
// the test package.
const MaxCountSetCancel uint32 = maxCountSetCancel
// MaxTxPerBlock makes the internal maxTxPerBlock constant available to
// the test package.
MaxTxPerBlock = maxTxPerBlock
// MaxCountSetSubVer makes the internal maxCountSetSubVer constant available to
// the test package.
const MaxCountSetSubVer uint32 = maxCountSetSubVer
// MaxFlagsPerMerkleBlock makes the internal maxFlagsPerMerkleBlock
// constant available to the test package.
MaxFlagsPerMerkleBlock = maxFlagsPerMerkleBlock
// CommandSize makes the internal commandSize constant available to the test
// package.
const CommandSize = commandSize
// MaxCountSetCancel makes the internal maxCountSetCancel constant
// available to the test package.
MaxCountSetCancel = maxCountSetCancel
// MaxCountSetSubVer makes the internal maxCountSetSubVer constant
// available to the test package.
MaxCountSetSubVer = maxCountSetSubVer
// CommandSize makes the internal commandSize constant available to the
// test package.
CommandSize = commandSize
)
// TstRandomUint64 makes the internal randomUint64 function available to the
// test package.

View file

@ -44,8 +44,6 @@ type MsgBlock struct {
// AddTransaction adds a transaction to the message.
func (msg *MsgBlock) AddTransaction(tx *MsgTx) error {
// TODO: Return error if adding the transaction would make the message
// too large.
msg.Transactions = append(msg.Transactions, tx)
return nil

View file

@ -16,8 +16,9 @@ const (
MaxFilterAddDataSize = 520
)
// MsgFilterAdd implements the Message interface and represents a bitcoin filteradd
// message which is used to add a data element to an existing Bloom filter.
// MsgFilterAdd implements the Message interface and represents a bitcoin
// filteradd message. It is used to add a data element to an existing Bloom
// filter.
//
// This message was not added until protocol version BIP0037Version.
type MsgFilterAdd struct {
@ -33,19 +34,9 @@ func (msg *MsgFilterAdd) BtcDecode(r io.Reader, pver uint32) error {
return messageError("MsgFilterAdd.BtcDecode", str)
}
size, err := readVarInt(r, pver)
if err != nil {
return err
}
if size > MaxFilterAddDataSize {
str := fmt.Sprintf("filteradd size too large for message "+
"[size %v, max %v]", size, MaxFilterAddDataSize)
return messageError("MsgFilterAdd.BtcDecode", str)
}
msg.Data = make([]byte, size)
_, err = io.ReadFull(r, msg.Data)
var err error
msg.Data, err = readVarBytes(r, pver, MaxFilterAddDataSize,
"filteradd data")
if err != nil {
return err
}
@ -69,12 +60,7 @@ func (msg *MsgFilterAdd) BtcEncode(w io.Writer, pver uint32) error {
return messageError("MsgFilterAdd.BtcEncode", str)
}
err := writeVarInt(w, pver, uint64(size))
if err != nil {
return err
}
err = writeElement(w, msg.Data)
err := writeVarBytes(w, pver, msg.Data)
if err != nil {
return err
}
@ -91,11 +77,12 @@ func (msg *MsgFilterAdd) Command() string {
// MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation.
func (msg *MsgFilterAdd) MaxPayloadLength(pver uint32) uint32 {
return MaxVarIntPayload + MaxFilterAddDataSize
return uint32(VarIntSerializeSize(MaxFilterAddDataSize)) +
MaxFilterAddDataSize
}
// NewMsgFilterAdd returns a new bitcoin filteradd message that conforms to the Message
// interface. See MsgFilterAdd for details.
// NewMsgFilterAdd returns a new bitcoin filteradd message that conforms to the
// Message interface. See MsgFilterAdd for details.
func NewMsgFilterAdd(data []byte) *MsgFilterAdd {
return &MsgFilterAdd{
Data: data,

View file

@ -8,10 +8,12 @@ import (
"bytes"
"github.com/conformal/btcwire"
"io"
"reflect"
"testing"
)
// TestFilterCLearLatest tests the MsgFilterAdd API against the latest protocol version.
// TestFilterAddLatest tests the MsgFilterAdd API against the latest protocol
// version.
func TestFilterAddLatest(t *testing.T) {
pver := btcwire.ProtocolVersion
@ -26,7 +28,7 @@ func TestFilterAddLatest(t *testing.T) {
}
// Ensure max payload is expected value for latest protocol version.
wantPayload := uint32(529)
wantPayload := uint32(523)
maxPayload := msg.MaxPayloadLength(pver)
if maxPayload != wantPayload {
t.Errorf("MaxPayloadLength: wrong max payload length for "+
@ -42,7 +44,7 @@ func TestFilterAddLatest(t *testing.T) {
}
// Test decode with latest protocol version.
readmsg := btcwire.MsgFilterAdd{}
var readmsg btcwire.MsgFilterAdd
err = readmsg.BtcDecode(&buf, pver)
if err != nil {
t.Errorf("decode of MsgFilterAdd failed [%v] err <%v>", buf, err)
@ -51,27 +53,36 @@ func TestFilterAddLatest(t *testing.T) {
return
}
// TestFilterAddCrossProtocol tests the MsgFilterAdd API when encoding with the latest
// protocol version and decoded with BIP0031Version.
// TestFilterAddCrossProtocol tests the MsgFilterAdd API when encoding with the
// latest protocol version and decoding with BIP0031Version.
func TestFilterAddCrossProtocol(t *testing.T) {
data := []byte{0x01, 0x02}
msg := btcwire.NewMsgFilterAdd(data)
if !bytes.Equal(msg.Data, data) {
t.Errorf("should get same data back out")
}
// Encode with old protocol version.
// Encode with latest protocol version.
var buf bytes.Buffer
err := msg.BtcEncode(&buf, btcwire.BIP0037Version-1)
if err == nil {
t.Errorf("encode of MsgFilterAdd succeeded when it shouldn't have %v",
msg)
err := msg.BtcEncode(&buf, btcwire.ProtocolVersion)
if err != nil {
t.Errorf("encode of MsgFilterAdd failed %v err <%v>", msg, err)
}
// Decode with old protocol version.
readmsg := btcwire.MsgFilterAdd{}
var readmsg btcwire.MsgFilterAdd
err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version)
if err == nil {
t.Errorf("decode of MsgFilterAdd succeeded when it shouldn't have %v",
msg)
t.Errorf("decode of MsgFilterAdd succeeded when it shouldn't "+
"have %v", msg)
}
// Since one of the protocol versions doesn't support the filteradd
// message, make sure the data didn't get encoded and decoded back out.
if bytes.Equal(msg.Data, readmsg.Data) {
t.Error("should not get same data for cross protocol")
}
}
// TestFilterAddMaxDataSize tests the MsgFilterAdd API maximum data size.
@ -83,16 +94,16 @@ func TestFilterAddMaxDataSize(t *testing.T) {
var buf bytes.Buffer
err := msg.BtcEncode(&buf, btcwire.ProtocolVersion)
if err == nil {
t.Errorf("encode of MsgFilterAdd succeeded when it shouldn't have %v",
msg)
t.Errorf("encode of MsgFilterAdd succeeded when it shouldn't "+
"have %v", msg)
}
// Decode with latest protocol version.
readbuf := bytes.NewReader(data)
err = msg.BtcDecode(readbuf, btcwire.ProtocolVersion)
if err == nil {
t.Errorf("decode of MsgFilterAdd succeeded when it shouldn't have %v",
msg)
t.Errorf("decode of MsgFilterAdd succeeded when it shouldn't "+
"have %v", msg)
}
}
@ -100,6 +111,12 @@ func TestFilterAddMaxDataSize(t *testing.T) {
// of MsgFilterAdd to confirm error paths work correctly.
func TestFilterAddWireErrors(t *testing.T) {
pver := btcwire.ProtocolVersion
pverNoFilterAdd := btcwire.BIP0037Version - 1
btcwireErr := &btcwire.MessageError{}
baseData := []byte{0x01, 0x02, 0x03, 0x04}
baseFilterAdd := btcwire.NewMsgFilterAdd(baseData)
baseFilterAddEncoded := append([]byte{0x04}, baseData...)
tests := []struct {
in *btcwire.MsgFilterAdd // Value to encode
@ -110,38 +127,20 @@ func TestFilterAddWireErrors(t *testing.T) {
readErr error // Expected read error
}{
// Latest protocol version with intentional read/write errors.
// Force error in data size.
{
&btcwire.MsgFilterAdd{Data: []byte{0x01, 0x02, 0x03, 0x04}},
[]byte{
0x05, // Varint for size of data
0x02, 0x03, 0x04, // Data
},
pver,
2,
io.ErrShortWrite,
io.ErrUnexpectedEOF,
baseFilterAdd, baseFilterAddEncoded, pver, 0,
io.ErrShortWrite, io.EOF,
},
// Force error in data.
{
&btcwire.MsgFilterAdd{Data: []byte{0x01, 0x02, 0x03, 0x04}},
[]byte{
0x05, // Varint for size of data
0x02, 0x03, 0x04, // Data
},
pver,
0,
io.ErrShortWrite,
io.EOF,
baseFilterAdd, baseFilterAddEncoded, pver, 1,
io.ErrShortWrite, io.EOF,
},
// Force error due to unsupported protocol version.
{
&btcwire.MsgFilterAdd{Data: []byte{0x01, 0x02, 0x03, 0x04}},
[]byte{
0x05, // Varint for size of data
0x02, 0x03, 0x04, // Data
},
pver,
1,
io.ErrShortWrite,
io.EOF,
baseFilterAdd, baseFilterAddEncoded, pverNoFilterAdd, 5,
btcwireErr, btcwireErr,
},
}
@ -150,20 +149,40 @@ func TestFilterAddWireErrors(t *testing.T) {
// Encode to wire format.
w := newFixedWriter(test.max)
err := test.in.BtcEncode(w, test.pver)
if err != test.writeErr {
if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) {
t.Errorf("BtcEncode #%d wrong error got: %v, want: %v",
i, err, test.writeErr)
continue
}
// For errors which are not of type btcwire.MessageError, check
// them for equality.
if _, ok := err.(*btcwire.MessageError); !ok {
if err != test.writeErr {
t.Errorf("BtcEncode #%d wrong error got: %v, "+
"want: %v", i, err, test.writeErr)
continue
}
}
// Decode from wire format.
var msg btcwire.MsgFilterAdd
r := newFixedReader(test.max, test.buf)
err = msg.BtcDecode(r, test.pver)
if err != test.readErr {
if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) {
t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
// For errors which are not of type btcwire.MessageError, check
// them for equality.
if _, ok := err.(*btcwire.MessageError); !ok {
if err != test.readErr {
t.Errorf("BtcDecode #%d wrong error got: %v, "+
"want: %v", i, err, test.readErr)
continue
}
}
}
}

View file

@ -9,10 +9,11 @@ import (
"io"
)
// MsgFilterClear implements the Message interface and represents a bitcoin filterclear
// message which is used to reset a Bloom filter.
// MsgFilterClear implements the Message interface and represents a bitcoin
// filterclear message which is used to reset a Bloom filter.
//
// This message was not added until protocol version BIP0037Version.
// This message was not added until protocol version BIP0037Version and has
// no payload.
type MsgFilterClear struct{}
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.

View file

@ -7,10 +7,13 @@ package btcwire_test
import (
"bytes"
"github.com/conformal/btcwire"
"github.com/davecgh/go-spew/spew"
"reflect"
"testing"
)
// TestFilterCLearLatest tests the MsgFilterClear API against the latest protocol version.
// TestFilterCLearLatest tests the MsgFilterClear API against the latest
// protocol version.
func TestFilterClearLatest(t *testing.T) {
pver := btcwire.ProtocolVersion
@ -32,41 +35,162 @@ func TestFilterClearLatest(t *testing.T) {
maxPayload, wantPayload)
}
// Test encode with latest protocol version.
return
}
// TestFilterClearCrossProtocol tests the MsgFilterClear API when encoding with
// the latest protocol version and decoding with BIP0031Version.
func TestFilterClearCrossProtocol(t *testing.T) {
msg := btcwire.NewMsgFilterClear()
// Encode with latest protocol version.
var buf bytes.Buffer
err := msg.BtcEncode(&buf, pver)
err := msg.BtcEncode(&buf, btcwire.ProtocolVersion)
if err != nil {
t.Errorf("encode of MsgFilterClear failed %v err <%v>", msg, err)
}
// Test decode with latest protocol version.
readmsg := btcwire.NewMsgFilterClear()
err = readmsg.BtcDecode(&buf, pver)
if err != nil {
t.Errorf("decode of MsgFilterClear failed [%v] err <%v>", buf, err)
}
return
}
// TestFilterClearCrossProtocol tests the MsgFilterClear API when encoding with the latest
// protocol version and decoded with BIP0031Version.
func TestFilterClearCrossProtocol(t *testing.T) {
msg := btcwire.NewMsgFilterClear()
// Encode with old protocol version.
var buf bytes.Buffer
err := msg.BtcEncode(&buf, btcwire.BIP0037Version-1)
if err == nil {
t.Errorf("encode of MsgFilterClear succeeded when it shouldn't have %v",
msg)
}
// Decode with old protocol version.
readmsg := btcwire.NewMsgFilterClear()
var readmsg btcwire.MsgFilterClear
err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version)
if err == nil {
t.Errorf("decode of MsgFilterClear succeeded when it shouldn't have %v",
msg)
t.Errorf("decode of MsgFilterClear succeeded when it "+
"shouldn't have %v", msg)
}
}
// TestFilterClearWire tests the MsgFilterClear wire encode and decode for
// various protocol versions.
func TestFilterClearWire(t *testing.T) {
msgFilterClear := btcwire.NewMsgFilterClear()
msgFilterClearEncoded := []byte{}
tests := []struct {
in *btcwire.MsgFilterClear // Message to encode
out *btcwire.MsgFilterClear // Expected decoded message
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
}{
// Latest protocol version.
{
msgFilterClear,
msgFilterClear,
msgFilterClearEncoded,
btcwire.ProtocolVersion,
},
// Protocol version BIP0037Version + 1.
{
msgFilterClear,
msgFilterClear,
msgFilterClearEncoded,
btcwire.BIP0037Version + 1,
},
// Protocol version BIP0037Version.
{
msgFilterClear,
msgFilterClear,
msgFilterClearEncoded,
btcwire.BIP0037Version,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode the message to wire format.
var buf bytes.Buffer
err := test.in.BtcEncode(&buf, test.pver)
if err != nil {
t.Errorf("BtcEncode #%d error %v", i, err)
continue
}
if !bytes.Equal(buf.Bytes(), test.buf) {
t.Errorf("BtcEncode #%d\n got: %s want: %s", i,
spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
continue
}
// Decode the message from wire format.
var msg btcwire.MsgFilterClear
rbuf := bytes.NewBuffer(test.buf)
err = msg.BtcDecode(rbuf, test.pver)
if err != nil {
t.Errorf("BtcDecode #%d error %v", i, err)
continue
}
if !reflect.DeepEqual(&msg, test.out) {
t.Errorf("BtcDecode #%d\n got: %s want: %s", i,
spew.Sdump(msg), spew.Sdump(test.out))
continue
}
}
}
// TestFilterClearWireErrors performs negative tests against wire encode and
// decode of MsgFilterClear to confirm error paths work correctly.
func TestFilterClearWireErrors(t *testing.T) {
pverNoFilterClear := btcwire.BIP0037Version - 1
btcwireErr := &btcwire.MessageError{}
baseFilterClear := btcwire.NewMsgFilterClear()
baseFilterClearEncoded := []byte{}
tests := []struct {
in *btcwire.MsgFilterClear // 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 error due to unsupported protocol version.
{
baseFilterClear, baseFilterClearEncoded,
pverNoFilterClear, 4, btcwireErr, btcwireErr,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
w := newFixedWriter(test.max)
err := test.in.BtcEncode(w, test.pver)
if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) {
t.Errorf("BtcEncode #%d wrong error got: %v, want: %v",
i, err, test.writeErr)
continue
}
// For errors which are not of type btcwire.MessageError, check
// them for equality.
if _, ok := err.(*btcwire.MessageError); !ok {
if err != test.writeErr {
t.Errorf("BtcEncode #%d wrong error got: %v, "+
"want: %v", i, err, test.writeErr)
continue
}
}
// Decode from wire format.
var msg btcwire.MsgFilterClear
r := newFixedReader(test.max, test.buf)
err = msg.BtcDecode(r, test.pver)
if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) {
t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
// For errors which are not of type btcwire.MessageError, check
// them for equality.
if _, ok := err.(*btcwire.MessageError); !ok {
if err != test.readErr {
t.Errorf("BtcDecode #%d wrong error got: %v, "+
"want: %v", i, err, test.readErr)
continue
}
}
}
}

View file

@ -9,33 +9,37 @@ import (
"io"
)
// BloomUpdateType specifies how the filter is updated when a match is found
type BloomUpdateType uint8
const (
// BloomUpdateNone indicates the filter is not adjusted when a match is found.
// BloomUpdateNone indicates the filter is not adjusted when a match is
// found.
BloomUpdateNone BloomUpdateType = 0
// BloomUpdateAll indicates if the filter matches any data element in a
// scriptPubKey, the outpoint is serialized and inserted into the filter.
// public key script, the outpoint is serialized and inserted into the
// filter.
BloomUpdateAll BloomUpdateType = 1
// BloomUpdateP2PubkeyOnly indicates if the filter matches a data element in
// a scriptPubkey and the script is of the standard payToPybKey or payToMultiSig,
// the outpoint is inserted into the filter.
// BloomUpdateP2PubkeyOnly indicates if the filter matches a data
// element in a public key script and the script is of the standard
// pay-to-pubkey or multisig, the outpoint is serialized and inserted
// into the filter.
BloomUpdateP2PubkeyOnly BloomUpdateType = 2
)
const (
// MaxFilterLoadHashFuncs is the maximum number of hash functions to load
// into the Bloom filter.
// MaxFilterLoadHashFuncs is the maximum number of hash functions to
// load into the Bloom filter.
MaxFilterLoadHashFuncs = 50
// MaxFilterLoadFilterSize is the maximum size in bytes a filter may be.
MaxFilterLoadFilterSize = 36000
)
// MsgFilterLoad implements the Message interface and represents a bitcoin filterload
// message which is used to reset a Bloom filter.
// MsgFilterLoad implements the Message interface and represents a bitcoin
// filterload message which is used to reset a Bloom filter.
//
// This message was not added until protocol version BIP0037Version.
type MsgFilterLoad struct {
@ -54,19 +58,9 @@ func (msg *MsgFilterLoad) BtcDecode(r io.Reader, pver uint32) error {
return messageError("MsgFilterLoad.BtcDecode", str)
}
// Read num filter and limit to max.
size, err := readVarInt(r, pver)
if err != nil {
return err
}
if size > MaxFilterLoadFilterSize {
str := fmt.Sprintf("filterload filter size too large for message "+
"[size %v, max %v]", size, MaxFilterLoadFilterSize)
return messageError("MsgFilterLoad.BtcDecode", str)
}
msg.Filter = make([]byte, size)
_, err = io.ReadFull(r, msg.Filter)
var err error
msg.Filter, err = readVarBytes(r, pver, MaxFilterLoadFilterSize,
"filterload filter size")
if err != nil {
return err
}
@ -107,11 +101,12 @@ func (msg *MsgFilterLoad) BtcEncode(w io.Writer, pver uint32) error {
return messageError("MsgFilterLoad.BtcEncode", str)
}
err := writeVarInt(w, pver, uint64(size))
err := writeVarBytes(w, pver, msg.Filter)
if err != nil {
return err
}
err = writeElements(w, msg.Filter, msg.HashFuncs, msg.Tweak, msg.Flags)
err = writeElements(w, msg.HashFuncs, msg.Tweak, msg.Flags)
if err != nil {
return err
}
@ -119,23 +114,6 @@ func (msg *MsgFilterLoad) BtcEncode(w io.Writer, pver uint32) error {
return nil
}
// Serialize encodes the transaction to w using a format that suitable for
// long-term storage such as a database while respecting the Version field in
// the transaction. This function differs from BtcEncode in that BtcEncode
// encodes the transaction to the bitcoin wire protocol in order to be sent
// across the network. The wire encoding can technically differ depending on
// the protocol version and doesn't even really need to match the format of a
// stored transaction at all. As of the time this comment was written, the
// encoded transaction is the same in both instances, but there is a distinct
// difference and separating the two allows the API to be flexible enough to
// deal with changes.
func (msg *MsgFilterLoad) Serialize(w io.Writer) error {
// At the current time, there is no difference between the wire encoding
// at protocol version 0 and the stable long-term storage format. As
// a result, make use of BtcEncode.
return msg.BtcEncode(w, BIP0037Version)
}
// Command returns the protocol command string for the message. This is part
// of the Message interface implementation.
func (msg *MsgFilterLoad) Command() string {
@ -145,11 +123,14 @@ func (msg *MsgFilterLoad) Command() string {
// MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation.
func (msg *MsgFilterLoad) MaxPayloadLength(pver uint32) uint32 {
return MaxVarIntPayload + MaxFilterLoadFilterSize + 4 + 4 + 1
// Num filter bytes (varInt) + filter + 4 bytes hash funcs +
// 4 bytes tweak + 1 byte flags.
return uint32(VarIntSerializeSize(MaxFilterLoadFilterSize)) +
MaxFilterLoadFilterSize + 9
}
// NewMsgFilterLoad returns a new bitcoin filterload message that conforms to the Message
// interface. See MsgFilterLoad for details.
// NewMsgFilterLoad returns a new bitcoin filterload message that conforms to
// the Message interface. See MsgFilterLoad for details.
func NewMsgFilterLoad(filter []byte, hashFuncs uint32, tweak uint32, flags BloomUpdateType) *MsgFilterLoad {
return &MsgFilterLoad{
Filter: filter,

View file

@ -8,10 +8,12 @@ import (
"bytes"
"github.com/conformal/btcwire"
"io"
"reflect"
"testing"
)
// TestFilterCLearLatest tests the MsgFilterLoad API against the latest protocol version.
// TestFilterCLearLatest tests the MsgFilterLoad API against the latest protocol
// version.
func TestFilterLoadLatest(t *testing.T) {
pver := btcwire.ProtocolVersion
@ -25,8 +27,8 @@ func TestFilterLoadLatest(t *testing.T) {
cmd, wantCmd)
}
// Ensure max payadd is expected value for latest protocol version.
wantPayload := uint32(36018)
// Ensure max payload is expected value for latest protocol version.
wantPayload := uint32(36012)
maxPayload := msg.MaxPayloadLength(pver)
if maxPayload != wantPayload {
t.Errorf("MaxPayLoadLength: wrong max payload length for "+
@ -51,22 +53,22 @@ func TestFilterLoadLatest(t *testing.T) {
return
}
// TestFilterLoadCrossProtocol tests the MsgFilterLoad API when encoding with the latest
// protocol version and decoded with BIP0031Version.
// TestFilterLoadCrossProtocol tests the MsgFilterLoad API when encoding with
// the latest protocol version and decoding with BIP0031Version.
func TestFilterLoadCrossProtocol(t *testing.T) {
data := []byte{0x01, 0x02}
msg := btcwire.NewMsgFilterLoad(data, 10, 0, 0)
// Encode with old protocol version.
// Encode with latest protocol version.
var buf bytes.Buffer
err := msg.BtcEncode(&buf, btcwire.BIP0037Version-1)
if err == nil {
t.Errorf("encode of MsgFilterLoad succeeded when it shouldn't have %v",
msg)
err := msg.BtcEncode(&buf, btcwire.ProtocolVersion)
if err != nil {
t.Errorf("encode of NewMsgFilterLoad failed %v err <%v>", msg,
err)
}
// Decode with old protocol version.
readmsg := btcwire.MsgFilterLoad{}
var readmsg btcwire.MsgFilterLoad
err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version)
if err == nil {
t.Errorf("decode of MsgFilterLoad succeeded when it shouldn't have %v",
@ -83,16 +85,16 @@ func TestFilterLoadMaxFilterSize(t *testing.T) {
var buf bytes.Buffer
err := msg.BtcEncode(&buf, btcwire.ProtocolVersion)
if err == nil {
t.Errorf("encode of MsgFilterLoad succeeded when it shouldn't have %v",
msg)
t.Errorf("encode of MsgFilterLoad succeeded when it shouldn't "+
"have %v", msg)
}
// Decode with latest protocol version.
readbuf := bytes.NewReader(data)
err = msg.BtcDecode(readbuf, btcwire.ProtocolVersion)
if err == nil {
t.Errorf("decode of MsgFilterLoad succeeded when it shouldn't have %v",
msg)
t.Errorf("decode of MsgFilterLoad succeeded when it shouldn't "+
"have %v", msg)
}
}
@ -130,6 +132,17 @@ func TestFilterLoadMaxHashFuncsSize(t *testing.T) {
// of MsgFilterLoad to confirm error paths work correctly.
func TestFilterLoadWireErrors(t *testing.T) {
pver := btcwire.ProtocolVersion
pverNoFilterLoad := btcwire.BIP0037Version - 1
btcwireErr := &btcwire.MessageError{}
baseFilter := []byte{0x01, 0x02, 0x03, 0x04}
baseFilterLoad := btcwire.NewMsgFilterLoad(baseFilter, 10, 0,
btcwire.BloomUpdateNone)
baseFilterLoadEncoded := append([]byte{0x04}, baseFilter...)
baseFilterLoadEncoded = append(baseFilterLoadEncoded,
0x00, 0x00, 0x00, 0x0a, // HashFuncs
0x00, 0x00, 0x00, 0x00, // Tweak
0x00) // Flags
tests := []struct {
in *btcwire.MsgFilterLoad // Value to encode
@ -140,62 +153,35 @@ func TestFilterLoadWireErrors(t *testing.T) {
readErr error // Expected read error
}{
// Latest protocol version with intentional read/write errors.
// Force error in filter size.
{
&btcwire.MsgFilterLoad{
Filter: []byte{0x01, 0x02, 0x03, 0x04},
HashFuncs: 10,
Tweak: 0,
Flags: btcwire.BloomUpdateNone,
},
[]byte{
0x04, // Varint for size of Filter
0x01, 0x02, 0x03, 0x04, // Filter
0x00, 0x0a, // HashFuncs
0x00, 0x00, // Tweak
0x00, // Flags
},
pver,
2,
io.ErrShortWrite,
io.ErrUnexpectedEOF,
baseFilterLoad, baseFilterLoadEncoded, pver, 0,
io.ErrShortWrite, io.EOF,
},
// Force error in filter.
{
&btcwire.MsgFilterLoad{
Filter: []byte{0x01, 0x02, 0x03, 0x04},
HashFuncs: 10,
Tweak: 0,
Flags: btcwire.BloomUpdateNone,
},
[]byte{
0x04, // Varint for size of Filter
0x01, 0x02, 0x03, 0x04, // Filter
0x00, 0x0a, // HashFuncs
0x00, 0x00, // Tweak
0x00, // Flags
},
pver,
0,
io.ErrShortWrite,
io.EOF,
baseFilterLoad, baseFilterLoadEncoded, pver, 1,
io.ErrShortWrite, io.EOF,
},
// Force error in hash funcs.
{
&btcwire.MsgFilterLoad{
Filter: []byte{0x01, 0x02, 0x03, 0x04},
HashFuncs: 10,
Tweak: 0,
Flags: btcwire.BloomUpdateNone,
},
[]byte{
0x04, // Varint for size of Filter
0x01, 0x02, 0x03, 0x04, // Filter
0x00, 0x0a, // HashFuncs
0x00, 0x00, // Tweak
0x00, // Flags
},
pver,
10,
io.ErrShortWrite,
io.ErrUnexpectedEOF,
baseFilterLoad, baseFilterLoadEncoded, pver, 5,
io.ErrShortWrite, io.EOF,
},
// Force error in tweak.
{
baseFilterLoad, baseFilterLoadEncoded, pver, 9,
io.ErrShortWrite, io.EOF,
},
// Force error in flags.
{
baseFilterLoad, baseFilterLoadEncoded, pver, 13,
io.ErrShortWrite, io.EOF,
},
// Force error due to unsupported protocol version.
{
baseFilterLoad, baseFilterLoadEncoded, pverNoFilterLoad,
10, btcwireErr, btcwireErr,
},
}
@ -204,20 +190,41 @@ func TestFilterLoadWireErrors(t *testing.T) {
// Encode to wire format.
w := newFixedWriter(test.max)
err := test.in.BtcEncode(w, test.pver)
if err != test.writeErr {
if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) {
t.Errorf("BtcEncode #%d wrong error got: %v, want: %v",
i, err, test.writeErr)
continue
}
// For errors which are not of type btcwire.MessageError, check
// them for equality.
if _, ok := err.(*btcwire.MessageError); !ok {
if err != test.writeErr {
t.Errorf("BtcEncode #%d wrong error got: %v, "+
"want: %v", i, err, test.writeErr)
continue
}
}
// Decode from wire format.
var msg btcwire.MsgFilterLoad
r := newFixedReader(test.max, test.buf)
err = msg.BtcDecode(r, test.pver)
if err != test.readErr {
if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) {
t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
// For errors which are not of type btcwire.MessageError, check
// them for equality.
if _, ok := err.(*btcwire.MessageError); !ok {
if err != test.readErr {
t.Errorf("BtcDecode #%d wrong error got: %v, "+
"want: %v", i, err, test.readErr)
continue
}
}
}
}

View file

@ -9,8 +9,14 @@ import (
"io"
)
// MsgMerkleBlock implements the Message interface and represents a bitcoin merkleblock
// message which is used to reset a Bloom filter.
// maxFlagsPerMerkleBlock is the maximum number of flag bytes that could
// possibly fit into a merkle block. Since each transaction is represented by
// a single bit, this is the max number of transactions per block divided by
// 8 bits per byte. Then an extra one to cover partials.
const maxFlagsPerMerkleBlock = maxTxPerBlock / 8
// MsgMerkleBlock implements the Message interface and represents a bitcoin
// merkleblock message which is used to reset a Bloom filter.
//
// This message was not added until protocol version BIP0037Version.
type MsgMerkleBlock struct {
@ -64,7 +70,7 @@ func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32) error {
msg.Hashes = make([]*ShaHash, 0, count)
for i := uint64(0); i < count; i++ {
sha := ShaHash{}
var sha ShaHash
err := readElement(r, &sha)
if err != nil {
return err
@ -72,13 +78,8 @@ func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32) error {
msg.AddTxHash(&sha)
}
count, err = readVarInt(r, pver)
if err != nil {
return err
}
msg.Flags = make([]byte, 0, count)
err = readElement(r, &msg.Flags)
msg.Flags, err = readVarBytes(r, pver, maxFlagsPerMerkleBlock,
"merkle block flags size")
if err != nil {
return err
}
@ -96,10 +97,16 @@ func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32) error {
}
// Read num transaction hashes and limit to max.
count := len(msg.Hashes)
if count > maxTxPerBlock {
numHashes := len(msg.Hashes)
if numHashes > maxTxPerBlock {
str := fmt.Sprintf("too many transaction hashes for message "+
"[count %v, max %v]", count, maxTxPerBlock)
"[count %v, max %v]", numHashes, maxTxPerBlock)
return messageError("MsgMerkleBlock.BtcDecode", str)
}
numFlagBytes := len(msg.Flags)
if numFlagBytes > maxFlagsPerMerkleBlock {
str := fmt.Sprintf("too many flag bytes for message [count %v, "+
"max %v]", numFlagBytes, maxFlagsPerMerkleBlock)
return messageError("MsgMerkleBlock.BtcDecode", str)
}
@ -113,11 +120,10 @@ func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32) error {
return err
}
err = writeVarInt(w, pver, uint64(count))
err = writeVarInt(w, pver, uint64(numHashes))
if err != nil {
return err
}
for _, hash := range msg.Hashes {
err = writeElement(w, hash)
if err != nil {
@ -125,12 +131,10 @@ func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32) error {
}
}
count = len(msg.Flags)
err = writeVarInt(w, pver, uint64(count))
err = writeVarInt(w, pver, uint64(numFlagBytes))
if err != nil {
return err
}
err = writeElement(w, msg.Flags)
if err != nil {
return err
@ -151,8 +155,8 @@ func (msg *MsgMerkleBlock) MaxPayloadLength(pver uint32) uint32 {
return MaxBlockPayload
}
// NewMsgMerkleBlock returns a new bitcoin merkleblock message that conforms to the Message
// interface. See MsgMerkleBlock for details.
// NewMsgMerkleBlock returns a new bitcoin merkleblock message that conforms to
// the Message interface. See MsgMerkleBlock for details.
func NewMsgMerkleBlock(bh *BlockHeader) *MsgMerkleBlock {
return &MsgMerkleBlock{
Header: *bh,

View file

@ -8,13 +8,16 @@ import (
"bytes"
"crypto/rand"
"github.com/conformal/btcwire"
"github.com/davecgh/go-spew/spew"
"io"
"reflect"
"testing"
"time"
)
// TestMerkleBlock tests the MsgMerkleBlock API.
func TestMerkleBlock(t *testing.T) {
pver := btcwire.ProtocolVersion
pverOld := btcwire.BIP0037Version - 1
// Block 1 header.
prevHash := &blockOne.Header.PrevBlock
@ -43,7 +46,7 @@ func TestMerkleBlock(t *testing.T) {
// Load maxTxPerBlock hashes
data := make([]byte, 32)
for i := 0; i < (btcwire.MaxBlockPayload/10)+1; i++ {
for i := 0; i < btcwire.MaxTxPerBlock; i++ {
rand.Read(data)
hash, err := btcwire.NewShaHash(data)
if err != nil {
@ -57,7 +60,7 @@ func TestMerkleBlock(t *testing.T) {
}
}
// Add one more Tx to test failure
// Add one more Tx to test failure.
rand.Read(data)
hash, err := btcwire.NewShaHash(data)
if err != nil {
@ -77,13 +80,6 @@ func TestMerkleBlock(t *testing.T) {
t.Errorf("encode of MsgMerkleBlock failed %v err <%v>", msg, err)
}
// Test encode with old protocol version.
if err = msg.BtcEncode(&buf, pverOld); err == nil {
t.Errorf("encode of MsgMerkleBlock succeeded with old protocol " +
"version when it should have failed")
return
}
// Test decode with latest protocol version.
readmsg := btcwire.MsgMerkleBlock{}
err = readmsg.BtcDecode(&buf, pver)
@ -91,19 +87,339 @@ func TestMerkleBlock(t *testing.T) {
t.Errorf("decode of MsgMerkleBlock failed [%v] err <%v>", buf, err)
}
// Test decode with old protocol version.
if err = readmsg.BtcDecode(&buf, pverOld); err == nil {
t.Errorf("decode of MsgMerkleBlock successed with old protocol " +
"version when it should have failed")
return
}
// Force extra hash to test maxTxPerBlock
// Force extra hash to test maxTxPerBlock.
msg.Hashes = append(msg.Hashes, hash)
err = msg.BtcEncode(&buf, pver)
if err == nil {
t.Errorf("encode of MsgMerkleBlock succeeded with too many tx hashes " +
"when it should have failed")
t.Errorf("encode of MsgMerkleBlock succeeded with too many " +
"tx hashes when it should have failed")
return
}
// Force too many flag bytes to test maxFlagsPerMerkleBlock.
// Reset the number of hashes back to a valid value.
msg.Hashes = msg.Hashes[len(msg.Hashes)-1:]
msg.Flags = make([]byte, btcwire.MaxFlagsPerMerkleBlock+1)
err = msg.BtcEncode(&buf, pver)
if err == nil {
t.Errorf("encode of MsgMerkleBlock succeeded with too many " +
"flag bytes when it should have failed")
return
}
}
// TestMerkleBlockCrossProtocol tests the MsgMerkleBlock API when encoding with
// the latest protocol version and decoding with BIP0031Version.
func TestMerkleBlockCrossProtocol(t *testing.T) {
// Block 1 header.
prevHash := &blockOne.Header.PrevBlock
merkleHash := &blockOne.Header.MerkleRoot
bits := blockOne.Header.Bits
nonce := blockOne.Header.Nonce
bh := btcwire.NewBlockHeader(prevHash, merkleHash, bits, nonce)
msg := btcwire.NewMsgMerkleBlock(bh)
// Encode with latest protocol version.
var buf bytes.Buffer
err := msg.BtcEncode(&buf, btcwire.ProtocolVersion)
if err != nil {
t.Errorf("encode of NewMsgFilterLoad failed %v err <%v>", msg,
err)
}
// Decode with old protocol version.
var readmsg btcwire.MsgFilterLoad
err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version)
if err == nil {
t.Errorf("decode of MsgFilterLoad succeeded when it shouldn't have %v",
msg)
}
}
// TestMerkleBlockWire tests the MsgMerkleBlock wire encode and decode for
// various numbers of transaction hashes and protocol versions.
func TestMerkleBlockWire(t *testing.T) {
tests := []struct {
in *btcwire.MsgMerkleBlock // Message to encode
out *btcwire.MsgMerkleBlock // Expected decoded message
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
}{
// Latest protocol version.
{
&merkleBlockOne, &merkleBlockOne, merkleBlockOneBytes,
btcwire.ProtocolVersion,
},
// Protocol version BIP0037Version.
{
&merkleBlockOne, &merkleBlockOne, merkleBlockOneBytes,
btcwire.BIP0037Version,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode the message to wire format.
var buf bytes.Buffer
err := test.in.BtcEncode(&buf, test.pver)
if err != nil {
t.Errorf("BtcEncode #%d error %v", i, err)
continue
}
if !bytes.Equal(buf.Bytes(), test.buf) {
t.Errorf("BtcEncode #%d\n got: %s want: %s", i,
spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
continue
}
// Decode the message from wire format.
var msg btcwire.MsgMerkleBlock
rbuf := bytes.NewBuffer(test.buf)
err = msg.BtcDecode(rbuf, test.pver)
if err != nil {
t.Errorf("BtcDecode #%d error %v", i, err)
continue
}
if !reflect.DeepEqual(&msg, test.out) {
t.Errorf("BtcDecode #%d\n got: %s want: %s", i,
spew.Sdump(&msg), spew.Sdump(test.out))
continue
}
}
}
// TestMerkleBlockWireErrors performs negative tests against wire encode and
// decode of MsgBlock to confirm error paths work correctly.
func TestMerkleBlockWireErrors(t *testing.T) {
// Use protocol version 70001 specifically here instead of the latest
// because the test data is using bytes encoded with that protocol
// version.
pver := uint32(70001)
pverNoMerkleBlock := btcwire.BIP0037Version - 1
btcwireErr := &btcwire.MessageError{}
tests := []struct {
in *btcwire.MsgMerkleBlock // 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 error in version.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 0,
io.ErrShortWrite, io.EOF,
},
// Force error in prev block hash.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 4,
io.ErrShortWrite, io.EOF,
},
// Force error in merkle root.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 36,
io.ErrShortWrite, io.EOF,
},
// Force error in timestamp.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 68,
io.ErrShortWrite, io.EOF,
},
// Force error in difficulty bits.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 72,
io.ErrShortWrite, io.EOF,
},
// Force error in header nonce.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 76,
io.ErrShortWrite, io.EOF,
},
// Force error in transaction count.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 80,
io.ErrShortWrite, io.EOF,
},
// Force error in num hashes.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 84,
io.ErrShortWrite, io.EOF,
},
// Force error in hashes.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 85,
io.ErrShortWrite, io.EOF,
},
// Force error in num flag bytes.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 117,
io.ErrShortWrite, io.EOF,
},
// Force error in flag bytes.
{
&merkleBlockOne, merkleBlockOneBytes, pver, 118,
io.ErrShortWrite, io.EOF,
},
// Force error due to unsupported protocol version.
{
&merkleBlockOne, merkleBlockOneBytes, pverNoMerkleBlock,
119, btcwireErr, btcwireErr,
},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Encode to wire format.
w := newFixedWriter(test.max)
err := test.in.BtcEncode(w, test.pver)
if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) {
t.Errorf("BtcEncode #%d wrong error got: %v, want: %v",
i, err, test.writeErr)
continue
}
// For errors which are not of type btcwire.MessageError, check
// them for equality.
if _, ok := err.(*btcwire.MessageError); !ok {
if err != test.writeErr {
t.Errorf("BtcEncode #%d wrong error got: %v, "+
"want: %v", i, err, test.writeErr)
continue
}
}
// Decode from wire format.
var msg btcwire.MsgMerkleBlock
r := newFixedReader(test.max, test.buf)
err = msg.BtcDecode(r, test.pver)
if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) {
t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
i, err, test.readErr)
continue
}
// For errors which are not of type btcwire.MessageError, check
// them for equality.
if _, ok := err.(*btcwire.MessageError); !ok {
if err != test.readErr {
t.Errorf("BtcDecode #%d wrong error got: %v, "+
"want: %v", i, err, test.readErr)
continue
}
}
}
}
// TestMerkleBlockOverflowErrors performs tests to ensure encoding and decoding
// merkle blocks that are intentionally crafted to use large values for the
// number of hashes and flags are handled properly. This could otherwise
// potentially be used as an attack vector.
func TestMerkleBlockOverflowErrors(t *testing.T) {
// Use protocol version 70001 specifically here instead of the latest
// protocol version because the test data is using bytes encoded with
// that version.
pver := uint32(70001)
// Create bytes for a merkle block that claims to have more than the max
// allowed tx hashes.
var buf bytes.Buffer
btcwire.TstWriteVarInt(&buf, pver, btcwire.MaxTxPerBlock+1)
numHashesOffset := 84
exceedMaxHashes := make([]byte, numHashesOffset)
copy(exceedMaxHashes, merkleBlockOneBytes[:numHashesOffset])
exceedMaxHashes = append(exceedMaxHashes, buf.Bytes()...)
// Create bytes for a merkle block that claims to have more than the max
// allowed flag bytes.
buf.Reset()
btcwire.TstWriteVarInt(&buf, pver, btcwire.MaxFlagsPerMerkleBlock+1)
numFlagBytesOffset := 117
exceedMaxFlagBytes := make([]byte, numFlagBytesOffset)
copy(exceedMaxFlagBytes, merkleBlockOneBytes[:numFlagBytesOffset])
exceedMaxFlagBytes = append(exceedMaxFlagBytes, buf.Bytes()...)
tests := []struct {
buf []byte // Wire encoding
pver uint32 // Protocol version for wire encoding
err error // Expected error
}{
// Block that claims to have more than max allowed hashes.
{exceedMaxHashes, pver, &btcwire.MessageError{}},
// Block that claims to have more than max allowed flag bytes.
{exceedMaxFlagBytes, pver, &btcwire.MessageError{}},
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
// Decode from wire format.
var msg btcwire.MsgMerkleBlock
r := bytes.NewReader(test.buf)
err := msg.BtcDecode(r, test.pver)
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
i, err, reflect.TypeOf(test.err))
continue
}
}
}
// merkleBlockOne is a merkle block created from block one of the block chain
// where the first transaction matches.
var merkleBlockOne = btcwire.MsgMerkleBlock{
Header: btcwire.BlockHeader{
Version: 1,
PrevBlock: btcwire.ShaHash([btcwire.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,
}),
MerkleRoot: btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy.
0x98, 0x20, 0x51, 0xfd, 0x1e, 0x4b, 0xa7, 0x44,
0xbb, 0xbe, 0x68, 0x0e, 0x1f, 0xee, 0x14, 0x67,
0x7b, 0xa1, 0xa3, 0xc3, 0x54, 0x0b, 0xf7, 0xb1,
0xcd, 0xb6, 0x06, 0xe8, 0x57, 0x23, 0x3e, 0x0e,
}),
Timestamp: time.Unix(0x4966bc61, 0), // 2009-01-08 20:54:25 -0600 CST
Bits: 0x1d00ffff, // 486604799
Nonce: 0x9962e301, // 2573394689
},
Transactions: 1,
Hashes: []*btcwire.ShaHash{
(*btcwire.ShaHash)(&[btcwire.HashSize]byte{ // Make go vet happy.
0x98, 0x20, 0x51, 0xfd, 0x1e, 0x4b, 0xa7, 0x44,
0xbb, 0xbe, 0x68, 0x0e, 0x1f, 0xee, 0x14, 0x67,
0x7b, 0xa1, 0xa3, 0xc3, 0x54, 0x0b, 0xf7, 0xb1,
0xcd, 0xb6, 0x06, 0xe8, 0x57, 0x23, 0x3e, 0x0e,
}),
},
Flags: []byte{0x80},
}
// merkleBlockOneBytes is the serialized bytes for a merkle block created from
// block one of the block chain where the first transation matches.
var merkleBlockOneBytes = []byte{
0x01, 0x00, 0x00, 0x00, // Version 1
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, // PrevBlock
0x98, 0x20, 0x51, 0xfd, 0x1e, 0x4b, 0xa7, 0x44,
0xbb, 0xbe, 0x68, 0x0e, 0x1f, 0xee, 0x14, 0x67,
0x7b, 0xa1, 0xa3, 0xc3, 0x54, 0x0b, 0xf7, 0xb1,
0xcd, 0xb6, 0x06, 0xe8, 0x57, 0x23, 0x3e, 0x0e, // MerkleRoot
0x61, 0xbc, 0x66, 0x49, // Timestamp
0xff, 0xff, 0x00, 0x1d, // Bits
0x01, 0xe3, 0x62, 0x99, // Nonce
0x01, 0x00, 0x00, 0x00, // TxnCount
0x01, // Num hashes
0x98, 0x20, 0x51, 0xfd, 0x1e, 0x4b, 0xa7, 0x44,
0xbb, 0xbe, 0x68, 0x0e, 0x1f, 0xee, 0x14, 0x67,
0x7b, 0xa1, 0xa3, 0xc3, 0x54, 0x0b, 0xf7, 0xb1,
0xcd, 0xb6, 0x06, 0xe8, 0x57, 0x23, 0x3e, 0x0e, // Hash
0x01, // Num flag bytes
0x80, // Flags
}

View file

@ -96,7 +96,7 @@ func TestPingBIP0031(t *testing.T) {
}
// TestPingCrossProtocol tests the MsgPing API when encoding with the latest
// protocol version and decoded with BIP0031Version.
// protocol version and decoding with BIP0031Version.
func TestPingCrossProtocol(t *testing.T) {
nonce, err := btcwire.RandomUint64()
if err != nil {

View file

@ -113,7 +113,7 @@ func TestPongBIP0031(t *testing.T) {
}
// TestPongCrossProtocol tests the MsgPong API when encoding with the latest
// protocol version and decoded with BIP0031Version.
// protocol version and decoding with BIP0031Version.
func TestPongCrossProtocol(t *testing.T) {
nonce, err := btcwire.RandomUint64()
if err != nil {
@ -140,7 +140,7 @@ func TestPongCrossProtocol(t *testing.T) {
}
// Since one of the protocol versions doesn't support the pong message,
// make sure the nonce didn't get encoded and decoded back out.
// make sure the nonce didn't get encoded and decoded back out.
if msg.Nonce == readmsg.Nonce {
t.Error("Should not get same nonce for cross protocol")
}