From b4ebd0057bfaf02fe74ee9a892a71fe21548e6ff Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 8 May 2013 14:16:41 -0500 Subject: [PATCH 001/219] Initial commit. --- .gitignore | 33 +++++++++++++++++++++++++++++++++ README.md | 4 ++++ 2 files changed, 37 insertions(+) create mode 100644 .gitignore create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..16e35934 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Temp files +*~ + +# Databases +btcd.db +*-shm +*-wal + +# Log files +*.log + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/README.md b/README.md new file mode 100644 index 00000000..90fb26df --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +btcwire +======= + +Package btcwire implements the bitcoin wire protocol. \ No newline at end of file From 69b27dd5d3effb7229e9cc759e87ec9836ce3942 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 8 May 2013 14:31:00 -0500 Subject: [PATCH 002/219] Initial implementation. --- LICENSE | 13 ++ README.md | 122 ++++++++++++- blockheader.go | 119 +++++++++++++ blockheader_test.go | 160 +++++++++++++++++ common.go | 181 ++++++++++++++++++++ common_test.go | 304 +++++++++++++++++++++++++++++++++ cov_report.sh | 17 ++ doc.go | 163 ++++++++++++++++++ fakeconn_test.go | 62 +++++++ fakemessage_test.go | 40 +++++ fixedIO_test.go | 67 ++++++++ genesis.go | 83 +++++++++ genesis_test.go | 87 ++++++++++ internal_test.go | 100 +++++++++++ invvect.go | 79 +++++++++ invvect_test.go | 268 +++++++++++++++++++++++++++++ message.go | 286 +++++++++++++++++++++++++++++++ message_test.go | 98 +++++++++++ msgaddr.go | 136 +++++++++++++++ msgaddr_test.go | 205 ++++++++++++++++++++++ msgalert.go | 80 +++++++++ msgalert_test.go | 139 +++++++++++++++ msgblock.go | 163 ++++++++++++++++++ msgblock_test.go | 292 +++++++++++++++++++++++++++++++ msggetaddr.go | 47 +++++ msggetaddr_test.go | 122 +++++++++++++ msggetblocks.go | 140 +++++++++++++++ msggetblocks_test.go | 259 ++++++++++++++++++++++++++++ msggetdata.go | 105 ++++++++++++ msggetdata_test.go | 222 ++++++++++++++++++++++++ msggetheaders.go | 135 +++++++++++++++ msggetheaders_test.go | 248 +++++++++++++++++++++++++++ msgheaders.go | 119 +++++++++++++ msgheaders_test.go | 219 ++++++++++++++++++++++++ msginv.go | 104 ++++++++++++ msginv_test.go | 222 ++++++++++++++++++++++++ msgmempool.go | 58 +++++++ msgmempool_test.go | 65 +++++++ msgnotfound.go | 103 +++++++++++ msgnotfound_test.go | 222 ++++++++++++++++++++++++ msgping.go | 87 ++++++++++ msgping_test.go | 194 +++++++++++++++++++++ msgpong.go | 88 ++++++++++ msgpong_test.go | 215 +++++++++++++++++++++++ msgtx.go | 387 ++++++++++++++++++++++++++++++++++++++++++ msgtx_test.go | 361 +++++++++++++++++++++++++++++++++++++++ msgverack.go | 46 +++++ msgverack_test.go | 121 +++++++++++++ msgversion.go | 210 +++++++++++++++++++++++ msgversion_test.go | 277 ++++++++++++++++++++++++++++++ netaddress.go | 163 ++++++++++++++++++ netaddress_test.go | 215 +++++++++++++++++++++++ protocol.go | 83 +++++++++ protocol_test.go | 32 ++++ shahash.go | 106 ++++++++++++ shahash_test.go | 167 ++++++++++++++++++ test_coverage.txt | 152 +++++++++++++++++ 57 files changed, 8557 insertions(+), 1 deletion(-) create mode 100644 LICENSE create mode 100644 blockheader.go create mode 100644 blockheader_test.go create mode 100644 common.go create mode 100644 common_test.go create mode 100644 cov_report.sh create mode 100644 doc.go create mode 100644 fakeconn_test.go create mode 100644 fakemessage_test.go create mode 100644 fixedIO_test.go create mode 100644 genesis.go create mode 100644 genesis_test.go create mode 100644 internal_test.go create mode 100644 invvect.go create mode 100644 invvect_test.go create mode 100644 message.go create mode 100644 message_test.go create mode 100644 msgaddr.go create mode 100644 msgaddr_test.go create mode 100644 msgalert.go create mode 100644 msgalert_test.go create mode 100644 msgblock.go create mode 100644 msgblock_test.go create mode 100644 msggetaddr.go create mode 100644 msggetaddr_test.go create mode 100644 msggetblocks.go create mode 100644 msggetblocks_test.go create mode 100644 msggetdata.go create mode 100644 msggetdata_test.go create mode 100644 msggetheaders.go create mode 100644 msggetheaders_test.go create mode 100644 msgheaders.go create mode 100644 msgheaders_test.go create mode 100644 msginv.go create mode 100644 msginv_test.go create mode 100644 msgmempool.go create mode 100644 msgmempool_test.go create mode 100644 msgnotfound.go create mode 100644 msgnotfound_test.go create mode 100644 msgping.go create mode 100644 msgping_test.go create mode 100644 msgpong.go create mode 100644 msgpong_test.go create mode 100644 msgtx.go create mode 100644 msgtx_test.go create mode 100644 msgverack.go create mode 100644 msgverack_test.go create mode 100644 msgversion.go create mode 100644 msgversion_test.go create mode 100644 netaddress.go create mode 100644 netaddress_test.go create mode 100644 protocol.go create mode 100644 protocol_test.go create mode 100644 shahash.go create mode 100644 shahash_test.go create mode 100644 test_coverage.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..0d760cbb --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2013 Conformal Systems LLC. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 90fb26df..cdacac5e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,124 @@ btcwire ======= -Package btcwire implements the bitcoin wire protocol. \ No newline at end of file +Package btcwire implements the bitcoin wire protocol. A comprehensive suite of +tests is provided to ensure proper functionality. See `test_coverage.txt` for +the gocov coverage report. Alternatively, if you are running a POSIX OS, you +can run the `cov_report.sh` script for a real-time report. Package btcwire is +licensed under the liberal ISC license. + +There is an associated blog post about the release of this package +[here](https://blog.conformal.com/btcwire-the-bitcoin-wire-protocol-package-from-btcd/). + +## Documentation + +Full `go doc` style documentation for the project can be viewed online without +installing this package by using the GoDoc site here: +http://godoc.org/github.com/conformal/btcwire + +You can also view the documentation locally once the package is installed with +the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to +http://localhost:6060/pkg/github.com/conformal/btcwire + +## Installation + +```bash +$ go get github.com/conformal/btcwire +``` + +## Bitcoin Message Overview + +The bitcoin protocol consists of exchanging messages between peers. Each message +is preceded by a header which identifies information about it such as which +bitcoin network it is a part of, its type, how big it is, and a checksum to +verify validity. All encoding and decoding of message headers is handled by this +package. + +To accomplish this, there is a generic interface for bitcoin messages named +`Message` which allows messages of any type to be read, written, or passed +around through channels, functions, etc. In addition, concrete implementations +of most of the currently supported bitcoin messages are provided. For these +supported messages, all of the details of marshalling and unmarshalling to and +from the wire using bitcoin encoding are handled so the caller doesn't have to +concern themselves with the specifics. + +## Reading Messages Example + +In order to unmarshal bitcoin messages from the wire, use the `ReadMessage` +function. It accepts any `io.Reader`, but typically this will be a `net.Conn` +to a remote node running a bitcoin peer. Example syntax is: + +```Go + // Use the most recent protocol verison supported by the package and the + // main bitcoin network. + pver := btcwire.ProtocolVersion + btcnet := btcwire.MainNet + + // Reads and validates the next bitcoin message from conn using the + // protocol version pver and the bitcoin network btcnet. The returns + // are a btcwire.Message, a []byte which contains the unmarshalled + // raw payload, and a possible error. + msg, rawPayload, err := btcwire.ReadMessage(conn, pver, btcnet) + if err != nil { + // Log and handle the error + } +``` + +See the package documentation for details on determining the message type. + +## Writing Messages Example + +In order to marshal bitcoin messages to the wire, use the `WriteMessage` +function. It accepts any `io.Writer`, but typically this will be a `net.Conn` +to a remote node running a bitcoin peer. Example syntax to request addresses +from a remote peer is: + +```Go + // Use the most recent protocol verison supported by the package and the + // main bitcoin network. + pver := btcwire.ProtocolVersion + btcnet := btcwire.MainNet + + // Create a new getaddr bitcoin message. + msg := btcwire.NewMsgGetAddr() + + // Writes a bitcoin message msg to conn using the protocol version + // pver, and the bitcoin network btcnet. The return is a possible + // error. + err := btcwire.WriteMessage(conn, msg, pver, btcnet) + if err != nil { + // Log and handle the error + } +``` + +## TODO + +- Implement functions for [BIP 0014](https://en.bitcoin.it/wiki/BIP_0014) +- 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) +- Increase test coverage to 100% + +## GPG Verification Key + +All official release tags are signed by Conformal so users can ensure the code +has not been tampered with and is coming from Conformal. To verify the +signature perform the following: + +- Download the public key from the Conformal website at + https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt + +- Import the public key into your GPG keyring: + ```bash + gpg --import GIT-GPG-KEY-conformal.txt + ``` + +- Verify the release tag with the following command where `TAG_NAME` is a + placeholder for the specific tag: + ```bash + git tag -v TAG_NAME + ``` + +## License + +Package btcwire is licensed under the liberal ISC License. diff --git a/blockheader.go b/blockheader.go new file mode 100644 index 00000000..e2e93228 --- /dev/null +++ b/blockheader.go @@ -0,0 +1,119 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "bytes" + "io" + "time" +) + +// BlockVersion is the current latest supported block version. +const BlockVersion uint32 = 2 + +// Version 4 bytes + Timestamp 4 bytes + Bits 4 bytes + Nonce 4 bytes + +// TxnCount (varInt) + PrevBlock and MarkleRoot hashes. +const maxBlockHeaderPayload = 16 + maxVarIntPayload + (HashSize * 2) + +// BlockHeader defines information about a block and is used in the bitcoin +// block (MsgBlock) and headers (MsgHeaders) messages. +type BlockHeader struct { + // Version of the block. This is not the same as the protocol version. + Version uint32 + + // Hash of the previous block in the block chain. + PrevBlock ShaHash + + // Merkle tree reference to hash of all transactions for the block. + MerkleRoot ShaHash + + // Time the block was created. This is, unfortunately, encoded as a + // uint32 on the wire and therefore is limited to 2106. + Timestamp time.Time + + // Difficulty target for the block. + Bits uint32 + + // Nonce used to generate the block. + Nonce uint32 + + // Number of transactions in the block. For the bitcoin headers + // (MsgHeaders) message, this must be 0. This is encoded as a variable + // length integer on the wire. + TxnCount uint64 +} + +// blockHashLen is a constant that represents how much of the block header is +// used when computing the block sha 0:blockHashLen +const blockHashLen = 80 + +// BlockSha computes the block identifier hash for the given block header. +func (h *BlockHeader) BlockSha(pver uint32) (sha ShaHash, err error) { + var buf bytes.Buffer + err = writeBlockHeader(&buf, pver, h) + if err != nil { + return + } + + err = sha.SetBytes(DoubleSha256(buf.Bytes()[0:blockHashLen])) + if err != nil { + return + } + + return +} + +// NewBlockHeader returns a new BlockHeader using the provided previous block +// hash, merkle root hash, difficulty bits, and nonce used to generate the +// block with defaults for the remaining fields. +func NewBlockHeader(prevHash *ShaHash, merkleRootHash *ShaHash, bits uint32, + nonce uint32) *BlockHeader { + + return &BlockHeader{ + Version: BlockVersion, + PrevBlock: *prevHash, + MerkleRoot: *merkleRootHash, + Timestamp: time.Now(), + Bits: bits, + Nonce: nonce, + TxnCount: 0, + } +} + +// readBlockHeader reads a bitcoin block header from r. +func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error { + var sec uint32 + err := readElements(r, &bh.Version, &bh.PrevBlock, &bh.MerkleRoot, &sec, + &bh.Bits, &bh.Nonce) + if err != nil { + return err + } + bh.Timestamp = time.Unix(int64(sec), 0) + + count, err := readVarInt(r, pver) + if err != nil { + return err + } + bh.TxnCount = count + + return nil +} + +// writeBlockHeader writes a bitcoin block header to w. +func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { + sec := uint32(bh.Timestamp.Unix()) + err := writeElements(w, bh.Version, bh.PrevBlock, bh.MerkleRoot, + sec, bh.Bits, bh.Nonce) + if err != nil { + return err + } + + err = writeVarInt(w, pver, bh.TxnCount) + if err != nil { + return err + } + + return nil +} diff --git a/blockheader_test.go b/blockheader_test.go new file mode 100644 index 00000000..ca352883 --- /dev/null +++ b/blockheader_test.go @@ -0,0 +1,160 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" + "time" +) + +// TestBlockHeader tests the BlockHeader API. +func TestBlockHeader(t *testing.T) { + nonce64, err := btcwire.RandomUint64() + if err != nil { + t.Errorf("RandomUint64: Error generating nonce: %v", err) + } + nonce := uint32(nonce64) + + hash := btcwire.GenesisHash + merkleHash := btcwire.GenesisMerkleRoot + bits := uint32(0x1d00ffff) + bh := btcwire.NewBlockHeader(&hash, &merkleHash, bits, nonce) + + // Ensure we get the same data back out. + if !bh.PrevBlock.IsEqual(&hash) { + t.Errorf("NewBlockHeader: wrong prev hash - got %v, want %v", + spew.Sprint(bh.PrevBlock), spew.Sprint(hash)) + } + if !bh.MerkleRoot.IsEqual(&merkleHash) { + t.Errorf("NewBlockHeader: wrong merkle root - got %v, want %v", + spew.Sprint(bh.MerkleRoot), spew.Sprint(merkleHash)) + } + if bh.Bits != bits { + t.Errorf("NewBlockHeader: wrong bits - got %v, want %v", + bh.Bits, bits) + } + if bh.Nonce != nonce { + t.Errorf("NewBlockHeader: wrong nonce - got %v, want %v", + bh.Nonce, nonce) + } +} + +// TestBlockHeaderWire tests the BlockHeader wire encode and decode for various +// protocol versions. +func TestBlockHeaderWire(t *testing.T) { + nonce := uint32(123123) // 0x1e0f3 + + // baseBlockHdr is used in the various tests as a baseline BlockHeader. + hash := btcwire.GenesisHash + merkleHash := btcwire.GenesisMerkleRoot + bits := uint32(0x1d00ffff) + baseBlockHdr := &btcwire.BlockHeader{ + Version: 1, + PrevBlock: hash, + MerkleRoot: merkleHash, + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST + Bits: bits, + Nonce: nonce, + TxnCount: 0, + } + + // baseBlockHdrEncoded is the wire encoded bytes of baseBlockHdr. + baseBlockHdrEncoded := []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 + 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, // MerkleRoot + 0x29, 0xab, 0x5f, 0x49, // Timestamp + 0xff, 0xff, 0x00, 0x1d, // Bits + 0xf3, 0xe0, 0x01, 0x00, // Nonce + 0x00, // TxnCount Varint + } + + tests := []struct { + in *btcwire.BlockHeader // Data to encode + out *btcwire.BlockHeader // Expected decoded data + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version. + { + baseBlockHdr, + baseBlockHdr, + baseBlockHdrEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version. + { + baseBlockHdr, + baseBlockHdr, + baseBlockHdrEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version. + { + baseBlockHdr, + baseBlockHdr, + baseBlockHdrEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion. + { + baseBlockHdr, + baseBlockHdr, + baseBlockHdrEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion. + { + baseBlockHdr, + baseBlockHdr, + baseBlockHdrEncoded, + btcwire.MultipleAddressVersion, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Encode to wire format. + var buf bytes.Buffer + err := btcwire.TstWriteBlockHeader(&buf, test.pver, test.in) + if err != nil { + t.Errorf("writeBlockHeader #%d error %v", i, err) + continue + } + if !bytes.Equal(buf.Bytes(), test.buf) { + t.Errorf("writeBlockHeader #%d\n got: %s want: %s", i, + spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) + continue + } + + // Decode the block header from wire format. + var bh btcwire.BlockHeader + rbuf := bytes.NewBuffer(test.buf) + err = btcwire.TstReadBlockHeader(rbuf, test.pver, &bh) + if err != nil { + t.Errorf("readBlockHeader #%d error %v", i, err) + continue + } + if !reflect.DeepEqual(&bh, test.out) { + t.Errorf("readBlockHeader #%d\n got: %s want: %s", i, + spew.Sdump(&bh), spew.Sdump(test.out)) + continue + } + } +} diff --git a/common.go b/common.go new file mode 100644 index 00000000..28c8f325 --- /dev/null +++ b/common.go @@ -0,0 +1,181 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "crypto/rand" + "crypto/sha256" + "encoding/binary" + "io" + "math" +) + +// Maximum payload size for a variable length integer. +const maxVarIntPayload = 9 + +// readElement reads the next sequence of bytes from r using little endian +// depending on the concrete type of element pointed to. +func readElement(r io.Reader, element interface{}) error { + return binary.Read(r, binary.LittleEndian, element) +} + +// readElements reads multiple items from r. It is equivalent to multiple +// calls to readElement. +func readElements(r io.Reader, elements ...interface{}) error { + for _, element := range elements { + err := readElement(r, element) + if err != nil { + return err + } + } + return nil +} + +// writeElement writes the little endian representation of element to w. +func writeElement(w io.Writer, element interface{}) error { + return binary.Write(w, binary.LittleEndian, element) +} + +// writeElements writes multiple items to w. It is equivalent to multiple +// calls to writeElement. +func writeElements(w io.Writer, elements ...interface{}) error { + for _, element := range elements { + err := writeElement(w, element) + if err != nil { + return err + } + } + return nil +} + +// readVarInt reads a variable length integer from r and returns it as a uint64. +func readVarInt(r io.Reader, pver uint32) (uint64, error) { + b := make([]byte, 1) + _, err := r.Read(b) + if err != nil { + return 0, err + } + + var rv uint64 + discriminant := uint8(b[0]) + switch discriminant { + case 0xff: + var u uint64 + err = binary.Read(r, binary.LittleEndian, &u) + if err != nil { + return 0, err + } + rv = u + + case 0xfe: + var u uint32 + err = binary.Read(r, binary.LittleEndian, &u) + if err != nil { + return 0, err + } + rv = uint64(u) + + case 0xfd: + var u uint16 + err = binary.Read(r, binary.LittleEndian, &u) + if err != nil { + return 0, err + } + rv = uint64(u) + + default: + rv = uint64(discriminant) + } + + return rv, nil +} + +// writeVarInt serializes val to w using a variable number of bytes depending +// on its value. +func writeVarInt(w io.Writer, pver uint32, val uint64) error { + if val > math.MaxUint32 { + err := writeElements(w, []byte{0xff}, uint64(val)) + if err != nil { + return err + } + return nil + } + if val > math.MaxUint16 { + err := writeElements(w, []byte{0xfe}, uint32(val)) + if err != nil { + return err + } + return nil + } + if val >= 0xfd { + err := writeElements(w, []byte{0xfd}, uint16(val)) + if err != nil { + return err + } + return nil + } + return writeElement(w, uint8(val)) +} + +// readVarString reads a variable length string from r and returns it as a Go +// string. A varString is encoded as a varInt containing the length of the +// string, and the bytes that represent the string itself. +func readVarString(r io.Reader, pver uint32) (string, error) { + slen, err := readVarInt(r, pver) + if err != nil { + return "", err + } + buf := make([]byte, slen) + err = readElement(r, buf) + if err != nil { + return "", err + } + return string(buf), nil +} + +// writeVarString serializes str to w as a varInt containing the length of the +// string followed by the bytes that represent the string itself. +func writeVarString(w io.Writer, pver uint32, str string) error { + err := writeVarInt(w, pver, uint64(len(str))) + if err != nil { + return err + } + err = writeElement(w, []byte(str)) + if err != nil { + return err + } + return nil +} + +// randomUint64 returns a cryptographically random uint64 value. This +// unexported version takes a reader primarily to ensure the error paths +// can be properly by passing a fake reader in the tests. +func randomUint64(r io.Reader) (uint64, error) { + b := make([]byte, 8) + n, err := r.Read(b) + if n != len(b) { + return 0, io.ErrShortBuffer + } + if err != nil { + return 0, err + } + return binary.BigEndian.Uint64(b), nil +} + +// RandomUint64 returns a cryptographically random uint64 value. +func RandomUint64() (uint64, error) { + return randomUint64(rand.Reader) +} + +// DoubleSha256 calculates sha256(sha256(b)) and returns the resulting bytes. +func DoubleSha256(b []byte) []byte { + hasher := sha256.New() + hasher.Write(b) + sum := hasher.Sum(nil) + hasher.Reset() + hasher.Write(sum) + sum = hasher.Sum(nil) + return sum +} diff --git a/common_test.go b/common_test.go new file mode 100644 index 00000000..ab6e64de --- /dev/null +++ b/common_test.go @@ -0,0 +1,304 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "fmt" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "io" + "strings" + "testing" +) + +// 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 p. +func (r *fakeRandReader) Read(p []byte) (int, error) { + n := r.n + if n > len(p) { + n = len(p) + } + return n, r.err +} + +// TestVarIntWire tests wire encode and decode for variable length integers. +func TestVarIntWire(t *testing.T) { + pver := btcwire.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 := btcwire.TstWriteVarInt(&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.NewBuffer(test.buf) + val, err := btcwire.TstReadVarInt(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 := btcwire.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 + }{ + // Latest protocol version with intentional read/write errors. + // 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 := btcwire.TstWriteVarInt(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 = btcwire.TstReadVarInt(r, test.pver) + if err != test.readErr { + t.Errorf("readVarInt #%d wrong error got: %v, want :%v", + i, err, test.readErr) + continue + } + } +} + +// TestVarStringWire tests wire encode and decode for variable length strings. +func TestVarStringWire(t *testing.T) { + pver := btcwire.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 := btcwire.TstWriteVarString(&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.NewBuffer(test.buf) + val, err := btcwire.TstReadVarString(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: %d want: %d", 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 := btcwire.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 := btcwire.TstWriteVarString(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 = btcwire.TstReadVarString(r, test.pver) + if err != test.readErr { + t.Errorf("readVarString #%d wrong error got: %v, want :%v", + i, err, test.readErr) + 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 := btcwire.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: nil} + nonce, err := btcwire.TstRandomUint64(fr) + if err != io.ErrShortBuffer { + t.Errorf("TestRandomUint64Fails: Error not expected value of %v [%v]", + io.ErrShortBuffer, err) + } + if nonce != 0 { + t.Errorf("TestRandomUint64Fails: nonce is not 0 [%v]", nonce) + } + + // Test err with full read. + fr = &fakeRandReader{n: 20, err: io.ErrClosedPipe} + nonce, err = btcwire.TstRandomUint64(fr) + if err != io.ErrClosedPipe { + t.Errorf("TestRandomUint64Fails: Error not expected value of %v [%v]", + io.ErrClosedPipe, err) + } + if nonce != 0 { + t.Errorf("TestRandomUint64Fails: nonce is not 0 [%v]", nonce) + } +} diff --git a/cov_report.sh b/cov_report.sh new file mode 100644 index 00000000..ef5cf816 --- /dev/null +++ b/cov_report.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# This script uses gocov to generate a test coverage report. +# The gocov tool my be obtained with the following command: +# go get github.com/awx/gocov/gocov +# +# It will be installed it $GOPATH/bin, so ensure that location is in your $PATH. + +# Check for gocov. +type gocov >/dev/null 2>&1 +if [ $? -ne 0 ]; then + echo >&2 "This script requires the gocov tool." + echo >&2 "You may obtain it with the following command:" + echo >&2 "go get github.com/awx/gocov/gocov" + exit 1 +fi +gocov test | gocov report diff --git a/doc.go b/doc.go new file mode 100644 index 00000000..b7086aed --- /dev/null +++ b/doc.go @@ -0,0 +1,163 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +/* +Package btcwire implements the bitcoin wire protocol. + +For the complete details of the bitcoin protocol, see the official wiki entry +at https://en.bitcoin.it/wiki/Protocol_specification. The following only serves +as a quick overview to provide information on how to use the package. + +At a high level, this package provides support for marshalling and unmarshalling +supported bitcoin messages to and from the wire. This package does not deal +with the specifics of message handling such as what to do when a message is +received. This provides the caller with a high level of flexibility. + +Bitcoin Message Overview + +The bitcoin protocol consists of exchanging messages between peers. Each +message is preceded by a header which identifies information about it such as +which bitcoin network it is a part of, its type, how big it is, and a checksum +to verify validity. All encoding and decoding of message headers is handled by +this package. + +To accomplish this, there is a generic interface for bitcoin messages named +Message which allows messages of any type to be read, written, or passed around +through channels, functions, etc. In addition, concrete implementations of most +of the currently supported bitcoin messages are provided. For these supported +messages, all of the details of marshalling and unmarshalling to and from the +wire using bitcoin encoding are handled so the caller doesn't have to concern +themselves with the specifics. + +Message Interaction + +The following provides a quick summary of how the bitcoin messages are intended +to interact with one another. As stated above, these interactions are not +directly handled by this package. For more in-depth details about the +appropriate interactions, see the official bitcoin protocol wiki entry at +https://en.bitcoin.it/wiki/Protocol_specification. + +The initial handshake consists of two peers sending each other a version message +(MsgVersion) followed by responding with a verack message (MsgVerAck). Both +peers use the information in the version message (MsgVersion) to negotiate +things such as protocol version and supported services with each other. Once +the initial handshake is complete, the following chart indicates message +interactions in no particular order. + + Peer A Sends Peer B Responds + ---------------------------------------------------------------------------- + getaddr message (MsgGetAddr) addr message (MsgAddr) + getblocks message (MsgGetBlocks) inv message (MsgInv) + inv message (MsgInv) getdata message (MsgGetData) + getdata message (MsgGetData) block message (MsgBlock) -or- + tx message (MsgTx) -or- + notfound message (MsgNotFound) + getheaders message (MsgGetHeaders) headers message (MsgHeaders) + ping message (MsgPing) pong message (MsgHeaders)* -or- + (none -- Ability to send message is enough) + + NOTES: + * The pong message was not added until later protocol versions as defined + in BIP0031. The BIP0031Version constant can be used to detect a recent + enough protocol version for this purpose (version > BIP0031Version). + +Common Parameters + +There are several common parameters that arise when using this package to read +and write bitcoin messages. The following sections provide a quick overview of +these parameters so the next sections can build on them. + +Protocol Version + +The protocol version should be negotiated with the remote peer at a higher +level than this package via the version (MsgVersion) message exchange, however, +this package provides the btcwire.ProtocolVersion constant which indicates the +latest protocol version this package supports and is typically the value to use +for all outbound connections before a potentially lower protocol version is +negotiated. + +Bitcoin Network + +The bitcoin network is a magic number which is used to identify the start of a +and which bitcoin network the message applies to. This package provides the +following constants: + + btcwire.MainNet + btcwire.TestNet + btcwire.TestNet3 + +Determining Message Type + +As discussed in the bitcoin message overview section, this package reads +and writes bitcoin messages using a generic interface named Message. In +order to determine the actual concrete type of the message, use a type +switch or type assertion. An example of a type switch follows: + + // Assumes msg is already a valid concrete message such as one created + // via NewMsgVersion or read via ReadMessage. + switch msg.(type) { + case *btcwire.MsgVersion: + // The message is a pointer to a MsgVersion struct. + fmt.Printf("Protocol version: %v", msg.ProtocolVersion) + case *btcwire.MsgBlock: + // The message is a pointer to a MsgBlock struct. + fmt.Printf("Number of tx in block: %v", msg.Header.TxnCount) + + } + +Reading Messages + +In order to unmarshall bitcoin messages from the wire, use the ReadMessage +function. It accepts any io.Reader, but typically this will be a net.Conn to +a remote node running a bitcoin peer. Example syntax is: + + // Reads and validates the next bitcoin message from conn using the + // protocol version pver and the bitcoin network btcnet. The returns + // are a btcwire.Message, a []byte which contains the unmarshalled + // raw payload, and a possible error. + msg, rawPayload, err := btcwire.ReadMessage(conn, pver, btcnet) + if err != nil { + // Log and handle the error + } + +Writing Messages + +In order to marshall bitcoin messages to the wire, use the WriteMessage +function. It accepts any io.Writer, but typically this will be a net.Conn to +a remote node running a bitcoin peer. Example syntax to request addresses +from a remote peer is: + + // Create a new getaddr bitcoin message. + msg := btcwire.NewMsgGetAddr() + + // Writes a bitcoin message msg to conn using the protocol version + // pver, and the bitcoin network btcnet. The return is a possible + // error. + err := btcwire.WriteMessage(conn, msg, pver, btcnet) + if err != nil { + // Log and handle the error + } + +Errors + +Most errors returned by this package are either the raw errors provided by +underlying calls to read/write from streams, or raw strings that describe +the error. See the documentation of each function for any exceptions. NOTE: +This will change soon as the package should return errors that can be +programatically tested. + +Bitcoin Improvement Proposals + +This package includes spec changes outlined by the following BIPs: + + BIP0031 (https://en.bitcoin.it/wiki/BIP_0031) + BIP0035 (https://en.bitcoin.it/wiki/BIP_0035) + +Other important information + +The package does not yet implement BIP0037 (https://en.bitcoin.it/wiki/BIP_0037) +and therefore does not recognize filterload, filteradd, filterclear, or +merkleblock messages. +*/ +package btcwire diff --git a/fakeconn_test.go b/fakeconn_test.go new file mode 100644 index 00000000..3c6f6bc6 --- /dev/null +++ b/fakeconn_test.go @@ -0,0 +1,62 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "net" + "time" +) + +// fakeConn implements the net.Conn interface and is used to test functions +// which work with a net.Conn without having to actually make any real +// connections. +type fakeConn struct { + localAddr net.Addr + remoteAddr net.Addr +} + +// Read doesn't do anything. It just satisfies the net.Conn interface. +func (c *fakeConn) Read(b []byte) (n int, err error) { + return 0, nil +} + +// Write doesn't do anything. It just satisfies the net.Conn interface. +func (c *fakeConn) Write(b []byte) (n int, err error) { + return 0, nil +} + +// Close doesn't do anything. It just satisfies the net.Conn interface. +func (c *fakeConn) Close() error { + return nil +} + +// LocalAddr returns the localAddr field of the fake connection and satisfies +// the net.Conn interface. +func (c *fakeConn) LocalAddr() net.Addr { + return c.localAddr +} + +// RemoteAddr returns the remoteAddr field of the fake connection and satisfies +// the net.Conn interface. +func (c *fakeConn) RemoteAddr() net.Addr { + return c.remoteAddr +} + +// SetDeadline doesn't do anything. It just satisfies the net.Conn interface. +func (c *fakeConn) SetDeadline(t time.Time) error { + return nil +} + +// SetReadDeadline doesn't do anything. It just satisfies the net.Conn +// interface. +func (c *fakeConn) SetReadDeadline(t time.Time) error { + return nil +} + +// SetWriteDeadline doesn't do anything. It just satisfies the net.Conn +// interface. +func (c *fakeConn) SetWriteDeadline(t time.Time) error { + return nil +} diff --git a/fakemessage_test.go b/fakemessage_test.go new file mode 100644 index 00000000..3288d93e --- /dev/null +++ b/fakemessage_test.go @@ -0,0 +1,40 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "io" +) + +// fakeMessage implements the btcwire.Message interface and is used to force +// errors. +type fakeMessage struct { + command string + maxPayload uint32 +} + +// BtcDecode doesn't do anything. It just satisfies the btcwire.Message +// interface. +func (msg *fakeMessage) BtcDecode(r io.Reader, pver uint32) error { + return nil +} + +// BtcEncode doesn't do anything. It just satisfies the btcwire.Message +// interface. +func (msg *fakeMessage) BtcEncode(w io.Writer, pver uint32) error { + return nil +} + +// Command returns the command field of the fake message and satisfies the +// btcwire.Message interface. +func (msg *fakeMessage) Command() string { + return msg.command +} + +// Command returns the maxPayload field of the fake message and satisfies the +// btcwire.Message interface. +func (msg *fakeMessage) MaxPayloadLength(pver uint32) uint32 { + return msg.maxPayload +} diff --git a/fixedIO_test.go b/fixedIO_test.go new file mode 100644 index 00000000..7ea0377d --- /dev/null +++ b/fixedIO_test.go @@ -0,0 +1,67 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "io" +) + +// fixedWriter implements the io.Writer interface and intentially allows +// testing of error paths by forcing short writes. +type fixedWriter struct { + b []byte + pos int +} + +// Write ... +func (w *fixedWriter) Write(p []byte) (n int, err error) { + lenp := len(p) + if w.pos+lenp > cap(w.b) { + return 0, io.ErrShortWrite + } + n = lenp + w.pos += copy(w.b[w.pos:], p) + return +} + +// Bytes ... +func (w *fixedWriter) Bytes() []byte { + return w.b +} + +// newFixedWriter... +func newFixedWriter(max int) *fixedWriter { + b := make([]byte, max, max) + fw := fixedWriter{b, 0} + return &fw +} + +// fixedReader implements the io.Reader interface and intentially allows +// testing of error paths by forcing short reads. +type fixedReader struct { + buf []byte + pos int + iobuf *bytes.Buffer +} + +// Read .... +func (fr *fixedReader) Read(p []byte) (n int, err error) { + n, err = fr.iobuf.Read(p) + fr.pos += n + return +} + +// newFixedReader ... +func newFixedReader(max int, buf []byte) *fixedReader { + b := make([]byte, max, max) + if buf != nil { + copy(b[:], buf) + } + + iobuf := bytes.NewBuffer(b) + fr := fixedReader{b, 0, iobuf} + return &fr +} diff --git a/genesis.go b/genesis.go new file mode 100644 index 00000000..0ab72fa3 --- /dev/null +++ b/genesis.go @@ -0,0 +1,83 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "time" +) + +// GenesisHash is the hash of the first block in the block chain (genesis +// block). +var GenesisHash ShaHash = ShaHash{ + 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, +} + +// GenesisMerkleRoot is the hash of the first transaction in the genesis block. +var GenesisMerkleRoot ShaHash = ShaHash{ + 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, +} + +// GenesisBlock defines the genesis block of the block chain which serves as the +// public transaction ledger. +var GenesisBlock MsgBlock = MsgBlock{ + Header: BlockHeader{ + Version: 1, + PrevBlock: ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 + MerkleRoot: GenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST + Bits: 0x1d00ffff, // 486604799 + Nonce: 0x7c2bac1d, // 2083236893 + TxnCount: 1, + }, + Transactions: []*MsgTx{ + &MsgTx{ + Version: 1, + TxIn: []*TxIn{ + &TxIn{ + PreviousOutpoint: OutPoint{ + Hash: ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ + 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ + 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ + 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ + 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ + 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ + 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ + 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ + 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ + }, + Sequence: 0xffffffff, + }, + }, + TxOut: []*TxOut{ + &TxOut{ + Value: 0x12a05f200, + PkScript: []byte{ + 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ + 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ + 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ + 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ + 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ + 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ + 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ + 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ + 0x1d, 0x5f, 0xac, /* |._.| */ + }, + }, + }, + LockTime: 0, + }, + }, +} diff --git a/genesis_test.go b/genesis_test.go new file mode 100644 index 00000000..75bd6bdf --- /dev/null +++ b/genesis_test.go @@ -0,0 +1,87 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "testing" +) + +// TestGenesisBlock tests the genesis block for validity by checking the encoded +// bytes and hashes. +func TestGenesisBlock(t *testing.T) { + pver := uint32(60002) + + // Encode the genesis block to raw bytes. + var buf bytes.Buffer + err := btcwire.GenesisBlock.BtcEncode(&buf, pver) + if err != nil { + t.Errorf("TestGenesisBlock: %v", err) + return + } + + // Ensure the encoded block matches the expected bytes. + if !bytes.Equal(buf.Bytes(), genesisBlockBytes) { + t.Errorf("TestGenesisBlock: Genesis block does not appear valid - "+ + "got %v, want %v", spew.Sdump(buf.Bytes()), + spew.Sdump(genesisBlockBytes)) + return + } + + // Check hash of the block against expected hash. + hash, err := btcwire.GenesisBlock.Header.BlockSha(pver) + if err != nil { + t.Errorf("BlockSha: %v", err) + } + if !btcwire.GenesisHash.IsEqual(&hash) { + t.Errorf("TestGenesisBlock: Genesis block hash does not appear valid - "+ + "got %v, want %v", spew.Sdump(hash), + spew.Sdump(btcwire.GenesisHash)) + return + } +} + +// genesisBlockBytes are the wire encoded bytes for the genesis block as of +// protocol version 60002. +var genesisBlockBytes = []byte{ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */ + 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */ + 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */ + 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */ + 0x4b, 0x1e, 0x5e, 0x4a, 0x29, 0xab, 0x5f, 0x49, /* |K.^J)._I| */ + 0xff, 0xff, 0x00, 0x1d, 0x1d, 0xac, 0x2b, 0x7c, /* |......+|| */ + 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */ + 0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */ + 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */ + 0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */ + 0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */ + 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */ + 0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */ + 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */ + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */ + 0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */ + 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */ + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */ + 0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */ + 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */ + 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */ + 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */ + 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */ + 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */ + 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */ + 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */ + 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ + 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ +} diff --git a/internal_test.go b/internal_test.go new file mode 100644 index 00000000..d57754a5 --- /dev/null +++ b/internal_test.go @@ -0,0 +1,100 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +/* +This test file is part of the btcwire package rather than than the +btcwire_test package so it can bridge access to the internals to properly test +cases which are either not possible or can't reliably be tested via the public +interface. The functions are only exported while the tests are being run. +*/ + +package btcwire + +import ( + "io" +) + +// TstRandomUint64 makes the internal randomUint64 function available to the +// test package. +func TstRandomUint64(r io.Reader) (uint64, error) { + return randomUint64(r) +} + +// TstReadVarInt makes the internal readVarInt function available to the +// test package. +func TstReadVarInt(r io.Reader, pver uint32) (uint64, error) { + return readVarInt(r, pver) +} + +// TstWriteVarInt makes the internal writeVarInt function available to the +// test package. +func TstWriteVarInt(w io.Writer, pver uint32, val uint64) error { + return writeVarInt(w, pver, val) +} + +// TstReadVarString makes the internal readVarString function available to the +// test package. +func TstReadVarString(r io.Reader, pver uint32) (string, error) { + return readVarString(r, pver) +} + +// TstWriteVarString makes the internal writeVarString function available to the +// test package. +func TstWriteVarString(w io.Writer, pver uint32, str string) error { + return writeVarString(w, pver, str) +} + +// TstReadNetAddress makes the internal readNetAddress function available to +// the test package. +func TstReadNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error { + return readNetAddress(r, pver, na, ts) +} + +// TstWriteNetAddress makes the internal writeNetAddress function available to +// the test package. +func TstWriteNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error { + return writeNetAddress(w, pver, na, ts) +} + +// TstMaxNetAddressPayload makes the internal maxNetAddressPayload function +// available to the test package. +func TstMaxNetAddressPayload(pver uint32) uint32 { + return maxNetAddressPayload(pver) +} + +// TstReadInvVect makes the internal readInvVect function available to the test +// package. +func TstReadInvVect(r io.Reader, pver uint32, iv *InvVect) error { + return readInvVect(r, pver, iv) +} + +// TstWriteInvVect makes the internal writeInvVect function available to the +// test package. +func TstWriteInvVect(w io.Writer, pver uint32, iv *InvVect) error { + return writeInvVect(w, pver, iv) +} + +// TstReadBlockHeader makes the internal readBlockHeader function available to +// the test package. +func TstReadBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error { + return readBlockHeader(r, pver, bh) +} + +// TstWriteBlockHeader makes the internal writeBlockHeader function available to +// the test package. +func TstWriteBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { + return writeBlockHeader(w, pver, bh) +} + +// TstReadMessage makes the internal readMessage function available to +// the test package. +func TstReadMessage(r io.Reader, pver uint32, hdr *messageHeader) (Message, []byte, error) { + return readMessage(r, pver, hdr) +} + +// TstReadMessageHeader makes the internal readMessageHeader function available +// to the test package. +func TstReadMessageHeader(r io.Reader) (*messageHeader, error) { + return readMessageHeader(r) +} diff --git a/invvect.go b/invvect.go new file mode 100644 index 00000000..1784a094 --- /dev/null +++ b/invvect.go @@ -0,0 +1,79 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +const ( + // MaxInvPerMsg is the maximum number of inventory vectors that can be in a + // single bitcoin inv message. + MaxInvPerMsg = 50000 + + // Maximum payload size for an inventory vector. + maxInvVectPayload = 4 + HashSize +) + +// InvType represents the allowed types of inventory vectors. See InvVect. +type InvType uint32 + +const ( + InvVect_Error InvType = 0 + InvVect_Tx InvType = 1 + InvVect_Block InvType = 2 +) + +// Map of service flags back to their constant names for pretty printing. +var ivStrings = map[InvType]string{ + InvVect_Error: "ERROR", + InvVect_Tx: "MSG_TX", + InvVect_Block: "MSG_BLOCK", +} + +// String returns the InvType in human-readable form. +func (invtype InvType) String() string { + if s, ok := ivStrings[invtype]; ok { + return s + } + + return fmt.Sprintf("Unknown InvType (%d)", uint32(invtype)) +} + +// InvVect defines a bitcoin inventory vector which is used to describe data, +// as specified by the Type field, that a peer wants, has, or does not have to +// another peer. +type InvVect struct { + Type InvType // Type of data + Hash ShaHash // Hash of the data +} + +// NewInvVect returns a new InvVect using the provided type and hash. +func NewInvVect(typ InvType, hash *ShaHash) *InvVect { + return &InvVect{ + Type: typ, + Hash: *hash, + } +} + +// readInvVect reads an encoded InvVect from r depending on the protocol +// version. +func readInvVect(r io.Reader, pver uint32, iv *InvVect) error { + err := readElements(r, &iv.Type, &iv.Hash) + if err != nil { + return err + } + return nil +} + +// writeInvVect serializes an InvVect to w depending on the protocol version. +func writeInvVect(w io.Writer, pver uint32, iv *InvVect) error { + err := writeElements(w, iv.Type, iv.Hash) + if err != nil { + return err + } + return nil +} diff --git a/invvect_test.go b/invvect_test.go new file mode 100644 index 00000000..d374c976 --- /dev/null +++ b/invvect_test.go @@ -0,0 +1,268 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestInvVectStringer tests the stringized output for inventory vector types. +func TestInvTypeStringer(t *testing.T) { + tests := []struct { + in btcwire.InvType + want string + }{ + {btcwire.InvVect_Error, "ERROR"}, + {btcwire.InvVect_Tx, "MSG_TX"}, + {btcwire.InvVect_Block, "MSG_BLOCK"}, + {0xffffffff, "Unknown InvType (4294967295)"}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + result := test.in.String() + if result != test.want { + t.Errorf("String #%d\n got: %s want: %s", i, result, + test.want) + continue + } + } + +} + +// TestInvVect tests the InvVect API. +func TestInvVect(t *testing.T) { + ivType := btcwire.InvVect_Block + hash := btcwire.ShaHash{} + + // Ensure we get the same payload and signature back out. + iv := btcwire.NewInvVect(ivType, &hash) + if iv.Type != ivType { + t.Errorf("NewInvVect: wrong type - got %v, want %v", + iv.Type, ivType) + } + if !iv.Hash.IsEqual(&hash) { + t.Errorf("NewInvVect: wrong hash - got %v, want %v", + spew.Sdump(iv.Hash), spew.Sdump(hash)) + } + +} + +// TestInvVectWire tests the InvVect wire encode and decode for various +// protocol versions and supported inventory vector types. +func TestInvVectWire(t *testing.T) { + // Block 203707 hash. + hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" + baseHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // errInvVect is an inventory vector with an error. + errInvVect := btcwire.InvVect{ + Type: btcwire.InvVect_Error, + Hash: btcwire.ShaHash{}, + } + + // errInvVectEncoded is the wire encoded bytes of errInvVect. + errInvVectEncoded := []byte{ + 0x00, 0x00, 0x00, 0x00, // InvVect_Error + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // No hash + } + + // txInvVect is an inventory vector representing a transaction. + txInvVect := btcwire.InvVect{ + Type: btcwire.InvVect_Tx, + Hash: *baseHash, + } + + // txInvVectEncoded is the wire encoded bytes of txInvVect. + txInvVectEncoded := []byte{ + 0x01, 0x00, 0x00, 0x00, // InvVect_Tx + 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, + 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, + 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, + 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash + } + + // blockInvVect is an inventory vector representing a block. + blockInvVect := btcwire.InvVect{ + Type: btcwire.InvVect_Block, + Hash: *baseHash, + } + + // blockInvVectEncoded is the wire encoded bytes of blockInvVect. + blockInvVectEncoded := []byte{ + 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, + 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, + 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, + 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash + } + + tests := []struct { + in btcwire.InvVect // NetAddress to encode + out btcwire.InvVect // Expected decoded NetAddress + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version error inventory vector. + { + errInvVect, + errInvVect, + errInvVectEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version tx inventory vector. + { + txInvVect, + txInvVect, + txInvVectEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version block inventory vector. + { + blockInvVect, + blockInvVect, + blockInvVectEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version error inventory vector. + { + errInvVect, + errInvVect, + errInvVectEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0035Version tx inventory vector. + { + txInvVect, + txInvVect, + txInvVectEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0035Version block inventory vector. + { + blockInvVect, + blockInvVect, + blockInvVectEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version error inventory vector. + { + errInvVect, + errInvVect, + errInvVectEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version BIP0031Version tx inventory vector. + { + txInvVect, + txInvVect, + txInvVectEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version BIP0031Version block inventory vector. + { + blockInvVect, + blockInvVect, + blockInvVectEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion error inventory vector. + { + errInvVect, + errInvVect, + errInvVectEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion tx inventory vector. + { + txInvVect, + txInvVect, + txInvVectEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion block inventory vector. + { + blockInvVect, + blockInvVect, + blockInvVectEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion error inventory vector. + { + errInvVect, + errInvVect, + errInvVectEncoded, + btcwire.MultipleAddressVersion, + }, + + // Protocol version MultipleAddressVersion tx inventory vector. + { + txInvVect, + txInvVect, + txInvVectEncoded, + btcwire.MultipleAddressVersion, + }, + + // Protocol version MultipleAddressVersion block inventory vector. + { + blockInvVect, + blockInvVect, + blockInvVectEncoded, + btcwire.MultipleAddressVersion, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Encode to wire format. + var buf bytes.Buffer + err := btcwire.TstWriteInvVect(&buf, test.pver, &test.in) + if err != nil { + t.Errorf("writeInvVect #%d error %v", i, err) + continue + } + if !bytes.Equal(buf.Bytes(), test.buf) { + t.Errorf("writeInvVect #%d\n got: %s want: %s", i, + spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) + continue + } + + // Decode the message from wire format. + var iv btcwire.InvVect + rbuf := bytes.NewBuffer(test.buf) + err = btcwire.TstReadInvVect(rbuf, test.pver, &iv) + if err != nil { + t.Errorf("readInvVect #%d error %v", i, err) + continue + } + if !reflect.DeepEqual(iv, test.out) { + t.Errorf("readInvVect #%d\n got: %s want: %s", i, + spew.Sdump(iv), spew.Sdump(test.out)) + continue + } + } +} diff --git a/message.go b/message.go new file mode 100644 index 00000000..dea9668b --- /dev/null +++ b/message.go @@ -0,0 +1,286 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "bytes" + "fmt" + "io" + "unicode/utf8" +) + +// commandSize is the fixed size of all commands in the common bitcoin message +// header. Shorter commands must be zero padded. +const commandSize = 12 + +// maxMessagePayload is the maximum byes a message can be regardless of other +// individual limits imposed by messages themselves. +const maxMessagePayload = (1024 * 1024 * 32) // 32MB + +// Commands used in bitcoin message headers which describe the type of message. +const ( + cmdVersion = "version" + cmdVerAck = "verack" + cmdGetAddr = "getaddr" + cmdAddr = "addr" + cmdGetBlocks = "getblocks" + cmdInv = "inv" + cmdGetData = "getdata" + cmdNotFound = "notfound" + cmdBlock = "block" + cmdTx = "tx" + cmdGetHeaders = "getheaders" + cmdHeaders = "headers" + cmdPing = "ping" + cmdPong = "pong" + cmdAlert = "alert" + cmdMemPool = "mempool" +) + +// Message is an interface that describes a bitcoin message. A type that +// implements Message has complete control over the representation of its data +// and may therefore contain additional or fewer fields than those which +// are used directly in the protocol encoded message. +type Message interface { + BtcDecode(io.Reader, uint32) error + BtcEncode(io.Writer, uint32) error + Command() string + MaxPayloadLength(uint32) uint32 +} + +// makeEmptyMessage creates a message of the appropriate concrete type based +// on the command. +func makeEmptyMessage(command string) (Message, error) { + var msg Message + switch command { + case cmdVersion: + msg = &MsgVersion{} + + case cmdVerAck: + msg = &MsgVerAck{} + + case cmdGetAddr: + msg = &MsgGetAddr{} + + case cmdAddr: + msg = &MsgAddr{} + + case cmdGetBlocks: + msg = &MsgGetBlocks{} + + case cmdBlock: + msg = &MsgBlock{} + + case cmdInv: + msg = &MsgInv{} + + case cmdGetData: + msg = &MsgGetData{} + + case cmdNotFound: + msg = &MsgNotFound{} + + case cmdTx: + msg = &MsgTx{} + + case cmdPing: + msg = &MsgPing{} + + case cmdPong: + msg = &MsgPong{} + + case cmdGetHeaders: + msg = &MsgGetHeaders{} + + case cmdHeaders: + msg = &MsgHeaders{} + + default: + return nil, fmt.Errorf("unhandled command [%s]", command) + } + return msg, nil +} + +// messageHeader defines the header structure for all bitcoin protocol messages. +type messageHeader struct { + magic BitcoinNet // 4 bytes + command string // 12 bytes + length uint32 // 4 bytes + checksum [4]byte // 4 bytes +} + +// readMessageHeader reads a bitcoin messager header from r. +func readMessageHeader(r io.Reader) (*messageHeader, error) { + var command [commandSize]byte + + hdr := messageHeader{} + err := readElements(r, &hdr.magic, &command, &hdr.length, &hdr.checksum) + if err != nil { + return nil, err + } + + // Strip trailing zeros from command string. + hdr.command = string(bytes.TrimRight(command[:], string(0))) + + // Enforce maximum message payload. + if hdr.length > maxMessagePayload { + str := "readMessageHeader: message payload is too large - " + + "Header indicates %d bytes, but max message payload is %d bytes." + return nil, fmt.Errorf(str, hdr.length, maxMessagePayload) + } + + return &hdr, nil +} + +// discardInput reads n bytes from reader r in chunks and discards the read +// bytes. This is used to skip payloads when various errors occur and helps +// prevent rogue nodes from causing massive memory allocation through forging +// header length. +func discardInput(r io.Reader, n uint32) { + maxSize := uint32(10240) // 2k at a time + numReads := n / maxSize + bytesRemaining := n % maxSize + if n > 0 { + buf := make([]byte, maxSize) + for i := uint32(0); i < numReads; i++ { + io.ReadFull(r, buf) + } + } + if bytesRemaining > 0 { + buf := make([]byte, bytesRemaining) + io.ReadFull(r, buf) + } +} + +// readMessage reads the next bitcoin message from r for the provided protocol +// version and message header. +func readMessage(r io.Reader, pver uint32, hdr *messageHeader) (Message, []byte, error) { + if hdr == nil { + return nil, nil, fmt.Errorf("readMessage: nil header") + } + + command := hdr.command + if !utf8.ValidString(command) { + discardInput(r, hdr.length) + str := "readMessage: invalid command %v" + return nil, nil, fmt.Errorf(str, []byte(command)) + } + + // Create struct of appropriate message type based on the command. + msg, err := makeEmptyMessage(command) + if err != nil { + discardInput(r, hdr.length) + return nil, nil, fmt.Errorf("readMessage: %v", err) + } + + // Check for maximum length based on the message type as a malicious client + // could otherwise create a well-formed header and set the length to max + // numbers in order to exhaust the machine's memory. + mpl := msg.MaxPayloadLength(pver) + if hdr.length > mpl { + discardInput(r, hdr.length) + str := "ReadMessage: payload exceeds max length - Header " + + "indicates %v bytes, but max payload size for messages of type " + + "[%v] is %v." + return nil, nil, fmt.Errorf(str, hdr.length, command, mpl) + } + + // Read payload. + payload := make([]byte, hdr.length) + n, err := io.ReadFull(r, payload) + if err != nil { + return nil, nil, err + } + if uint32(n) != hdr.length { + str := "readMessage: failed to read payload - Read %v " + + "bytes, but payload size is %v bytes." + return nil, nil, fmt.Errorf(str, n, hdr.length) + } + + // Test checksum. + checksum := DoubleSha256(payload)[0:4] + if !bytes.Equal(checksum[:], hdr.checksum[:]) { + str := "readMessage: payload checksum failed - Header " + + "indicates %v, but actual checksum is %v." + return nil, nil, fmt.Errorf(str, hdr.checksum, checksum) + } + + // Unmarshal message. + pr := bytes.NewBuffer(payload) + err = msg.BtcDecode(pr, pver) + if err != nil { + return nil, nil, err + } + + return msg, payload, nil +} + +// WriteMessage writes a bitcoin Message to w including the necessary header +// information. +func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) error { + var command [commandSize]byte + + cmd := msg.Command() + if len(cmd) > commandSize { + str := "WriteMessage: command is too long [%s]" + return fmt.Errorf(str, command) + } + copy(command[:], []byte(cmd)) + + var bw bytes.Buffer + err := msg.BtcEncode(&bw, pver) + if err != nil { + return err + } + payload := bw.Bytes() + lenp := len(payload) + + // Enforce maximum message payload. + if lenp > maxMessagePayload { + str := "WriteMessage: message payload is too large - " + + "Encoded %d bytes, but maximum message payload is %d bytes." + return fmt.Errorf(str, lenp, maxMessagePayload) + } + + // Create header for the message. + hdr := messageHeader{} + hdr.magic = btcnet + hdr.command = cmd + hdr.length = uint32(lenp) + copy(hdr.checksum[:], DoubleSha256(payload)[0:4]) + + // Write header. + err = writeElements(w, hdr.magic, command, hdr.length, hdr.checksum) + if err != nil { + return err + } + + // Write payload. + n, err := w.Write(payload) + if err != nil { + return err + } + if n != lenp { + str := "WriteMessage: failed to write payload. " + + "Wrote %v bytes, but payload size is %v bytes." + return fmt.Errorf(str, n, lenp) + } + return nil +} + +// ReadMessage reads, validates, and parses the next bitcoin Message from r. +func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, error) { + hdr, err := readMessageHeader(r) + if err != nil { + return nil, nil, err + } + + if hdr.magic != btcnet { + str := "ReadMessage: message from other network [%v]" + return nil, nil, fmt.Errorf(str, hdr.magic) + } + + return readMessage(r, pver, hdr) +} diff --git a/message_test.go b/message_test.go new file mode 100644 index 00000000..27756e9e --- /dev/null +++ b/message_test.go @@ -0,0 +1,98 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "net" + "reflect" + "testing" + "time" +) + +// TestMessage tests the Read/WriteMessage API. +func TestMessage(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Create the various types of messages to test. + + // MsgVersion. + addrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333} + you, err := btcwire.NewNetAddress(addrYou, btcwire.SFNodeNetwork) + if err != nil { + t.Errorf("NewNetAddress: %v", err) + } + you.Timestamp = time.Time{} // Version message has zero value timestamp. + addrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} + me, err := btcwire.NewNetAddress(addrMe, btcwire.SFNodeNetwork) + if err != nil { + t.Errorf("NewNetAddress: %v", err) + } + me.Timestamp = time.Time{} // Version message has zero value timestamp. + msgVersion := btcwire.NewMsgVersion(me, you, 123123, "/test:0.0.1/", 0) + + msgVerack := btcwire.NewMsgVerAck() + msgGetAddr := btcwire.NewMsgGetAddr() + msgAddr := btcwire.NewMsgAddr() + msgGetBlocks := btcwire.NewMsgGetBlocks(&btcwire.ShaHash{}) + msgBlock := &blockOne + msgInv := btcwire.NewMsgInv() + msgGetData := btcwire.NewMsgGetData() + msgNotFound := btcwire.NewMsgNotFound() + msgTx := btcwire.NewMsgTx() + msgPing := btcwire.NewMsgPing(123123) + msgPong := btcwire.NewMsgPong(123123) + msgGetHeaders := btcwire.NewMsgGetHeaders() + msgHeaders := btcwire.NewMsgHeaders() + + tests := []struct { + in btcwire.Message // Value to encode + out btcwire.Message // Expected decoded value + pver uint32 // Protocol version for wire encoding + btcnet btcwire.BitcoinNet // Network to use for wire encoding + }{ + {msgVersion, msgVersion, pver, btcwire.MainNet}, + {msgVerack, msgVerack, pver, btcwire.MainNet}, + {msgGetAddr, msgGetAddr, pver, btcwire.MainNet}, + {msgAddr, msgAddr, pver, btcwire.MainNet}, + {msgGetBlocks, msgGetBlocks, pver, btcwire.MainNet}, + {msgBlock, msgBlock, pver, btcwire.MainNet}, + {msgInv, msgInv, pver, btcwire.MainNet}, + {msgGetData, msgGetData, pver, btcwire.MainNet}, + {msgNotFound, msgNotFound, pver, btcwire.MainNet}, + {msgTx, msgTx, pver, btcwire.MainNet}, + {msgPing, msgPing, pver, btcwire.MainNet}, + {msgPong, msgPong, pver, btcwire.MainNet}, + {msgGetHeaders, msgGetHeaders, pver, btcwire.MainNet}, + {msgHeaders, msgHeaders, pver, btcwire.MainNet}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Encode to wire format. + var buf bytes.Buffer + err := btcwire.WriteMessage(&buf, test.in, test.pver, test.btcnet) + if err != nil { + t.Errorf("WriteMessage #%d error %v", i, err) + continue + } + + // Decode from wire format. + rbuf := bytes.NewBuffer(buf.Bytes()) + msg, _, err := btcwire.ReadMessage(rbuf, test.pver, test.btcnet) + if err != nil { + t.Errorf("ReadMessage #%d error %v, msg %v", i, err, + spew.Sdump(msg)) + continue + } + if !reflect.DeepEqual(msg, test.out) { + t.Errorf("ReadMessage #%d\n got: %v want: %v", i, + spew.Sdump(msg), spew.Sdump(test.out)) + continue + } + } +} diff --git a/msgaddr.go b/msgaddr.go new file mode 100644 index 00000000..54eb4e6c --- /dev/null +++ b/msgaddr.go @@ -0,0 +1,136 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// MaxAddrPerMsg is the maximum number of addresses that can be in a single +// bitcoin addr message (MsgAddr). +const MaxAddrPerMsg = 1000 + +// MsgAddr implements the Message interface and represents a bitcoin +// addr message. It is used to provide a list of known active peers on the +// network. An active peer is considered one that has transmitted a message +// within the last 3 hours. Nodes which have not transmitted in that time +// frame should be forgotten. Each message is limited to a maximum number of +// addresses, which is currently 1000. As a result, multiple messages must +// be used to relay the full list. +// +// Use the AddAddress function to build up the list of known addresses when +// sending an addr message to another peer. +type MsgAddr struct { + AddrList []*NetAddress +} + +// AddAddress adds a known active peer to the message. +func (msg *MsgAddr) AddAddress(na *NetAddress) error { + if len(msg.AddrList)+1 > MaxAddrPerMsg { + str := "MsgAddr.AddAddress: too many addresses for message [max %v]" + return fmt.Errorf(str, MaxAddrPerMsg) + } + + msg.AddrList = append(msg.AddrList, na) + return nil +} + +// AddAddresses adds multiple known active peers to the message. +func (msg *MsgAddr) AddAddresses(netAddrs ...*NetAddress) error { + for _, na := range netAddrs { + err := msg.AddAddress(na) + if err != nil { + return err + } + } + return nil +} + +// ClearAddresses removes all addresses from the message. +func (msg *MsgAddr) ClearAddresses() { + msg.AddrList = []*NetAddress{} +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgAddr) BtcDecode(r io.Reader, pver uint32) error { + count, err := readVarInt(r, pver) + if err != nil { + return err + } + + // Limit to max addresses per message. + if count > MaxAddrPerMsg { + str := "MsgAddr.BtcDecode: too many addresses in message [%v]" + return fmt.Errorf(str, count) + } + + for i := uint64(0); i < count; i++ { + na := NetAddress{} + err := readNetAddress(r, pver, &na, true) + if err != nil { + return err + } + msg.AddAddress(&na) + } + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgAddr) BtcEncode(w io.Writer, pver uint32) error { + // Protocol versions before MultipleAddressVersion only allowed 1 address + // per message. + count := len(msg.AddrList) + if pver < MultipleAddressVersion && count > 1 { + str := "MsgAddr.BtcDecode: too many addresses in message " + + "for protocol version [version %v max 1]" + return fmt.Errorf(str, pver) + + } + if count > MaxAddrPerMsg { + str := "MsgAddr.BtcDecode: too many addresses in message [max %v]" + return fmt.Errorf(str, count) + } + + err := writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + for _, na := range msg.AddrList { + err = writeNetAddress(w, pver, na, true) + if err != nil { + return err + } + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgAddr) Command() string { + return cmdAddr +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgAddr) MaxPayloadLength(pver uint32) uint32 { + if pver < MultipleAddressVersion { + // Num addresses (varInt) + a single net addresses. + return maxVarIntPayload + maxNetAddressPayload(pver) + } + + // Num addresses (varInt) + max allowed addresses. + return maxVarIntPayload + (MaxAddrPerMsg * maxNetAddressPayload(pver)) +} + +// NewMsgAddr returns a new bitcoin addr message that conforms to the +// Message interface. See MsgAddr for details. +func NewMsgAddr() *MsgAddr { + return &MsgAddr{} +} diff --git a/msgaddr_test.go b/msgaddr_test.go new file mode 100644 index 00000000..fd741ac5 --- /dev/null +++ b/msgaddr_test.go @@ -0,0 +1,205 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "net" + "reflect" + "testing" + "time" +) + +// TestAddr tests the MsgAddr API. +func TestAddr(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Ensure the command is expected value. + wantCmd := "addr" + msg := btcwire.NewMsgAddr() + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgAddr: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Num addresses (varInt) + max allowed addresses. + wantPayload := uint32(30009) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure NetAddresses are added properly. + tcpAddr := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} + na, err := btcwire.NewNetAddress(tcpAddr, btcwire.SFNodeNetwork) + if err != nil { + t.Errorf("NewNetAddress: %v", err) + } + err = msg.AddAddress(na) + if err != nil { + t.Errorf("AddAddress: %v", err) + } + if msg.AddrList[0] != na { + t.Errorf("AddAddress: wrong address added - got %v, want %v", + spew.Sprint(msg.AddrList[0]), spew.Sprint(na)) + } + + // Ensure the address list is cleared properly. + msg.ClearAddresses() + if len(msg.AddrList) != 0 { + t.Errorf("ClearAddresses: address list is not empty - "+ + "got %v [%v], want %v", len(msg.AddrList), + spew.Sprint(msg.AddrList[0]), 0) + } + + // Ensure adding more than the max allowed addresses per message returns + // error. + for i := 0; i < btcwire.MaxAddrPerMsg+1; i++ { + err = msg.AddAddress(na) + } + if err == nil { + t.Errorf("AddAddress: expected error on too many addresses " + + "not received") + } + err = msg.AddAddresses(na) + if err == nil { + t.Errorf("AddAddresses: expected error on too many addresses " + + "not received") + } + + // Ensure max payload is expected value for protocol versions before + // timestamp was added to NetAddress. + // Num addresses (varInt) + max allowed addresses. + pver = btcwire.NetAddressTimeVersion - 1 + wantPayload = uint32(26009) + maxPayload = msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure max payload is expected value for protocol versions before + // multiple addresses were allowed. + // Num addresses (varInt) + a single net addresses. + pver = btcwire.MultipleAddressVersion - 1 + wantPayload = uint32(35) + maxPayload = msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + return +} + +// TestAddrWire tests the MsgAddr wire encode and decode for various numbers +// of addreses and protocol versions. +func TestAddrWire(t *testing.T) { + // A couple of NetAddresses to use for testing. + na := &btcwire.NetAddress{ + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("127.0.0.1"), + Port: 8333, + } + na2 := &btcwire.NetAddress{ + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("192.168.0.1"), + Port: 8334, + } + + // Empty address message. + noAddr := btcwire.NewMsgAddr() + noAddrEncoded := []byte{ + 0x00, // Varint for number of addresses + } + + // Address message with multiple addresses. + multiAddr := btcwire.NewMsgAddr() + multiAddr.AddAddresses(na, na2) + multiAddrEncoded := []byte{ + 0x02, // Varint for number of addresses + 0x29, 0xab, 0x5f, 0x49, // Timestamp + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + 0x29, 0xab, 0x5f, 0x49, // Timestamp + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01, // IP 192.168.0.1 + 0x20, 0x8e, // Port 8334 in big-endian + + } + + tests := []struct { + in *btcwire.MsgAddr // Message to encode + out *btcwire.MsgAddr // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version with no addresses. + { + noAddr, + noAddr, + noAddrEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version with multiple addresses. + { + multiAddr, + multiAddr, + multiAddrEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version MultipleAddressVersion-1 with no addresses. + { + noAddr, + noAddr, + noAddrEncoded, + btcwire.MultipleAddressVersion - 1, + }, + } + + 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.MsgAddr + 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 + } + } +} diff --git a/msgalert.go b/msgalert.go new file mode 100644 index 00000000..78879c12 --- /dev/null +++ b/msgalert.go @@ -0,0 +1,80 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "io" +) + +// MsgAlert implements the Message interface and defines a bitcoin alert +// message. +// +// This is a signed message that provides notifications that the client should +// display if the signature matches the key. bitcoind/bitcoin-qt only checks +// against a signature from the core developers. +type MsgAlert struct { + // PayloadBlob is the alert payload serialized as a string so that the + // version can change but the Alert can still be passed on by older + // clients. + PayloadBlob string + + // Signature is the ECDSA signature of the message. + Signature string +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgAlert) BtcDecode(r io.Reader, pver uint32) error { + var err error + msg.PayloadBlob, err = readVarString(r, pver) + if err != nil { + return err + } + msg.Signature, err = readVarString(r, pver) + if err != nil { + return err + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgAlert) BtcEncode(w io.Writer, pver uint32) error { + var err error + err = writeVarString(w, pver, msg.PayloadBlob) + if err != nil { + return err + } + err = writeVarString(w, pver, msg.Signature) + if err != nil { + return err + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgAlert) Command() string { + return cmdAlert +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgAlert) MaxPayloadLength(pver uint32) uint32 { + // Since this can vary depending on the message, make it the max + // size allowed. + return maxMessagePayload +} + +// NewMsgAlert returns a new bitcoin alert message that conforms to the Message +// interface. See MsgAlert for details. +func NewMsgAlert(payloadblob string, signature string) *MsgAlert { + return &MsgAlert{ + PayloadBlob: payloadblob, + Signature: signature, + } +} diff --git a/msgalert_test.go b/msgalert_test.go new file mode 100644 index 00000000..b2b2d8c6 --- /dev/null +++ b/msgalert_test.go @@ -0,0 +1,139 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestAlert tests the MsgAlert API. +func TestAlert(t *testing.T) { + pver := btcwire.ProtocolVersion + payloadblob := "some message" + signature := "some sig" + + // Ensure we get the same payload and signature back out. + msg := btcwire.NewMsgAlert(payloadblob, signature) + if msg.PayloadBlob != payloadblob { + t.Errorf("NewMsgAlert: wrong payloadblob - got %v, want %v", + msg.PayloadBlob, payloadblob) + } + if msg.Signature != signature { + t.Errorf("NewMsgAlert: wrong signature - got %v, want %v", + msg.Signature, signature) + } + + // Ensure the command is expected value. + wantCmd := "alert" + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgAlert: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value. + wantPayload := uint32(1024 * 1024 * 32) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + return +} + +// TestAlertWire tests the MsgAlert wire encode and decode for various protocol +// versions. +func TestAlertWire(t *testing.T) { + baseAlert := btcwire.NewMsgAlert("some payload", "somesig") + baseAlertEncoded := []byte{ + 0x0c, // Varint for payload length + 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, // "some payload" + 0x07, // Varint for signature length + 0x73, 0x6f, 0x6d, 0x65, 0x73, 0x69, 0x67, // "somesig" + } + + tests := []struct { + in *btcwire.MsgAlert // Message to encode + out *btcwire.MsgAlert // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version. + { + baseAlert, + baseAlert, + baseAlertEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version. + { + baseAlert, + baseAlert, + baseAlertEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version. + { + baseAlert, + baseAlert, + baseAlertEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion. + { + baseAlert, + baseAlert, + baseAlertEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion. + { + baseAlert, + baseAlert, + baseAlertEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgAlert + 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 + } + } +} diff --git a/msgblock.go b/msgblock.go new file mode 100644 index 00000000..cdf15eb2 --- /dev/null +++ b/msgblock.go @@ -0,0 +1,163 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "bytes" + "io" +) + +// MaxBlocksPerMsg is the maximum number of blocks allowed per message. +const MaxBlocksPerMsg = 500 + +// TxLoc holds locator data for the offset and length of where a transaction is +// located within a MsgBlock data buffer. +type TxLoc struct { + TxStart int + TxLen int +} + +// MsgBlock implements the Message interface and represents a bitcoin +// block message. It is used to deliver block and transaction information in +// response to a getdata message (MsgGetData) for a given block hash. +// +// NOTE: Unlike the other message types which contain slices, the number of +// transactions has a specific entry (Header.TxnCount) that must be kept in +// sync. The AddTransaction and ClearTransactions functions properly sync the +// value, but if you are manually modifying the public members, you will need +// to ensure you update the Header.TxnCount when you add and remove +// transactions. +type MsgBlock struct { + Header BlockHeader + Transactions []*MsgTx +} + +// AddTransaction adds a transaction to the message and updates Header.TxnCount +// accordingly. +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) + msg.Header.TxnCount = uint64(len(msg.Transactions)) + return nil + +} + +// ClearTransactions removes all transactions from the message and updates +// Header.TxnCount accordingly. +func (msg *MsgBlock) ClearTransactions() { + msg.Transactions = []*MsgTx{} + msg.Header.TxnCount = 0 +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32) error { + err := readBlockHeader(r, pver, &msg.Header) + if err != nil { + return err + } + + for i := uint64(0); i < msg.Header.TxnCount; i++ { + tx := MsgTx{} + err := tx.BtcDecode(r, pver) + if err != nil { + return err + } + msg.Transactions = append(msg.Transactions, &tx) + } + + return nil +} + +// BtcDecodeTxLoc decodes r using the bitcoin protocol encoding into the +// receiver and returns a slice containing the start and length each transaction +// within the raw data. +func (msg *MsgBlock) BtcDecodeTxLoc(r *bytes.Buffer, pver uint32) ([]TxLoc, error) { + var fullLen int + fullLen = r.Len() + + err := readBlockHeader(r, pver, &msg.Header) + if err != nil { + return nil, err + } + + var txLocs []TxLoc + txLocs = make([]TxLoc, msg.Header.TxnCount) + + for i := uint64(0); i < msg.Header.TxnCount; i++ { + txLocs[i].TxStart = fullLen - r.Len() + tx := MsgTx{} + err := tx.BtcDecode(r, pver) + if err != nil { + return nil, err + } + msg.Transactions = append(msg.Transactions, &tx) + txLocs[i].TxLen = (fullLen - r.Len()) - txLocs[i].TxStart + } + + return txLocs, nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32) error { + // XXX: Max transactions? + msg.Header.TxnCount = uint64(len(msg.Transactions)) + + err := writeBlockHeader(w, pver, &msg.Header) + if err != nil { + return err + } + + for _, tx := range msg.Transactions { + err = tx.BtcEncode(w, pver) + if err != nil { + return err + } + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgBlock) Command() string { + return cmdBlock +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 { + // Block header at 81 bytes + max transactions which can vary up to the + // max message payload. + return maxMessagePayload +} + +// BlockSha computes the block identifier hash for this block. +func (msg *MsgBlock) BlockSha(pver uint32) (ShaHash, error) { + return msg.Header.BlockSha(pver) +} + +// TxShas returns a slice of hashes of all of transactions in this block. +func (msg *MsgBlock) TxShas(pver uint32) ([]ShaHash, error) { + var shaList []ShaHash + for _, tx := range msg.Transactions { + sha, err := tx.TxSha(pver) + if err != nil { + return nil, err + } + shaList = append(shaList, sha) + } + return shaList, nil +} + +// NewMsgBlock returns a new bitcoin block message that conforms to the +// Message interface. See MsgBlock for details. +func NewMsgBlock(blockHeader *BlockHeader) *MsgBlock { + return &MsgBlock{ + Header: *blockHeader, + } +} diff --git a/msgblock_test.go b/msgblock_test.go new file mode 100644 index 00000000..5693153e --- /dev/null +++ b/msgblock_test.go @@ -0,0 +1,292 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" + "time" +) + +// TestBlock tests the MsgBlock API. +func TestBlock(t *testing.T) { + pver := uint32(60002) + + // 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) + + // Ensure the command is expected value. + wantCmd := "block" + msg := btcwire.NewMsgBlock(bh) + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgBlock: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Num addresses (varInt) + max allowed addresses. + wantPayload := uint32(1024 * 1024 * 32) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure we get the same block header data back out. + if !reflect.DeepEqual(&msg.Header, bh) { + t.Errorf("NewMsgBlock: wrong block header - got %v, want %v", + spew.Sdump(&msg.Header), spew.Sdump(bh)) + } + + // Ensure transactions are added properly. + tx := blockOne.Transactions[0].Copy() + msg.AddTransaction(tx) + if !reflect.DeepEqual(msg.Transactions, blockOne.Transactions) { + t.Errorf("AddTransaction: wrong transactions - got %v, want %v", + spew.Sdump(msg.Transactions), + spew.Sdump(blockOne.Transactions)) + } + + // Ensure transactions are properly cleared. + msg.ClearTransactions() + if len(msg.Transactions) != 0 { + t.Errorf("ClearTransactions: wrong transactions - got %v, want %v", + len(msg.Transactions), 0) + } + + return +} + +func TestBlockTxShas(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Block 1, transaction 1 hash. + hashStr := "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098" + wantHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + return + } + + wantShas := []btcwire.ShaHash{*wantHash} + shas, err := blockOne.TxShas(pver) + if err != nil { + t.Errorf("TxShas: %v", err) + } + if !reflect.DeepEqual(shas, wantShas) { + t.Errorf("TxShas: wrong transaction hashes - got %v, want %v", + spew.Sdump(shas), spew.Sdump(wantShas)) + } +} + +func TestBlockSha(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Block 1 hash. + hashStr := "839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048" + wantHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Ensure the hash produced is expected. + blockHash, err := blockOne.BlockSha(pver) + if err != nil { + t.Errorf("BlockSha: %v", err) + } + if !blockHash.IsEqual(wantHash) { + t.Errorf("BlockSha: wrong hash - got %v, want %v", + spew.Sprint(blockHash), spew.Sprint(wantHash)) + } +} + +// TestBlockWire tests the MsgBlock wire encode and decode for various numbers +// of transaction inputs and outputs and protocol versions. +func TestBlockWire(t *testing.T) { + tests := []struct { + in *btcwire.MsgBlock // Message to encode + out *btcwire.MsgBlock // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version. + { + &blockOne, + &blockOne, + blockOneBytes, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version. + { + &blockOne, + &blockOne, + blockOneBytes, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version. + { + &blockOne, + &blockOne, + blockOneBytes, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion. + { + &blockOne, + &blockOne, + blockOneBytes, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion. + { + &blockOne, + &blockOne, + blockOneBytes, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgBlock + 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 + } + } +} + +var blockOne btcwire.MsgBlock = btcwire.MsgBlock{ + Header: btcwire.BlockHeader{ + Version: 1, + PrevBlock: btcwire.ShaHash{ + 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{ + 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 + TxnCount: 1, + }, + Transactions: []*btcwire.MsgTx{ + &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + &btcwire.TxIn{ + PreviousOutpoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, + }, + Sequence: 0xffffffff, + }, + }, + TxOut: []*btcwire.TxOut{ + &btcwire.TxOut{ + Value: 0x12a05f200, + PkScript: []byte{ + 0x41, // OP_DATA_65 + 0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c, + 0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16, + 0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c, + 0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c, + 0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4, + 0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6, + 0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e, + 0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58, + 0xee, // 65-byte signature + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + }, + }, +} + +var blockOneBytes = []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, // TxnCount + 0x01, 0x00, 0x00, 0x00, // Version + 0x01, // Varint for number of input transactions + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // // Previous output hash + 0xff, 0xff, 0xff, 0xff, // Prevous output index + 0x07, // Varint for length of signature script + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script + 0xff, 0xff, 0xff, 0xff, // Sequence + 0x01, // Varint for number of output transactions + 0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount + 0x43, // Varint for length of pk script + 0x41, // OP_DATA_65 + 0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c, + 0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16, + 0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c, + 0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c, + 0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4, + 0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6, + 0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e, + 0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58, + 0xee, // 65-byte signature + 0xac, // OP_CHECKSIG + 0x00, 0x00, 0x00, 0x00, // Lock time +} diff --git a/msggetaddr.go b/msggetaddr.go new file mode 100644 index 00000000..385a3e44 --- /dev/null +++ b/msggetaddr.go @@ -0,0 +1,47 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "io" +) + +// MsgGetAddr implements the Message interface and represents a bitcoin +// getaddr message. It is used to request a list of known active peers on the +// network from a peer to help identify potential nodes. The list is returned +// via one or more addr messages (MsgAddr). +// +// This message has no payload. +type MsgGetAddr struct{} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgGetAddr) BtcDecode(r io.Reader, pver uint32) error { + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgGetAddr) BtcEncode(w io.Writer, pver uint32) error { + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgGetAddr) Command() string { + return cmdGetAddr +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgGetAddr) MaxPayloadLength(pver uint32) uint32 { + return 0 +} + +// NewMsgGetAddr returns a new bitcoin getaddr message that conforms to the +// Message interface. See MsgGetAddr for details. +func NewMsgGetAddr() *MsgGetAddr { + return &MsgGetAddr{} +} diff --git a/msggetaddr_test.go b/msggetaddr_test.go new file mode 100644 index 00000000..fdbc2d33 --- /dev/null +++ b/msggetaddr_test.go @@ -0,0 +1,122 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestGetAddr tests the MsgGetAddr API. +func TestGetAddr(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Ensure the command is expected value. + wantCmd := "getaddr" + msg := btcwire.NewMsgGetAddr() + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgGetAddr: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Num addresses (varInt) + max allowed addresses. + wantPayload := uint32(0) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + return +} + +// TestGetAddrWire tests the MsgGetAddr wire encode and decode for various +// protocol versions. +func TestGetAddrWire(t *testing.T) { + msgGetAddr := btcwire.NewMsgGetAddr() + msgGetAddrEncoded := []byte{} + + tests := []struct { + in *btcwire.MsgGetAddr // Message to encode + out *btcwire.MsgGetAddr // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version. + { + msgGetAddr, + msgGetAddr, + msgGetAddrEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version. + { + msgGetAddr, + msgGetAddr, + msgGetAddrEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version. + { + msgGetAddr, + msgGetAddr, + msgGetAddrEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion. + { + msgGetAddr, + msgGetAddr, + msgGetAddrEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion. + { + msgGetAddr, + msgGetAddr, + msgGetAddrEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgGetAddr + 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 + } + } +} diff --git a/msggetblocks.go b/msggetblocks.go new file mode 100644 index 00000000..9d301614 --- /dev/null +++ b/msggetblocks.go @@ -0,0 +1,140 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// MaxBlockLocatorsPerMsg is the maximum number of block locator hashes allowed +// per message. +const MaxBlockLocatorsPerMsg = 500 + +// MsgGetBlocks implements the Message interface and represents a bitcoin +// getblocks message. It is used to request a list of blocks starting after the +// last known hash in the slice of block locator hashes. The list is returned +// via an inv message (MsgInv) and is limited by a specific hash to stop at or +// the maximum number of blocks per message, which is currently 500. +// +// Set the HashStop field to the hash at which to stop and use +// AddBlockLocatorHash to build up the list of block locator hashes. +// +// The algorithm for building the block locator hashes should be to add the +// hashes in reverse order until you reach the genesis block. In order to keep +// the list of locator hashes to a reasonable number of entries, first add the +// most recent 10 block hashes, then double the step each loop iteration to +// exponentially decrease the number of hashes the further away from head and +// closer to the genesis block you get. +type MsgGetBlocks struct { + ProtocolVersion uint32 + BlockLocatorHashes []*ShaHash + HashStop ShaHash +} + +// AddBlockLocatorHash adds a new block locator hash to the message. +func (msg *MsgGetBlocks) AddBlockLocatorHash(hash *ShaHash) error { + if len(msg.BlockLocatorHashes)+1 > MaxBlockLocatorsPerMsg { + str := "MsgGetBlocks.AddBlockLocatorHash: too many block " + + "locator hashes for message [max %v]" + return fmt.Errorf(str, MaxBlockLocatorsPerMsg) + } + + msg.BlockLocatorHashes = append(msg.BlockLocatorHashes, hash) + return nil +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgGetBlocks) BtcDecode(r io.Reader, pver uint32) error { + err := readElement(r, &msg.ProtocolVersion) + if err != nil { + return err + } + + // Read num block locator hashes and limit to max. + count, err := readVarInt(r, pver) + if err != nil { + return err + } + if count > MaxBlockLocatorsPerMsg { + str := "%v: too many block locator hashes in message [%v]" + return fmt.Errorf(str, "MsgGetBlocks.BtcDecode", count) + } + + for i := uint64(0); i < count; i++ { + sha := ShaHash{} + err := readElement(r, &sha) + if err != nil { + return err + } + msg.AddBlockLocatorHash(&sha) + } + + err = readElement(r, &msg.HashStop) + if err != nil { + return err + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgGetBlocks) BtcEncode(w io.Writer, pver uint32) error { + count := len(msg.BlockLocatorHashes) + if count > MaxBlockLocatorsPerMsg { + str := "%v: too many block locator hashes in message [%v]" + return fmt.Errorf(str, "MsgGetBlocks.BtcEncode", count) + } + + err := writeElement(w, msg.ProtocolVersion) + if err != nil { + return err + } + + err = writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + for _, hash := range msg.BlockLocatorHashes { + err = writeElement(w, hash) + if err != nil { + return err + } + } + + err = writeElement(w, msg.HashStop) + if err != nil { + return err + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgGetBlocks) Command() string { + return cmdGetBlocks +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgGetBlocks) MaxPayloadLength(pver uint32) uint32 { + // Protocol version 4 bytes + num hashes (varInt) + max block locator + // hashes + hash stop. + return 4 + maxVarIntPayload + (MaxBlockLocatorsPerMsg * HashSize) + HashSize +} + +// NewMsgGetBlocks returns a new bitcoin getblocks message that conforms to the +// Message interface using the passed parameters and defaults for the remaining +// fields. +func NewMsgGetBlocks(hashStop *ShaHash) *MsgGetBlocks { + return &MsgGetBlocks{ + ProtocolVersion: ProtocolVersion, + HashStop: *hashStop, + } +} diff --git a/msggetblocks_test.go b/msggetblocks_test.go new file mode 100644 index 00000000..8dc83b80 --- /dev/null +++ b/msggetblocks_test.go @@ -0,0 +1,259 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestGetBlocks tests the MsgGetBlocks API. +func TestGetBlocks(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Block 99500 hash. + hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" + locatorHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Block 100000 hash. + hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" + hashStop, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Ensure we get the same data back out. + msg := btcwire.NewMsgGetBlocks(hashStop) + if !msg.HashStop.IsEqual(hashStop) { + t.Errorf("NewMsgGetBlocks: wrong stop hash - got %v, want %v", + msg.HashStop, hashStop) + } + + // Ensure the command is expected value. + wantCmd := "getblocks" + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgGetBlocks: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Protocol version 4 bytes + num hashes (varInt) + max block locator + // hashes + hash stop. + wantPayload := uint32(16045) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure block locator hashes are added properly. + err = msg.AddBlockLocatorHash(locatorHash) + if err != nil { + t.Errorf("AddBlockLocatorHash: %v", err) + } + if msg.BlockLocatorHashes[0] != locatorHash { + t.Errorf("AddBlockLocatorHash: wrong block locator added - "+ + "got %v, want %v", + spew.Sprint(msg.BlockLocatorHashes[0]), + spew.Sprint(locatorHash)) + } + + // Ensure adding more than the max allowed block locator hashes per + // message returns an error. + for i := 0; i < btcwire.MaxBlockLocatorsPerMsg; i++ { + err = msg.AddBlockLocatorHash(locatorHash) + } + if err == nil { + t.Errorf("AddBlockLocatorHash: expected error on too many " + + "block locator hashes not received") + } + + return +} + +// TestGetBlocksWire tests the MsgGetBlocks wire encode and decode for various +// numbers of block locator hashes and protocol versions. +func TestGetBlocksWire(t *testing.T) { + // Set protocol inside getblocks message. + pver := uint32(60002) + + // Block 99499 hash. + hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535" + hashLocator, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Block 99500 hash. + hashStr = "2e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" + hashLocator2, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Block 100000 hash. + hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" + hashStop, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // MsgGetBlocks message with no block locators or stop hash. + NoLocators := btcwire.NewMsgGetBlocks(&btcwire.ShaHash{}) + NoLocators.ProtocolVersion = pver + NoLocatorsEncoded := []byte{ + 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 + 0x00, // Varint for number of block locator hashes + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Hash stop + } + + // MsgGetBlocks message with multiple block locators and a stop hash. + MultiLocators := btcwire.NewMsgGetBlocks(hashStop) + MultiLocators.AddBlockLocatorHash(hashLocator2) + MultiLocators.AddBlockLocatorHash(hashLocator) + MultiLocatorsEncoded := []byte{ + 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 + 0x02, // Varint for number of block locator hashes + 0xe0, 0xde, 0x06, 0x44, 0x68, 0x13, 0x2c, 0x63, + 0xd2, 0x20, 0xcc, 0x69, 0x12, 0x83, 0xcb, 0x65, + 0xbc, 0xaa, 0xe4, 0x79, 0x94, 0xef, 0x9e, 0x7b, + 0xad, 0xe7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99500 hash + 0x35, 0x75, 0x95, 0xb7, 0xf6, 0x8c, 0xb1, 0x60, + 0xcc, 0xba, 0x2c, 0x9a, 0xc5, 0x42, 0x5f, 0xd9, + 0x6f, 0x0a, 0x01, 0x3d, 0xc9, 0x7e, 0xc8, 0x40, + 0x0f, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99499 hash + 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39, + 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2, + 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa, + 0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // Hash stop + } + + tests := []struct { + in *btcwire.MsgGetBlocks // Message to encode + out *btcwire.MsgGetBlocks // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version with no block locators. + { + NoLocators, + NoLocators, + NoLocatorsEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version with multiple block locators. + { + MultiLocators, + MultiLocators, + MultiLocatorsEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version with no block locators. + { + NoLocators, + NoLocators, + NoLocatorsEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0035Version with multiple block locators. + { + MultiLocators, + MultiLocators, + MultiLocatorsEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version with no block locators. + { + NoLocators, + NoLocators, + NoLocatorsEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version BIP0031Versionwith multiple block locators. + { + MultiLocators, + MultiLocators, + MultiLocatorsEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion with no block locators. + { + NoLocators, + NoLocators, + NoLocatorsEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion multiple block locators. + { + MultiLocators, + MultiLocators, + MultiLocatorsEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion with no block locators. + { + NoLocators, + NoLocators, + NoLocatorsEncoded, + btcwire.MultipleAddressVersion, + }, + + // Protocol version MultipleAddressVersion multiple block locators. + { + MultiLocators, + MultiLocators, + MultiLocatorsEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgGetBlocks + 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 + } + } +} diff --git a/msggetdata.go b/msggetdata.go new file mode 100644 index 00000000..865c94d4 --- /dev/null +++ b/msggetdata.go @@ -0,0 +1,105 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// MsgGetData implements the Message interface and represents a bitcoin +// getdata message. It is used to request data such as blocks and transactions +// from another peer. It should be used in response to the inv (MsgInv) message +// to request the actual data referenced by each inventory vector the receiving +// peer doesn't already have. Each message is limited to a maximum number of +// inventory vectors, which is currently 50,000. As a result, multiple messages +// must be used to request larger amounts of data. +// +// Use the AddInvVect function to build up the list of inventory vectors when +// sending a getdata message to another peer. +type MsgGetData struct { + InvList []*InvVect +} + +// AddInvVect adds an inventory vector to the message. +func (msg *MsgGetData) AddInvVect(iv *InvVect) error { + if len(msg.InvList)+1 > MaxInvPerMsg { + str := "MsgAddr.AddAddress: too many invvect in message [max %v]" + return fmt.Errorf(str, MaxInvPerMsg) + } + + msg.InvList = append(msg.InvList, iv) + return nil +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgGetData) BtcDecode(r io.Reader, pver uint32) error { + count, err := readVarInt(r, pver) + if err != nil { + return err + } + + // Limit to max inventory vectors per message. + if count > MaxInvPerMsg { + str := "MsgGetData.BtcDecode: too many invvect in message [%v]" + return fmt.Errorf(str, count) + } + + for i := uint64(0); i < count; i++ { + iv := InvVect{} + err := readInvVect(r, pver, &iv) + if err != nil { + return err + } + msg.AddInvVect(&iv) + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgGetData) BtcEncode(w io.Writer, pver uint32) error { + // Limit to max inventory vectors per message. + count := len(msg.InvList) + if count > MaxInvPerMsg { + str := "MsgGetData.BtcDecode: too many invvect in message [%v]" + return fmt.Errorf(str, count) + } + + err := writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + for _, iv := range msg.InvList { + err := writeInvVect(w, pver, iv) + if err != nil { + return err + } + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgGetData) Command() string { + return cmdGetData +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgGetData) MaxPayloadLength(pver uint32) uint32 { + // Num inventory vectors (varInt) + max allowed inventory vectors. + return maxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload) +} + +// NewMsgGetData returns a new bitcoin getdata message that conforms to the +// Message interface. See MsgGetData for details. +func NewMsgGetData() *MsgGetData { + return &MsgGetData{} +} diff --git a/msggetdata_test.go b/msggetdata_test.go new file mode 100644 index 00000000..b800af7c --- /dev/null +++ b/msggetdata_test.go @@ -0,0 +1,222 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestGetData tests the MsgGetData API. +func TestGetData(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Ensure the command is expected value. + wantCmd := "getdata" + msg := btcwire.NewMsgGetData() + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgGetData: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Num inventory vectors (varInt) + max allowed inventory vectors. + wantPayload := uint32(1800009) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure inventory vectors are added properly. + hash := btcwire.ShaHash{} + iv := btcwire.NewInvVect(btcwire.InvVect_Block, &hash) + err := msg.AddInvVect(iv) + if err != nil { + t.Errorf("AddInvVect: %v", err) + } + if msg.InvList[0] != iv { + t.Errorf("AddInvVect: wrong invvect added - got %v, want %v", + spew.Sprint(msg.InvList[0]), spew.Sprint(iv)) + } + + // Ensure adding more than the max allowed inventory vectors per + // message returns an error. + for i := 0; i < btcwire.MaxInvPerMsg; i++ { + err = msg.AddInvVect(iv) + } + if err == nil { + t.Errorf("AddInvVect: expected error on too many inventory " + + "vectors not received") + } + + return +} + +// TestGetDataWire tests the MsgGetData wire encode and decode for various +// numbers of inventory vectors and protocol versions. +func TestGetDataWire(t *testing.T) { + // Block 203707 hash. + hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" + blockHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Transation 1 of Block 203707 hash. + hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0" + txHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) + iv2 := btcwire.NewInvVect(btcwire.InvVect_Tx, txHash) + + // Empty MsgGetData message. + NoInv := btcwire.NewMsgGetData() + NoInvEncoded := []byte{ + 0x00, // Varint for number of inventory vectors + } + + // MsgGetData message with multiple inventory vectors. + MultiInv := btcwire.NewMsgGetData() + MultiInv.AddInvVect(iv) + MultiInv.AddInvVect(iv2) + MultiInvEncoded := []byte{ + 0x02, // Varint for number of inv vectors + 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, + 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, + 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, + 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash + 0x01, 0x00, 0x00, 0x00, // InvVect_Tx + 0xf0, 0xfa, 0xcc, 0x7a, 0x48, 0x1b, 0xe7, 0xcf, + 0x42, 0xbd, 0x7f, 0xe5, 0x4f, 0x2c, 0x2a, 0xf8, + 0xef, 0x81, 0x9a, 0xdd, 0x93, 0xee, 0x55, 0x98, + 0x0a, 0xf0, 0x2b, 0x39, 0xc7, 0x3d, 0x8a, 0xd2, // Tx 1 of block 203707 hash + } + + tests := []struct { + in *btcwire.MsgGetData // Message to encode + out *btcwire.MsgGetData // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version with no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0035Version with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version BIP0031Version with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.MultipleAddressVersion, + }, + + // Protocol version MultipleAddressVersion with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgGetData + 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 + } + } +} diff --git a/msggetheaders.go b/msggetheaders.go new file mode 100644 index 00000000..0caeaf83 --- /dev/null +++ b/msggetheaders.go @@ -0,0 +1,135 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// MsgGetHeaders implements the Message interface and represents a bitcoin +// getheaders message. It is used to request a list of block headers for +// blocks starting after the last known hash in the slice of block locator +// hashes. The list is returned via a headers message (MsgHeaders) and is +// limited by a specific hash to stop at or the maximum number of block headers +// per message, which is currently 2000. +// +// Set the HashStop field to the hash at which to stop and use +// AddBlockLocatorHash to build up the list of block locator hashes. +// +// The algorithm for building the block locator hashes should be to add the +// hashes in reverse order until you reach the genesis block. In order to keep +// the list of locator hashes to a resonable number of entries, first add the +// most recent 10 block hashes, then double the step each loop iteration to +// exponentially decrease the number of hashes the further away from head and +// closer to the genesis block you get. +type MsgGetHeaders struct { + ProtocolVersion uint32 + BlockLocatorHashes []*ShaHash + HashStop ShaHash +} + +// AddBlockLocatorHash adds a new block locator hash to the message. +func (msg *MsgGetHeaders) AddBlockLocatorHash(hash *ShaHash) error { + if len(msg.BlockLocatorHashes)+1 > MaxBlockLocatorsPerMsg { + str := "MsgGetHeaders.AddBlockLocatorHash: too many block " + + "locator hashes for message [max %v]" + return fmt.Errorf(str, MaxBlockLocatorsPerMsg) + } + + msg.BlockLocatorHashes = append(msg.BlockLocatorHashes, hash) + return nil +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgGetHeaders) BtcDecode(r io.Reader, pver uint32) error { + err := readElement(r, &msg.ProtocolVersion) + if err != nil { + return err + } + + // Read num block locator hashes and limit to max. + count, err := readVarInt(r, pver) + if err != nil { + return err + } + if count > MaxBlockLocatorsPerMsg { + str := "%v: too many block locator hashes in message [%v]" + return fmt.Errorf(str, "MsgGetHeaders.BtcDecode", count) + } + + for i := uint64(0); i < count; i++ { + sha := ShaHash{} + err := readElement(r, &sha) + if err != nil { + return err + } + msg.AddBlockLocatorHash(&sha) + } + + err = readElement(r, &msg.HashStop) + if err != nil { + return err + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgGetHeaders) BtcEncode(w io.Writer, pver uint32) error { + // Limit to max block locator hashes per message. + count := len(msg.BlockLocatorHashes) + if count > MaxBlockLocatorsPerMsg { + str := "MsgGetHeaders.BtcEncode: too many block locator " + + "hashes in message [%v]" + return fmt.Errorf(str, count) + } + + err := writeElement(w, msg.ProtocolVersion) + if err != nil { + return err + } + + err = writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + for _, sha := range msg.BlockLocatorHashes { + err := writeElement(w, sha) + if err != nil { + return err + } + } + + err = writeElement(w, msg.HashStop) + if err != nil { + return err + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgGetHeaders) Command() string { + return cmdGetHeaders +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgGetHeaders) MaxPayloadLength(pver uint32) uint32 { + // Version 4 bytes + num block locator hashes (varInt) + max allowed block + // locators + hash stop. + return 4 + maxVarIntPayload + (MaxBlockLocatorsPerMsg * HashSize) + HashSize +} + +// NewMsgGetHeaders returns a new bitcoin getheaders message that conforms to +// the Message interface. See MsgGetHeaders for details. +func NewMsgGetHeaders() *MsgGetHeaders { + return &MsgGetHeaders{} +} diff --git a/msggetheaders_test.go b/msggetheaders_test.go new file mode 100644 index 00000000..86a0f8f5 --- /dev/null +++ b/msggetheaders_test.go @@ -0,0 +1,248 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestGetHeaders tests the MsgGetHeader API. +func TestGetHeaders(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Block 99500 hash. + hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" + locatorHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Ensure the command is expected value. + wantCmd := "getheaders" + msg := btcwire.NewMsgGetHeaders() + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgGetHeaders: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Protocol version 4 bytes + num hashes (varInt) + max block locator + // hashes + hash stop. + wantPayload := uint32(16045) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure block locator hashes are added properly. + err = msg.AddBlockLocatorHash(locatorHash) + if err != nil { + t.Errorf("AddBlockLocatorHash: %v", err) + } + if msg.BlockLocatorHashes[0] != locatorHash { + t.Errorf("AddBlockLocatorHash: wrong block locator added - "+ + "got %v, want %v", + spew.Sprint(msg.BlockLocatorHashes[0]), + spew.Sprint(locatorHash)) + } + + // Ensure adding more than the max allowed block locator hashes per + // message returns an error. + for i := 0; i < btcwire.MaxBlockLocatorsPerMsg; i++ { + err = msg.AddBlockLocatorHash(locatorHash) + } + if err == nil { + t.Errorf("AddBlockLocatorHash: expected error on too many " + + "block locator hashes not received") + } + + return +} + +// TestGetHeadersWire tests the MsgGetHeaders wire encode and decode for various +// numbers of block locator hashes and protocol versions. +func TestGetHeadersWire(t *testing.T) { + // Set protocol inside getheaders message. + pver := uint32(60002) + + // Block 99499 hash. + hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535" + hashLocator, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Block 99500 hash. + hashStr = "2e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" + hashLocator2, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Block 100000 hash. + hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" + hashStop, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // MsgGetHeaders message with no block locators or stop hash. + NoLocators := btcwire.NewMsgGetHeaders() + NoLocators.ProtocolVersion = pver + NoLocatorsEncoded := []byte{ + 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 + 0x00, // Varint for number of block locator hashes + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Hash stop + } + + // MsgGetHeaders message with multiple block locators and a stop hash. + MultiLocators := btcwire.NewMsgGetHeaders() + MultiLocators.ProtocolVersion = pver + MultiLocators.HashStop = *hashStop + MultiLocators.AddBlockLocatorHash(hashLocator2) + MultiLocators.AddBlockLocatorHash(hashLocator) + MultiLocatorsEncoded := []byte{ + 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 + 0x02, // Varint for number of block locator hashes + 0xe0, 0xde, 0x06, 0x44, 0x68, 0x13, 0x2c, 0x63, + 0xd2, 0x20, 0xcc, 0x69, 0x12, 0x83, 0xcb, 0x65, + 0xbc, 0xaa, 0xe4, 0x79, 0x94, 0xef, 0x9e, 0x7b, + 0xad, 0xe7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99500 hash + 0x35, 0x75, 0x95, 0xb7, 0xf6, 0x8c, 0xb1, 0x60, + 0xcc, 0xba, 0x2c, 0x9a, 0xc5, 0x42, 0x5f, 0xd9, + 0x6f, 0x0a, 0x01, 0x3d, 0xc9, 0x7e, 0xc8, 0x40, + 0x0f, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99499 hash + 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39, + 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2, + 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa, + 0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // Hash stop + } + + tests := []struct { + in *btcwire.MsgGetHeaders // Message to encode + out *btcwire.MsgGetHeaders // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version with no block locators. + { + NoLocators, + NoLocators, + NoLocatorsEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version with multiple block locators. + { + MultiLocators, + MultiLocators, + MultiLocatorsEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version with no block locators. + { + NoLocators, + NoLocators, + NoLocatorsEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0035Version with multiple block locators. + { + MultiLocators, + MultiLocators, + MultiLocatorsEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version with no block locators. + { + NoLocators, + NoLocators, + NoLocatorsEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version BIP0031Versionwith multiple block locators. + { + MultiLocators, + MultiLocators, + MultiLocatorsEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion with no block locators. + { + NoLocators, + NoLocators, + NoLocatorsEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion multiple block locators. + { + MultiLocators, + MultiLocators, + MultiLocatorsEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion with no block locators. + { + NoLocators, + NoLocators, + NoLocatorsEncoded, + btcwire.MultipleAddressVersion, + }, + + // Protocol version MultipleAddressVersion multiple block locators. + { + MultiLocators, + MultiLocators, + MultiLocatorsEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgGetHeaders + 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 + } + } +} diff --git a/msgheaders.go b/msgheaders.go new file mode 100644 index 00000000..dd416651 --- /dev/null +++ b/msgheaders.go @@ -0,0 +1,119 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// MaxBlockHeadersPerMsg is the maximum number of block headers that can be in +// a single bitcoin headers message. +const MaxBlockHeadersPerMsg = 2000 + +// MsgHeaders implements the Message interface and represents a bitcoin headers +// message. It is used to deliver block header information in response +// to a getheaders message (MsgGetHeaders). The maximum number of block headers +// per message is currently 2000. See MsgGetHeaders for details on requesting +// the headers. +type MsgHeaders struct { + Headers []*BlockHeader +} + +// AddBlockHeader adds a new block header to the message. +func (msg *MsgHeaders) AddBlockHeader(bh *BlockHeader) error { + if len(msg.Headers)+1 > MaxBlockHeadersPerMsg { + str := "MsgHeaders.AddBlockHeader: too many block headers " + + "for message [max %v]" + return fmt.Errorf(str, MaxBlockHeadersPerMsg) + } + + msg.Headers = append(msg.Headers, bh) + return nil +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32) error { + count, err := readVarInt(r, pver) + if err != nil { + return err + } + + // Limit to max block headers per message. + if count > MaxBlockHeadersPerMsg { + str := "MsgHeaders.BtcDecode: too many block headers in message [%v]" + return fmt.Errorf(str, count) + } + + for i := uint64(0); i < count; i++ { + bh := BlockHeader{} + err := readBlockHeader(r, pver, &bh) + if err != nil { + return err + } + + // Ensure the transaction count is zero for headers. + if bh.TxnCount > 0 { + str := "MsgHeaders.BtcDecode: block headers may not " + + "contain transactions [%v]" + return fmt.Errorf(str, count) + } + msg.AddBlockHeader(&bh) + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgHeaders) BtcEncode(w io.Writer, pver uint32) error { + // Limit to max block headers per message. + count := len(msg.Headers) + if count > MaxBlockHeadersPerMsg { + str := "MsgHeaders.BtcEncode: too many block headers in message [%v]" + return fmt.Errorf(str, count) + } + + err := writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + for _, bh := range msg.Headers { + // Ensure block headers do not contain a transaction count. + if bh.TxnCount > 0 { + str := "MsgHeaders.BtcEncode: block headers " + + "may not contain transactions [%v]" + return fmt.Errorf(str, count) + } + + err := writeBlockHeader(w, pver, bh) + if err != nil { + return err + } + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgHeaders) Command() string { + return cmdHeaders +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 { + // Num headers (varInt) + max allowed headers. + return maxVarIntPayload + (maxBlockHeaderPayload * MaxBlockHeadersPerMsg) +} + +// NewMsgGetHeaders returns a new bitcoin headers message that conforms to the +// Message interface. See MsgHeaders for details. +func NewMsgHeaders() *MsgHeaders { + return &MsgHeaders{} +} diff --git a/msgheaders_test.go b/msgheaders_test.go new file mode 100644 index 00000000..67ac3c89 --- /dev/null +++ b/msgheaders_test.go @@ -0,0 +1,219 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +var dumpmessage bool = false +var checkverbose = true + +const time1 uint32 = 1363020888 +const time2 uint32 = 1363021079 + +// TestHeaders tests the MsgHeaders API. +func TestHeaders(t *testing.T) { + pver := uint32(60002) + + // Ensure the command is expected value. + wantCmd := "headers" + msg := btcwire.NewMsgHeaders() + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgHeaders: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Num headers (varInt) + max allowed headers. + wantPayload := uint32(178009) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure headers are added properly. + bh := &blockOne.Header + msg.AddBlockHeader(bh) + if !reflect.DeepEqual(msg.Headers[0], bh) { + t.Errorf("AddHeader: wrong header - got %v, want %v", + spew.Sdump(msg.Headers), + spew.Sdump(bh)) + } + + // Ensure adding more than the max allowed headers per message returns + // error. + var err error + for i := 0; i < btcwire.MaxBlockHeadersPerMsg+1; i++ { + err = msg.AddBlockHeader(bh) + } + // TODO(davec): Check for actual error. + if err == nil { + t.Errorf("AddBlockHeader: expected error on too many headers " + + "not received") + } + + return +} + +// TestHeadersWire tests the MsgHeaders wire encode and decode for various +// numbers of headers and protocol versions. +func TestHeadersWire(t *testing.T) { + hash := btcwire.GenesisHash + merkleHash := blockOne.Header.MerkleRoot + bits := uint32(0x1d00ffff) + nonce := uint32(0x9962e301) + bh := btcwire.NewBlockHeader(&hash, &merkleHash, bits, nonce) + bh.Version = blockOne.Header.Version + bh.Timestamp = blockOne.Header.Timestamp + + // Empty headers message. + noHeaders := btcwire.NewMsgHeaders() + noHeadersEncoded := []byte{ + 0x00, // Varint for number of headers + } + + // Headers message with one header. + oneHeader := btcwire.NewMsgHeaders() + oneHeader.AddBlockHeader(bh) + oneHeaderEncoded := []byte{ + 0x01, // VarInt for number of headers. + 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 + 0x00, // TxnCount (0 for headers message) + } + + tests := []struct { + in *btcwire.MsgHeaders // Message to encode + out *btcwire.MsgHeaders // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version with no headers. + { + noHeaders, + noHeaders, + noHeadersEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version with one header. + { + oneHeader, + oneHeader, + oneHeaderEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version with no headers. + { + noHeaders, + noHeaders, + noHeadersEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0035Version with one header. + { + oneHeader, + oneHeader, + oneHeaderEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version with no headers. + { + noHeaders, + noHeaders, + noHeadersEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version BIP0031Version with one header. + { + oneHeader, + oneHeader, + oneHeaderEncoded, + btcwire.BIP0031Version, + }, + // Protocol version NetAddressTimeVersion with no headers. + { + noHeaders, + noHeaders, + noHeadersEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion with one header. + { + oneHeader, + oneHeader, + oneHeaderEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion with no headers. + { + noHeaders, + noHeaders, + noHeadersEncoded, + btcwire.MultipleAddressVersion, + }, + + // Protocol version MultipleAddressVersion with one header. + { + oneHeader, + oneHeader, + oneHeaderEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgHeaders + 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 + } + } +} diff --git a/msginv.go b/msginv.go new file mode 100644 index 00000000..9cbb5bf1 --- /dev/null +++ b/msginv.go @@ -0,0 +1,104 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// MsgInv implements the Message interface and represents a bitcoin inv message. +// It is used to advertise a peer's known data such as blocks and transactions +// through inventory vectors. It may be sent unsolicited to inform other peers +// of the data or in response to a getblocks message (MsgGetBlocks). Each +// message is limited to a maximum number of inventory vectors, which is +// currently 50,000. +// +// Use the AddInvVect function to build up the list of inventory vectors when +// sending an inv message to another peer. +type MsgInv struct { + InvList []*InvVect +} + +// AddInvVect adds an inventory vector to the message. +func (msg *MsgInv) AddInvVect(iv *InvVect) error { + if len(msg.InvList)+1 > MaxInvPerMsg { + str := "MsgInv.AddAddress: too many invvect in message [max %v]" + return fmt.Errorf(str, MaxInvPerMsg) + } + + msg.InvList = append(msg.InvList, iv) + return nil +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgInv) BtcDecode(r io.Reader, pver uint32) error { + count, err := readVarInt(r, pver) + if err != nil { + return err + } + + // Limit to max inventory vectors per message. + if count > MaxInvPerMsg { + str := "MsgInv.BtcDecode: too many invvect in message [%v]" + return fmt.Errorf(str, count) + } + + for i := uint64(0); i < count; i++ { + iv := InvVect{} + err := readInvVect(r, pver, &iv) + if err != nil { + return err + } + msg.AddInvVect(&iv) + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgInv) BtcEncode(w io.Writer, pver uint32) error { + // Limit to max inventory vectors per message. + count := len(msg.InvList) + if count > MaxInvPerMsg { + str := "MsgInv.BtcEncode: too many invvect in message [%v]" + return fmt.Errorf(str, count) + } + + err := writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + for _, iv := range msg.InvList { + err := writeInvVect(w, pver, iv) + if err != nil { + return err + } + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgInv) Command() string { + return cmdInv +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgInv) MaxPayloadLength(pver uint32) uint32 { + // Num inventory vectors (varInt) + max allowed inventory vectors. + return maxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload) +} + +// NewMsgInv returns a new bitcoin inv message that conforms to the Message +// interface. See MsgInv for details. +func NewMsgInv() *MsgInv { + return &MsgInv{} +} diff --git a/msginv_test.go b/msginv_test.go new file mode 100644 index 00000000..9852ed2b --- /dev/null +++ b/msginv_test.go @@ -0,0 +1,222 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestInv tests the MsgInv API. +func TestInv(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Ensure the command is expected value. + wantCmd := "inv" + msg := btcwire.NewMsgInv() + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgInv: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Num inventory vectors (varInt) + max allowed inventory vectors. + wantPayload := uint32(1800009) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure inventory vectors are added properly. + hash := btcwire.ShaHash{} + iv := btcwire.NewInvVect(btcwire.InvVect_Block, &hash) + err := msg.AddInvVect(iv) + if err != nil { + t.Errorf("AddInvVect: %v", err) + } + if msg.InvList[0] != iv { + t.Errorf("AddInvVect: wrong invvect added - got %v, want %v", + spew.Sprint(msg.InvList[0]), spew.Sprint(iv)) + } + + // Ensure adding more than the max allowed inventory vectors per + // message returns an error. + for i := 0; i < btcwire.MaxInvPerMsg; i++ { + err = msg.AddInvVect(iv) + } + if err == nil { + t.Errorf("AddInvVect: expected error on too many inventory " + + "vectors not received") + } + + return +} + +// TestInvWire tests the MsgInv wire encode and decode for various numbers +// of inventory vectors and protocol versions. +func TestInvWire(t *testing.T) { + // Block 203707 hash. + hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" + blockHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Transation 1 of Block 203707 hash. + hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0" + txHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) + iv2 := btcwire.NewInvVect(btcwire.InvVect_Tx, txHash) + + // Empty inv message. + NoInv := btcwire.NewMsgInv() + NoInvEncoded := []byte{ + 0x00, // Varint for number of inventory vectors + } + + // Inv message with multiple inventory vectors. + MultiInv := btcwire.NewMsgInv() + MultiInv.AddInvVect(iv) + MultiInv.AddInvVect(iv2) + MultiInvEncoded := []byte{ + 0x02, // Varint for number of inv vectors + 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, + 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, + 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, + 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash + 0x01, 0x00, 0x00, 0x00, // InvVect_Tx + 0xf0, 0xfa, 0xcc, 0x7a, 0x48, 0x1b, 0xe7, 0xcf, + 0x42, 0xbd, 0x7f, 0xe5, 0x4f, 0x2c, 0x2a, 0xf8, + 0xef, 0x81, 0x9a, 0xdd, 0x93, 0xee, 0x55, 0x98, + 0x0a, 0xf0, 0x2b, 0x39, 0xc7, 0x3d, 0x8a, 0xd2, // Tx 1 of block 203707 hash + } + + tests := []struct { + in *btcwire.MsgInv // Message to encode + out *btcwire.MsgInv // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version with no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0035Version with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version BIP0031Version with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.MultipleAddressVersion, + }, + + // Protocol version MultipleAddressVersion with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgInv + 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 + } + } +} diff --git a/msgmempool.go b/msgmempool.go new file mode 100644 index 00000000..36eaf7f5 --- /dev/null +++ b/msgmempool.go @@ -0,0 +1,58 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// MsgMemPool implements the Message interface and represents a bitcoin mempool +// message. It is used to request a list of transactions still in the active +// memory pool of a relay. +// +// This message has no payload and was not added until protocol versions +// starting with BIP0035Version. +type MsgMemPool struct{} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgMemPool) BtcDecode(r io.Reader, pver uint32) error { + if pver < BIP0035Version { + err := fmt.Errorf("mempool message invalid for protocol version: %d", pver) + return err + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgMemPool) BtcEncode(w io.Writer, pver uint32) error { + if pver < BIP0035Version { + err := fmt.Errorf("mempool message invalid for protocol version: %d", pver) + return err + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgMemPool) Command() string { + return cmdMemPool +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgMemPool) MaxPayloadLength(pver uint32) uint32 { + return 0 +} + +// NewMsgPong returns a new bitcoin pong message that conforms to the Message +// interface. See MsgPong for details. +func NewMsgMemPool() *MsgMemPool { + return &MsgMemPool{} +} diff --git a/msgmempool_test.go b/msgmempool_test.go new file mode 100644 index 00000000..4cab821e --- /dev/null +++ b/msgmempool_test.go @@ -0,0 +1,65 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "testing" +) + +func TestMemPool(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Ensure the command is expected value. + wantCmd := "mempool" + msg := btcwire.NewMsgMemPool() + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgMemPool: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value. + wantPayload := uint32(0) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Test encode with latest protocol version. + var buf bytes.Buffer + err := msg.BtcEncode(&buf, pver) + if err != nil { + t.Errorf("encode of MsgMemPool failed %v err <%v>", msg, err) + } + + // Older protocol versions should fail encode since message didn't + // exist yet. + oldPver := btcwire.BIP0035Version - 1 + err = msg.BtcEncode(&buf, oldPver) + if err == nil { + s := "encode of MsgMemPool passed for old protocol version %v err <%v>" + t.Errorf(s, msg, err) + } + + // Test decode with latest protocol version. + readmsg := btcwire.NewMsgMemPool() + err = readmsg.BtcDecode(&buf, pver) + if err != nil { + t.Errorf("decode of MsgMemPool failed [%v] err <%v>", buf, err) + } + + // Older protocol versions should fail decode since message didn't + // exist yet. + err = readmsg.BtcDecode(&buf, oldPver) + if err == nil { + s := "decode of MsgMemPool passed for old protocol version %v err <%v>" + t.Errorf(s, msg, err) + } + + return +} diff --git a/msgnotfound.go b/msgnotfound.go new file mode 100644 index 00000000..c920fe33 --- /dev/null +++ b/msgnotfound.go @@ -0,0 +1,103 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// MsgNotFound defines a bitcoin notfound message which is sent in response to +// a getdata message if any of the requested data in not available on the peer. +// Each message is limited to a maximum number of inventory vectors, which is +// currently 50,000. +// +// Use the AddInvVect function to build up the list of inventory vectors when +// sending a notfound message to another peer. +type MsgNotFound struct { + InvList []*InvVect +} + +// AddInvVect adds an inventory vector to the message. +func (msg *MsgNotFound) AddInvVect(iv *InvVect) error { + if len(msg.InvList)+1 > MaxInvPerMsg { + str := "MsgNotFound.AddAddress: too many invvect in message [max %v]" + return fmt.Errorf(str, MaxInvPerMsg) + } + + msg.InvList = append(msg.InvList, iv) + return nil +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgNotFound) BtcDecode(r io.Reader, pver uint32) error { + count, err := readVarInt(r, pver) + if err != nil { + return err + } + + // Limit to max inventory vectors per message. + if count > MaxInvPerMsg { + str := "MsgNotFound.BtcDecode: too many invvect in message [%v]" + return fmt.Errorf(str, count) + } + + for i := uint64(0); i < count; i++ { + iv := InvVect{} + err := readInvVect(r, pver, &iv) + if err != nil { + return err + } + msg.AddInvVect(&iv) + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgNotFound) BtcEncode(w io.Writer, pver uint32) error { + // Limit to max inventory vectors per message. + count := len(msg.InvList) + if count > MaxInvPerMsg { + str := "MsgNotFound.BtcEncode: too many invvect in message [%v]" + return fmt.Errorf(str, count) + } + + err := writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + for _, iv := range msg.InvList { + err := writeInvVect(w, pver, iv) + if err != nil { + return err + } + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgNotFound) Command() string { + return cmdNotFound +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgNotFound) MaxPayloadLength(pver uint32) uint32 { + // Max var int 9 bytes + max InvVects at 36 bytes each. + // Num inventory vectors (varInt) + max allowed inventory vectors. + return maxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload) +} + +// NewMsgNotFound returns a new bitcoin notfound message that conforms to the +// Message interface. See MsgNotFound for details. +func NewMsgNotFound() *MsgNotFound { + return &MsgNotFound{} +} diff --git a/msgnotfound_test.go b/msgnotfound_test.go new file mode 100644 index 00000000..190f2da2 --- /dev/null +++ b/msgnotfound_test.go @@ -0,0 +1,222 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestNotFound tests the MsgNotFound API. +func TestNotFound(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Ensure the command is expected value. + wantCmd := "notfound" + msg := btcwire.NewMsgNotFound() + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgNotFound: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Num inventory vectors (varInt) + max allowed inventory vectors. + wantPayload := uint32(1800009) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure inventory vectors are added properly. + hash := btcwire.ShaHash{} + iv := btcwire.NewInvVect(btcwire.InvVect_Block, &hash) + err := msg.AddInvVect(iv) + if err != nil { + t.Errorf("AddInvVect: %v", err) + } + if msg.InvList[0] != iv { + t.Errorf("AddInvVect: wrong invvect added - got %v, want %v", + spew.Sprint(msg.InvList[0]), spew.Sprint(iv)) + } + + // Ensure adding more than the max allowed inventory vectors per + // message returns an error. + for i := 0; i < btcwire.MaxInvPerMsg; i++ { + err = msg.AddInvVect(iv) + } + if err == nil { + t.Errorf("AddInvVect: expected error on too many inventory " + + "vectors not received") + } + + return +} + +// TestNotFoundWire tests the MsgNotFound wire encode and decode for various +// numbers of inventory vectors and protocol versions. +func TestNotFoundWire(t *testing.T) { + // Block 203707 hash. + hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" + blockHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Transation 1 of Block 203707 hash. + hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0" + txHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) + iv2 := btcwire.NewInvVect(btcwire.InvVect_Tx, txHash) + + // Empty notfound message. + NoInv := btcwire.NewMsgNotFound() + NoInvEncoded := []byte{ + 0x00, // Varint for number of inventory vectors + } + + // NotFound message with multiple inventory vectors. + MultiInv := btcwire.NewMsgNotFound() + MultiInv.AddInvVect(iv) + MultiInv.AddInvVect(iv2) + MultiInvEncoded := []byte{ + 0x02, // Varint for number of inv vectors + 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, + 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, + 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, + 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash + 0x01, 0x00, 0x00, 0x00, // InvVect_Tx + 0xf0, 0xfa, 0xcc, 0x7a, 0x48, 0x1b, 0xe7, 0xcf, + 0x42, 0xbd, 0x7f, 0xe5, 0x4f, 0x2c, 0x2a, 0xf8, + 0xef, 0x81, 0x9a, 0xdd, 0x93, 0xee, 0x55, 0x98, + 0x0a, 0xf0, 0x2b, 0x39, 0xc7, 0x3d, 0x8a, 0xd2, // Tx 1 of block 203707 hash + } + + tests := []struct { + in *btcwire.MsgNotFound // Message to encode + out *btcwire.MsgNotFound // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version with no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0035Version with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version BIP0031Version with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion no inv vectors. + { + NoInv, + NoInv, + NoInvEncoded, + btcwire.MultipleAddressVersion, + }, + + // Protocol version MultipleAddressVersion with multiple inv vectors. + { + MultiInv, + MultiInv, + MultiInvEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgNotFound + 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 + } + } +} diff --git a/msgping.go b/msgping.go new file mode 100644 index 00000000..15f6580d --- /dev/null +++ b/msgping.go @@ -0,0 +1,87 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "io" +) + +// MsgPong implements the Message interface and represents a bitcoin ping +// message. +// +// For versions BIP0031Version and earlier, it is used primarily to confirm +// that a connection is still valid. A transmission error is typically +// interpreted as a closed connection and that the peer should be removed. +// For versions AFTER BIP0031Version it contains an identifier which can be +// returned in the pong message to determine network timing. +// +// The payload for this message just consists of a nonce used for identifying +// it later. +type MsgPing struct { + // Unique value associated with message that is used to identify + // specific ping message. + Nonce uint64 +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgPing) BtcDecode(r io.Reader, pver uint32) error { + // There was no nonce for BIP0031Version and earlier. + // NOTE: > is not a mistake here. The BIP0031 was defined as AFTER + // the version unlike most others. + if pver > BIP0031Version { + err := readElement(r, &msg.Nonce) + if err != nil { + return err + } + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgPing) BtcEncode(w io.Writer, pver uint32) error { + // There was no nonce for BIP0031Version and earlier. + // NOTE: > is not a mistake here. The BIP0031 was defined as AFTER + // the version unlike most others. + if pver > BIP0031Version { + err := writeElement(w, msg.Nonce) + if err != nil { + return err + } + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgPing) Command() string { + return cmdPing +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgPing) MaxPayloadLength(pver uint32) uint32 { + plen := uint32(0) + // There was no nonce for BIP0031Version and earlier. + // NOTE: > is not a mistake here. The BIP0031 was defined as AFTER + // the version unlike most others. + if pver > BIP0031Version { + // Nonce 8 bytes. + plen += 8 + } + + return plen +} + +// NewMsgPing returns a new bitcoin ping message that conforms to the Message +// interface. See MsgPing for details. +func NewMsgPing(nonce uint64) *MsgPing { + return &MsgPing{ + Nonce: nonce, + } +} diff --git a/msgping_test.go b/msgping_test.go new file mode 100644 index 00000000..8f0d9d18 --- /dev/null +++ b/msgping_test.go @@ -0,0 +1,194 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestPing tests the MsgPing API against the latest protocol version. +func TestPing(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Ensure we get the same nonce back out. + nonce, err := btcwire.RandomUint64() + if err != nil { + t.Errorf("RandomUint64: Error generating nonce: %v", err) + } + msg := btcwire.NewMsgPing(nonce) + if msg.Nonce != nonce { + t.Errorf("NewMsgPing: wrong nonce - got %v, want %v", + msg.Nonce, nonce) + } + + // Ensure the command is expected value. + wantCmd := "ping" + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgPing: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + wantPayload := uint32(8) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + return +} + +// TestPingBIP0031 tests the MsgPing API against the protocol version +// BIP0031Version. +func TestPingBIP0031(t *testing.T) { + // Use the protocol version just prior to BIP0031Version changes. + pver := btcwire.BIP0031Version + + nonce, err := btcwire.RandomUint64() + if err != nil { + t.Errorf("RandomUint64: Error generating nonce: %v", err) + } + msg := btcwire.NewMsgPing(nonce) + if msg.Nonce != nonce { + t.Errorf("NewMsgPing: wrong nonce - got %v, want %v", + msg.Nonce, nonce) + } + + // Ensure max payload is expected value for old protocol version. + wantPayload := uint32(0) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Test encode with old protocol version. + var buf bytes.Buffer + err = msg.BtcEncode(&buf, pver) + if err != nil { + t.Errorf("encode of MsgPing failed %v err <%v>", msg, err) + } + + // Test decode with old protocol version. + readmsg := btcwire.NewMsgPing(0) + err = readmsg.BtcDecode(&buf, pver) + if err != nil { + t.Errorf("decode of MsgPing failed [%v] err <%v>", buf, err) + } + + // Since this protocol version doesn't support the nonce, make sure + // it didn't get encoded and decoded back out. + if msg.Nonce == readmsg.Nonce { + t.Errorf("Should not get same nonce for protocol version %d", pver) + } + + return +} + +// TestPingCrossProtocol tests the MsgPing API when encoding with the latest +// protocol version and decoded with BIP0031Version. +func TestPingCrossProtocol(t *testing.T) { + nonce, err := btcwire.RandomUint64() + if err != nil { + t.Errorf("RandomUint64: Error generating nonce: %v", err) + } + msg := btcwire.NewMsgPing(nonce) + if msg.Nonce != nonce { + t.Errorf("NewMsgPing: wrong nonce - got %v, want %v", + msg.Nonce, nonce) + } + + // Encode with latest protocol version. + var buf bytes.Buffer + err = msg.BtcEncode(&buf, btcwire.ProtocolVersion) + if err != nil { + t.Errorf("encode of MsgPing failed %v err <%v>", msg, err) + } + + // Decode with old protocol version. + readmsg := btcwire.NewMsgPing(0) + err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version) + if err != nil { + t.Errorf("decode of MsgPing failed [%v] err <%v>", buf, err) + } + + // Since one of the protocol versions doesn't support the nonce, make + // sure it didn't get encoded and decoded back out. + if msg.Nonce == readmsg.Nonce { + t.Error("Should not get same nonce for cross protocol") + } +} + +// TestPingWire tests the MsgPing wire encode and decode for various protocol +// versions. +func TestPingWire(t *testing.T) { + tests := []struct { + in btcwire.MsgPing // Message to encode + out btcwire.MsgPing // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version. + { + btcwire.MsgPing{Nonce: 123123}, // 0x1e0f3 + btcwire.MsgPing{Nonce: 123123}, // 0x1e0f3 + []byte{0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0031Version+1 + { + btcwire.MsgPing{Nonce: 456456}, // 0x6f708 + btcwire.MsgPing{Nonce: 456456}, // 0x6f708 + []byte{0x08, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, + btcwire.BIP0031Version + 1, + }, + + // Protocol version BIP0031Version + { + btcwire.MsgPing{Nonce: 789789}, // 0xc0d1d + btcwire.MsgPing{Nonce: 0}, // No nonce for pver + []byte{}, // No nonce for pver + btcwire.BIP0031Version, + }, + } + + 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.MsgPing + 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 + } + } +} diff --git a/msgpong.go b/msgpong.go new file mode 100644 index 00000000..8794ebd5 --- /dev/null +++ b/msgpong.go @@ -0,0 +1,88 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// MsgPong implements the Message interface and represents a bitcoin pong +// message which is used primarily to confirm that a connection is still valid +// in response to a bitcoin ping message (MsgPing). +// +// This message was not added until protocol versions AFTER BIP0031Version. +type MsgPong struct { + // Unique value associated with message that is used to identify + // specific ping message. + Nonce uint64 +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgPong) BtcDecode(r io.Reader, pver uint32) error { + // NOTE: <= is not a mistake here. The BIP0031 was defined as AFTER + // the version unlike most others. + if pver <= BIP0031Version { + err := fmt.Errorf("pong message invalid for protocol version: %d", + pver) + return err + } + + err := readElement(r, &msg.Nonce) + if err != nil { + return err + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgPong) BtcEncode(w io.Writer, pver uint32) error { + // NOTE: <= is not a mistake here. The BIP0031 was defined as AFTER + // the version unlike most others. + if pver <= BIP0031Version { + err := fmt.Errorf("pong message invalid for protocol version: %d", + pver) + return err + } + + err := writeElement(w, msg.Nonce) + if err != nil { + return err + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgPong) Command() string { + return cmdPong +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgPong) MaxPayloadLength(pver uint32) uint32 { + plen := uint32(0) + // The pong message did not exist for BIP0031Version and earlier. + // NOTE: > is not a mistake here. The BIP0031 was defined as AFTER + // the version unlike most others. + if pver > BIP0031Version { + // Nonce 8 bytes. + plen += 8 + } + + return plen +} + +// NewMsgPong returns a new bitcoin pong message that conforms to the Message +// interface. See MsgPong for details. +func NewMsgPong(nonce uint64) *MsgPong { + return &MsgPong{ + Nonce: nonce, + } +} diff --git a/msgpong_test.go b/msgpong_test.go new file mode 100644 index 00000000..0297888d --- /dev/null +++ b/msgpong_test.go @@ -0,0 +1,215 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestPongLatest tests the MsgPong API against the latest protocol version. +func TestPongLatest(t *testing.T) { + pver := btcwire.ProtocolVersion + + nonce, err := btcwire.RandomUint64() + if err != nil { + t.Errorf("RandomUint64: error generating nonce: %v", err) + } + msg := btcwire.NewMsgPong(nonce) + if msg.Nonce != nonce { + t.Errorf("NewMsgPong: wrong nonce - got %v, want %v", + msg.Nonce, nonce) + } + + // Ensure the command is expected value. + wantCmd := "pong" + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgPong: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + wantPayload := uint32(8) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Test encode with latest protocol version. + var buf bytes.Buffer + err = msg.BtcEncode(&buf, pver) + if err != nil { + t.Errorf("encode of MsgPong failed %v err <%v>", msg, err) + } + + // Test decode with latest protocol version. + readmsg := btcwire.NewMsgPong(0) + err = readmsg.BtcDecode(&buf, pver) + if err != nil { + t.Errorf("decode of MsgPong failed [%v] err <%v>", buf, err) + } + + // Ensure nonce is the same. + if msg.Nonce != readmsg.Nonce { + t.Errorf("Should get same nonce for protocol version %d", pver) + } + + return +} + +// TestPongBIP0031 tests the MsgPong API against the protocol version +// BIP0031Version. +func TestPongBIP0031(t *testing.T) { + // Use the protocol version just prior to BIP0031Version changes. + pver := btcwire.BIP0031Version + + nonce, err := btcwire.RandomUint64() + if err != nil { + t.Errorf("Error generating nonce: %v", err) + } + msg := btcwire.NewMsgPong(nonce) + if msg.Nonce != nonce { + t.Errorf("Should get same nonce back out.") + } + + // Ensure max payload is expected value for old protocol version. + size := msg.MaxPayloadLength(pver) + if size != 0 { + t.Errorf("Max length should be 0 for pong protocol version %d.", + pver) + } + + // Test encode with old protocol version. + var buf bytes.Buffer + err = msg.BtcEncode(&buf, pver) + if err == nil { + t.Errorf("encode of MsgPong succeeded when it shouldn't have %v", + msg) + } + + // Test decode with old protocol version. + readmsg := btcwire.NewMsgPong(0) + err = readmsg.BtcDecode(&buf, pver) + if err == nil { + t.Errorf("decode of MsgPong succeeded when it shouldn't have", + spew.Sdump(buf)) + } + + // Since this protocol version doesn't support pong, make sure the + // nonce didn't get encoded and decoded back out. + if msg.Nonce == readmsg.Nonce { + t.Errorf("Should not get same nonce for protocol version %d", pver) + } + + return +} + +// TestPongCrossProtocol tests the MsgPong API when encoding with the latest +// protocol version and decoded with BIP0031Version. +func TestPongCrossProtocol(t *testing.T) { + nonce, err := btcwire.RandomUint64() + if err != nil { + t.Errorf("Error generating nonce: %v", err) + } + msg := btcwire.NewMsgPong(nonce) + if msg.Nonce != nonce { + t.Errorf("Should get same nonce back out.") + } + + // Encode with latest protocol version. + var buf bytes.Buffer + err = msg.BtcEncode(&buf, btcwire.ProtocolVersion) + if err != nil { + t.Errorf("encode of MsgPong failed %v err <%v>", msg, err) + } + + // Decode with old protocol version. + readmsg := btcwire.NewMsgPong(0) + err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version) + if err == nil { + t.Errorf("encode of MsgPong succeeded when it shouldn't have %v", + msg) + } + + // Since one of the protocol versions doesn't support the pong message, + // 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") + } +} + +// TestPongWire tests the MsgPong wire encode and decode for various protocol +// versions. +func TestPongWire(t *testing.T) { + tests := []struct { + in btcwire.MsgPong // Message to encode + out btcwire.MsgPong // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + err error // expected error + }{ + // Latest protocol version. + { + btcwire.MsgPong{Nonce: 123123}, // 0x1e0f3 + btcwire.MsgPong{Nonce: 123123}, // 0x1e0f3 + []byte{0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}, + btcwire.ProtocolVersion, + nil, + }, + + // Protocol version BIP0031Version+1 + { + btcwire.MsgPong{Nonce: 456456}, // 0x6f708 + btcwire.MsgPong{Nonce: 456456}, // 0x6f708 + []byte{0x08, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, + btcwire.BIP0031Version + 1, + nil, + }, + + // Protocol version BIP0031Version + //{ + // btcwire.MsgPong{Nonce: 789789}, // 0xc0d1d + // btcwire.MsgPong{Nonce: 0}, // No nonce for pver + // []byte{}, // No nonce for pver + // btcwire.BIP0031Version, + // nil, /// Need err type.... + //}, + } + + 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 != test.err { + 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.MsgPong + rbuf := bytes.NewBuffer(test.buf) + err = msg.BtcDecode(rbuf, test.pver) + if err != test.err { + 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 + } + } +} diff --git a/msgtx.go b/msgtx.go new file mode 100644 index 00000000..27110f0c --- /dev/null +++ b/msgtx.go @@ -0,0 +1,387 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "bytes" + "io" +) + +// MaxTxInSequenceNum is the maximum sequence number the sequence field +// of a transaction input can be. +const MaxTxInSequenceNum uint32 = 0xffffffff + +// Outpoint defines a bitcoin data type that is used to track previous +// transaction outputs. +type OutPoint struct { + Hash ShaHash + Index uint32 +} + +// NewOutPoint returns a new bitcoin transaction outpoint point with the +// provided hash and index. +func NewOutPoint(hash *ShaHash, index uint32) *OutPoint { + return &OutPoint{ + Hash: *hash, + Index: index, + } +} + +// TxIn defines a bitcoin transaction input. +type TxIn struct { + PreviousOutpoint OutPoint + SignatureScript []byte + Sequence uint32 +} + +// NewTxIn returns a new bitcoin transaction input with the provided +// previous outpoint point and signature script with a default sequence of +// MaxTxInSequenceNum. +func NewTxIn(prevOut *OutPoint, signatureScript []byte) *TxIn { + return &TxIn{ + PreviousOutpoint: *prevOut, + SignatureScript: signatureScript, + Sequence: MaxTxInSequenceNum, + } +} + +// TxOut defines a bitcoin transaction output. +type TxOut struct { + Value int64 + PkScript []byte +} + +// NewTxOut returns a new bitcoin transaction output with the provided +// transaction value and public key script. +func NewTxOut(value int64, pkScript []byte) *TxOut { + return &TxOut{ + Value: value, + PkScript: pkScript, + } +} + +// MsgTx implements the Message interface and represents a bitcoin tx message. +// It is used to deliver transaction information in response to a getdata +// message (MsgGetData) for a given transaction. +// +// Use the AddTxIn and AddTxOut functions to build up the list of transaction +// inputs and outputs. +type MsgTx struct { + Version uint32 + TxIn []*TxIn + TxOut []*TxOut + LockTime uint32 +} + +// AddTxIn adds a transaction input to the message. +func (msg *MsgTx) AddTxIn(ti *TxIn) { + msg.TxIn = append(msg.TxIn, ti) +} + +// AddTxOut adds a transaction output to the message. +func (msg *MsgTx) AddTxOut(to *TxOut) { + msg.TxOut = append(msg.TxOut, to) +} + +// TxSha generates the ShaHash name for the transaction. +func (tx *MsgTx) TxSha(pver uint32) (ShaHash, error) { + var txsha ShaHash + var wbuf bytes.Buffer + err := tx.BtcEncode(&wbuf, pver) + if err != nil { + return txsha, err + } + txsha.SetBytes(DoubleSha256(wbuf.Bytes())) + + return txsha, nil +} + +// Copy creates a deep copy of a transaction so that the original does not get +// modified when the copy is manipulated. +func (tx *MsgTx) Copy() *MsgTx { + // Create new tx and start by copying primitive values. + newTx := MsgTx{ + Version: tx.Version, + LockTime: tx.LockTime, + } + + // Deep copy the old TxIn data. + for _, oldTxIn := range tx.TxIn { + // Deep copy the old previous outpoint. + oldOutPoint := oldTxIn.PreviousOutpoint + newOutPoint := OutPoint{} + newOutPoint.Hash.SetBytes(oldOutPoint.Hash[:]) + newOutPoint.Index = oldOutPoint.Index + + // Deep copy the old signature script. + var newScript []byte + oldScript := oldTxIn.SignatureScript + oldScriptLen := len(oldScript) + if oldScriptLen > 0 { + newScript = make([]byte, oldScriptLen, oldScriptLen) + copy(newScript, oldScript[:oldScriptLen]) + } + + // Create new txIn with the deep copied data and append it to + // new Tx. + newTxIn := TxIn{ + PreviousOutpoint: newOutPoint, + SignatureScript: newScript, + Sequence: oldTxIn.Sequence, + } + newTx.TxIn = append(newTx.TxIn, &newTxIn) + } + + // Deep copy the old TxOut data. + for _, oldTxOut := range tx.TxOut { + // Deep copy the old PkScript + var newScript []byte + oldScript := oldTxOut.PkScript + oldScriptLen := len(oldScript) + if oldScriptLen > 0 { + newScript = make([]byte, oldScriptLen, oldScriptLen) + copy(newScript, oldScript[:oldScriptLen]) + } + + // Create new txOut with the deep copied data and append it to + // new Tx. + newTxOut := TxOut{ + Value: oldTxOut.Value, + PkScript: newScript, + } + newTx.TxOut = append(newTx.TxOut, &newTxOut) + } + + return &newTx +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { + err := readElement(r, &msg.Version) + if err != nil { + return err + } + + count, err := readVarInt(r, pver) + if err != nil { + return err + } + + for i := uint64(0); i < count; i++ { + ti := TxIn{} + err = readTxIn(r, pver, msg.Version, &ti) + if err != nil { + return err + } + msg.TxIn = append(msg.TxIn, &ti) + } + + count, err = readVarInt(r, pver) + if err != nil { + return err + } + + for i := uint64(0); i < count; i++ { + to := TxOut{} + err = readTxOut(r, pver, msg.Version, &to) + if err != nil { + return err + } + msg.TxOut = append(msg.TxOut, &to) + } + + err = readElement(r, &msg.LockTime) + if err != nil { + return err + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32) error { + err := writeElement(w, msg.Version) + if err != nil { + return err + } + + count := uint64(len(msg.TxIn)) + err = writeVarInt(w, pver, count) + if err != nil { + return err + } + + for _, ti := range msg.TxIn { + err = writeTxIn(w, pver, msg.Version, ti) + if err != nil { + return err + } + } + + count = uint64(len(msg.TxOut)) + err = writeVarInt(w, pver, count) + if err != nil { + return err + } + + for _, to := range msg.TxOut { + err = writeTxOut(w, pver, to) + if err != nil { + return err + } + } + + err = writeElement(w, msg.LockTime) + if err != nil { + return err + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgTx) Command() string { + return cmdTx +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 { + return maxMessagePayload +} + +// NewMsgTx returns a new bitcoin tx message that conforms to the Message +// interface. The return instance has a default version of TxVersion and there +// are no transaction inputs or outputs. Also, the lock time is set to zero +// to indicate the transaction is valid immediately as opposed to some time in +// future. +func NewMsgTx() *MsgTx { + return &MsgTx{Version: TxVersion} +} + +// readOutPoint reads the next sequence of bytes from r as an OutPoint. +func readOutPoint(r io.Reader, pver uint32, version uint32, op *OutPoint) error { + err := readElements(r, &op.Hash, &op.Index) + if err != nil { + return err + } + return nil +} + +// writeOutPoint encodes op to the bitcoin protocol encoding for an OutPoint +// to w. +func writeOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error { + err := writeElements(w, op.Hash, op.Index) + if err != nil { + return err + } + return nil +} + +// readTxIn reads the next sequence of bytes from r as a transaction input +// (TxIn). +func readTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { + op := OutPoint{} + err := readOutPoint(r, pver, version, &op) + if err != nil { + return err + } + ti.PreviousOutpoint = op + + count, err := readVarInt(r, pver) + if err != nil { + return err + } + + b := make([]byte, count) + err = readElement(r, b) + if err != nil { + return err + } + ti.SignatureScript = b + + err = readElement(r, &ti.Sequence) + if err != nil { + return err + } + + return nil +} + +// writeTxIn encodes ti to the bitcoin protocol encoding for a transaction +// input (TxIn) to w. +func writeTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { + err := writeOutPoint(w, pver, version, &ti.PreviousOutpoint) + if err != nil { + return err + } + + slen := uint64(len(ti.SignatureScript)) + err = writeVarInt(w, pver, slen) + if err != nil { + return err + } + + b := []byte(ti.SignatureScript) + _, err = w.Write(b) + if err != nil { + return err + } + + err = writeElement(w, &ti.Sequence) + if err != nil { + return err + } + + return nil +} + +// readTxOut reads the next sequence of bytes from r as a transaction output +// (TxOut). +func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { + err := readElement(r, &to.Value) + if err != nil { + return err + } + + slen, err := readVarInt(r, pver) + if err != nil { + return err + } + + b := make([]byte, slen) + err = readElement(r, b) + if err != nil { + return err + } + to.PkScript = b + + return nil +} + +// writeTxOut encodes to into the bitcoin protocol encoding for a transaction +// output (TxOut) to w. +func writeTxOut(w io.Writer, pver uint32, to *TxOut) error { + err := writeElement(w, to.Value) + if err != nil { + return err + } + + pkLen := uint64(len(to.PkScript)) + err = writeVarInt(w, pver, pkLen) + if err != nil { + return err + } + + err = writeElement(w, to.PkScript) + if err != nil { + return err + } + + return nil +} diff --git a/msgtx_test.go b/msgtx_test.go new file mode 100644 index 00000000..66449bd5 --- /dev/null +++ b/msgtx_test.go @@ -0,0 +1,361 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestTx tests the MsgTx API. +func TestTx(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Block 100000 hash. + hashStr := "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" + hash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Ensure the command is expected value. + wantCmd := "tx" + msg := btcwire.NewMsgTx() + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgAddr: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Num addresses (varInt) + max allowed addresses. + wantPayload := uint32(1024 * 1024 * 32) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure we get the same transaction output point data back out. + prevOutIndex := uint32(1) + prevOut := btcwire.NewOutPoint(hash, prevOutIndex) + if !prevOut.Hash.IsEqual(hash) { + t.Errorf("NewOutPoint: wrong hash - got %v, want %v", + spew.Sprint(&prevOut.Hash), spew.Sprint(hash)) + } + if prevOut.Index != prevOutIndex { + t.Errorf("NewOutPoint: wrong index - got %v, want %v", + prevOut.Index, prevOutIndex) + } + + // Ensure we get the same transaction input back out. + sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62} + txIn := btcwire.NewTxIn(prevOut, sigScript) + if !reflect.DeepEqual(&txIn.PreviousOutpoint, prevOut) { + t.Errorf("NewTxIn: wrong prev outpoint - got %v, want %v", + spew.Sprint(&txIn.PreviousOutpoint), + spew.Sprint(prevOut)) + } + if !bytes.Equal(txIn.SignatureScript, sigScript) { + t.Errorf("NewTxIn: wrong signature script - got %v, want %v", + spew.Sdump(txIn.SignatureScript), + spew.Sdump(sigScript)) + } + + // Ensure we get the same transaction output back out. + txValue := int64(5000000000) + pkScript := []byte{ + 0x41, // OP_DATA_65 + 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, + 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, + 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, + 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, + 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, + 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, + 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, + 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, + 0xa6, // 65-byte signature + 0xac, // OP_CHECKSIG + } + txOut := btcwire.NewTxOut(txValue, pkScript) + if txOut.Value != txValue { + t.Errorf("NewTxOut: wrong pk script - got %v, want %v", + txOut.Value, txValue) + + } + if !bytes.Equal(txOut.PkScript, pkScript) { + t.Errorf("NewTxOut: wrong pk script - got %v, want %v", + spew.Sdump(txOut.PkScript), + spew.Sdump(pkScript)) + } + + // Ensure transaction inputs are added properly. + msg.AddTxIn(txIn) + if !reflect.DeepEqual(msg.TxIn[0], txIn) { + t.Errorf("AddTxIn: wrong transaction input added - got %v, want %v", + spew.Sprint(msg.TxIn[0]), spew.Sprint(txIn)) + } + + // Ensure transaction outputs are added properly. + msg.AddTxOut(txOut) + if !reflect.DeepEqual(msg.TxOut[0], txOut) { + t.Errorf("AddTxIn: wrong transaction output added - got %v, want %v", + spew.Sprint(msg.TxOut[0]), spew.Sprint(txOut)) + } + + // Ensure the copy produced an identical transaction message. + newMsg := msg.Copy() + if !reflect.DeepEqual(newMsg, msg) { + t.Errorf("Copy: mismatched tx messages - got %v, want %v", + spew.Sdump(newMsg), spew.Sdump(msg)) + } + + return +} + +func TestTxSha(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Hash of first transaction from block 113875. + hashStr := "f051e59b5e2503ac626d03aaeac8ab7be2d72ba4b7e97119c5852d70d52dcb86" + wantHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + return + } + + // First transaction from block 113875. + msgTx := btcwire.NewMsgTx() + txIn := btcwire.TxIn{ + PreviousOutpoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash{0x00}, + Index: 0xffffffff, + }, + SignatureScript: []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62}, + Sequence: 0xffffffff, + } + txOut := btcwire.TxOut{ + Value: 5000000000, + PkScript: []byte{ + 0x41, // OP_DATA_65 + 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, + 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, + 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, + 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, + 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, + 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, + 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, + 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, + 0xa6, // 65-byte signature + 0xac, // OP_CHECKSIG + }, + } + msgTx.AddTxIn(&txIn) + msgTx.AddTxOut(&txOut) + msgTx.LockTime = 0 + + // Ensure the hash produced is expected. + txHash, err := msgTx.TxSha(pver) + if err != nil { + t.Errorf("TxSha: %v", err) + } + if !txHash.IsEqual(wantHash) { + t.Errorf("TxSha: wrong hash - got %v, want %v", + spew.Sprint(txHash), spew.Sprint(wantHash)) + } +} + +// TestTxWire tests the MsgTx wire encode and decode for various numbers +// of transaction inputs and outputs and protocol versions. +func TestTxWire(t *testing.T) { + // Previous transaction output point for coinbase to test. + prevOutIndex := uint32(0xffffffff) + prevOut := btcwire.NewOutPoint(&btcwire.ShaHash{}, prevOutIndex) + + // Transaction input to test. + sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62} + txIn := btcwire.NewTxIn(prevOut, sigScript) + txIn.Sequence = 0xffffffff + + // Transaction output to test. + txValue := int64(5000000000) + pkScript := []byte{ + 0x41, // OP_DATA_65 + 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, + 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, + 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, + 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, + 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, + 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, + 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, + 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, + 0xa6, // 65-byte signature + 0xac, // OP_CHECKSIG + } + txOut := btcwire.NewTxOut(txValue, pkScript) + + // Empty tx message. + noTx := btcwire.NewMsgTx() + noTx.Version = 1 + noTxEncoded := []byte{ + 0x01, 0x00, 0x00, 0x00, // Version + 0x00, // Varint for number of input transactions + 0x00, // Varint for number of output transactions + 0x00, 0x00, 0x00, 0x00, // Lock time + } + + multiTx := btcwire.NewMsgTx() + multiTx.Version = 1 + multiTx.AddTxIn(txIn) + multiTx.AddTxOut(txOut) + multiTx.LockTime = 0 + multiTxEncoded := []byte{ + 0x01, 0x00, 0x00, 0x00, // Version + 0x01, // Varint for number of input transactions + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash + 0xff, 0xff, 0xff, 0xff, // Prevous output index + 0x07, // Varint for length of signature script + 0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62, // Signature script + 0xff, 0xff, 0xff, 0xff, // Sequence + 0x01, // Varint for number of output transactions + 0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount + 0x43, // Varint for length of pk script + 0x41, // OP_DATA_65 + 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, + 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, + 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, + 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, + 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, + 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, + 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, + 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, + 0xa6, // 65-byte signature + 0xac, // OP_CHECKSIG + 0x00, 0x00, 0x00, 0x00, // Lock time + } + + tests := []struct { + in *btcwire.MsgTx // Message to encode + out *btcwire.MsgTx // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version with no transactions. + { + noTx, + noTx, + noTxEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version with multiple transactions. + { + multiTx, + multiTx, + multiTxEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version with no transactions. + { + noTx, + noTx, + noTxEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0035Version with multiple transactions. + { + multiTx, + multiTx, + multiTxEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version with no transactions. + { + noTx, + noTx, + noTxEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version BIP0031Version with multiple transactions. + { + multiTx, + multiTx, + multiTxEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion with no transactions. + { + noTx, + noTx, + noTxEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion with multiple transactions. + { + multiTx, + multiTx, + multiTxEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion with no transactions. + { + noTx, + noTx, + noTxEncoded, + btcwire.MultipleAddressVersion, + }, + + // Protocol version MultipleAddressVersion with multiple transactions. + { + multiTx, + multiTx, + multiTxEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgTx + 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 + } + } +} diff --git a/msgverack.go b/msgverack.go new file mode 100644 index 00000000..65ba8afc --- /dev/null +++ b/msgverack.go @@ -0,0 +1,46 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "io" +) + +// MsgVerAck defines a bitcoin verack message which is used for a peer to +// acknowledge a version message (MsgVersion) after it has used the information +// to negotiate parameters. It implements the Message interface. +// +// This message has no payload. +type MsgVerAck struct{} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgVerAck) BtcDecode(r io.Reader, pver uint32) error { + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgVerAck) BtcEncode(w io.Writer, pver uint32) error { + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgVerAck) Command() string { + return cmdVerAck +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgVerAck) MaxPayloadLength(pver uint32) uint32 { + return 0 +} + +// NewMsgVerAck returns a new bitcoin verack message that conforms to the +// Message interface. +func NewMsgVerAck() *MsgVerAck { + return &MsgVerAck{} +} diff --git a/msgverack_test.go b/msgverack_test.go new file mode 100644 index 00000000..a32acd19 --- /dev/null +++ b/msgverack_test.go @@ -0,0 +1,121 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "reflect" + "testing" +) + +// TestVerAck tests the MsgVerAck API. +func TestVerAck(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Ensure the command is expected value. + wantCmd := "verack" + msg := btcwire.NewMsgVerAck() + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgVerAck: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value. + wantPayload := uint32(0) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + return +} + +// TestVerAckWire tests the MsgVerAck wire encode and decode for various +// protocol versions. +func TestVerAckWire(t *testing.T) { + msgVerAck := btcwire.NewMsgVerAck() + msgVerAckEncoded := []byte{} + + tests := []struct { + in *btcwire.MsgVerAck // Message to encode + out *btcwire.MsgVerAck // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version. + { + msgVerAck, + msgVerAck, + msgVerAckEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version. + { + msgVerAck, + msgVerAck, + msgVerAckEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version. + { + msgVerAck, + msgVerAck, + msgVerAckEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion. + { + msgVerAck, + msgVerAck, + msgVerAckEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion. + { + msgVerAck, + msgVerAck, + msgVerAckEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgVerAck + 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 + } + } +} diff --git a/msgversion.go b/msgversion.go new file mode 100644 index 00000000..d9b13e37 --- /dev/null +++ b/msgversion.go @@ -0,0 +1,210 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" + "net" + "time" +) + +// MaxUserAgentLen is the maximum allowed length for the user agent field in a +// version message (MsgVersion). +const MaxUserAgentLen = 2000 + +// MsgVersion implements the Message interface and represents a bitcoin version +// message. It is used for a peer to advertise itself as soon as an outbound +// connection is made. The remote peer then uses this information along with +// its own to negotiate. The remote peer must then respond with a version +// message of its own containing the negotiated values followed by a verack +// message (MsgVerAck). This exchange must take place before any further +// communication is allowed to proceed. +type MsgVersion struct { + // Version of the protocol the node is using. + ProtocolVersion int32 + + // Bitfield which identifies the enabled services. + Services ServiceFlag + + // Time the message was generated. This is encoded as an int64 on the wire. + Timestamp time.Time + + // Address of the remote peer. + AddrYou NetAddress + + // Address of the local peer. + AddrMe NetAddress + + // Unique value associated with message that is used to detect self + // connections. + Nonce uint64 + + // The user agent that generated messsage. This is a encoded as a varString + // on the wire. This has a max length of MaxUserAgentLen. + UserAgent string + + // Last block seen by the generator of the version message. + LastBlock int32 +} + +// HasService returns whether the specified service is supported by the peer +// that generated the message. +func (msg *MsgVersion) HasService(service ServiceFlag) bool { + if msg.Services&service == service { + return true + } + return false +} + +// AddService adds service as a supported service by the peer generating the +// message. +func (msg *MsgVersion) AddService(service ServiceFlag) { + msg.Services |= service +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error { + var sec int64 + err := readElements(r, &msg.ProtocolVersion, &msg.Services, &sec) + if err != nil { + return err + } + msg.Timestamp = time.Unix(sec, 0) + + err = readNetAddress(r, pver, &msg.AddrYou, false) + if err != nil { + return err + } + + err = readNetAddress(r, pver, &msg.AddrMe, false) + if err != nil { + return err + } + + err = readElement(r, &msg.Nonce) + if err != nil { + return err + } + + userAgent, err := readVarString(r, pver) + if err != nil { + return err + } + if len(userAgent) > MaxUserAgentLen { + str := "MsgVersion.BtcDecode: user agent too long [max %v]" + return fmt.Errorf(str, MaxUserAgentLen) + } + msg.UserAgent = userAgent + + err = readElement(r, &msg.LastBlock) + if err != nil { + return err + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32) error { + if len(msg.UserAgent) > MaxUserAgentLen { + str := "MsgVersion.BtcEncode: user agent too long [max %v]" + return fmt.Errorf(str, MaxUserAgentLen) + } + + err := writeElements(w, msg.ProtocolVersion, msg.Services, + msg.Timestamp.Unix()) + if err != nil { + return err + } + + err = writeNetAddress(w, pver, &msg.AddrYou, false) + if err != nil { + return err + } + + err = writeNetAddress(w, pver, &msg.AddrMe, false) + if err != nil { + return err + } + + err = writeElement(w, msg.Nonce) + if err != nil { + return err + } + + err = writeVarString(w, pver, msg.UserAgent) + if err != nil { + return err + } + + err = writeElement(w, msg.LastBlock) + if err != nil { + return err + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgVersion) Command() string { + return cmdVersion +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 { + // XXX: <= 106 different + // XXX: >= 70001 different + + // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + remote + // and local net addresses + nonce 8 bytes + length of user agent (varInt) + + // max allowed useragent length + last block 4 bytes. + return 32 + (maxNetAddressPayload(pver) * 2) + maxVarIntPayload + MaxUserAgentLen +} + +// NewMsgVersion returns a new bitcoin version message that conforms to the +// Message interface using the passed parameters and defaults for the remaining +// fields. +func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64, + userAgent string, lastBlock int32) *MsgVersion { + + // Limit the Timestamp to millisecond precision since the protocol + // doesn't support better. + return &MsgVersion{ + ProtocolVersion: int32(ProtocolVersion), + Services: 0, + Timestamp: time.Unix(time.Now().Unix(), 0), + AddrYou: *you, + AddrMe: *me, + Nonce: nonce, + UserAgent: userAgent, + LastBlock: lastBlock, + } +} + +// NewMsgVersionFromConn is a convenience function that extracts the remote +// and local address from conn and returns a new bitcoin version message that +// conforms to the Message interface. See NewMsgVersion. +func NewMsgVersionFromConn(conn net.Conn, nonce uint64, userAgent string, + lastBlock int32) (*MsgVersion, error) { + + // Don't assume any services until we know otherwise. + lna, err := NewNetAddress(conn.LocalAddr(), 0) + if err != nil { + return nil, err + } + + // Don't assume any services until we know otherwise. + rna, err := NewNetAddress(conn.RemoteAddr(), 0) + if err != nil { + return nil, err + } + + return NewMsgVersion(lna, rna, nonce, userAgent, lastBlock), nil +} diff --git a/msgversion_test.go b/msgversion_test.go new file mode 100644 index 00000000..f9071b84 --- /dev/null +++ b/msgversion_test.go @@ -0,0 +1,277 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "net" + "reflect" + "testing" + "time" +) + +// TestVersion tests the MsgVersion API. +func TestVersion(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Create version message data. + userAgent := "/btcdtest:0.0.1/" + lastBlock := int32(234234) + tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} + me, err := btcwire.NewNetAddress(tcpAddrMe, btcwire.SFNodeNetwork) + if err != nil { + t.Errorf("NewNetAddress: %v", err) + } + tcpAddrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333} + you, err := btcwire.NewNetAddress(tcpAddrYou, btcwire.SFNodeNetwork) + if err != nil { + t.Errorf("NewNetAddress: %v", err) + } + nonce, err := btcwire.RandomUint64() + if err != nil { + t.Errorf("RandomUint64: error generating nonce: %v", err) + } + + // Ensure we get the correct data back out. + msg := btcwire.NewMsgVersion(me, you, nonce, userAgent, lastBlock) + if msg.ProtocolVersion != int32(pver) { + t.Errorf("NewMsgVersion: wrong protocol version - got %v, want %v", + msg.ProtocolVersion, pver) + } + if !reflect.DeepEqual(&msg.AddrMe, me) { + t.Errorf("NewMsgVersion: wrong me address - got %v, want %v", + spew.Sdump(&msg.AddrMe), spew.Sdump(me)) + } + if !reflect.DeepEqual(&msg.AddrYou, you) { + t.Errorf("NewMsgVersion: wrong you address - got %v, want %v", + spew.Sdump(&msg.AddrYou), spew.Sdump(you)) + } + if msg.Nonce != nonce { + t.Errorf("NewMsgVersion: wrong nonce - got %v, want %v", + msg.Nonce, nonce) + } + if msg.UserAgent != userAgent { + t.Errorf("NewMsgVersion: wrong user agent - got %v, want %v", + msg.UserAgent, userAgent) + } + if msg.LastBlock != lastBlock { + t.Errorf("NewMsgVersion: wrong last block - got %v, want %v", + msg.LastBlock, lastBlock) + } + + // Version message should not have any services set by default. + if msg.Services != 0 { + t.Errorf("NewMsgVersion: wrong default services - got %v, want %v", + msg.Services, 0) + + } + if msg.HasService(btcwire.SFNodeNetwork) { + t.Errorf("HasService: SFNodeNetwork service is set") + } + + // Ensure the command is expected value. + wantCmd := "version" + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgVersion: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value. + // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + + // remote and local net addresses + nonce 8 bytes + length of user agent + // (varInt) + max allowed user agent length + last block 4 bytes. + wantPayload := uint32(2101) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Ensure adding the full service node flag works. + msg.AddService(btcwire.SFNodeNetwork) + if msg.Services != btcwire.SFNodeNetwork { + t.Errorf("AddService: wrong services - got %v, want %v", + msg.Services, btcwire.SFNodeNetwork) + } + if !msg.HasService(btcwire.SFNodeNetwork) { + t.Errorf("HasService: SFNodeNetwork service not set") + } + + // Use a fake connection. + conn := &fakeConn{localAddr: tcpAddrMe, remoteAddr: tcpAddrYou} + msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, userAgent, lastBlock) + if err != nil { + t.Errorf("NewMsgVersionFromConn: %v", err) + } + + // Ensure we get the correct connection data back out. + if !msg.AddrMe.IP.Equal(tcpAddrMe.IP) { + t.Errorf("NewMsgVersionFromConn: wrong me ip - got %v, want %v", + msg.AddrMe.IP, tcpAddrMe.IP) + } + if !msg.AddrYou.IP.Equal(tcpAddrYou.IP) { + t.Errorf("NewMsgVersionFromConn: wrong you ip - got %v, want %v", + msg.AddrYou.IP, tcpAddrYou.IP) + } + + // Use a fake connection with local UDP addresses to force a failure. + conn = &fakeConn{ + localAddr: &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333}, + remoteAddr: tcpAddrYou, + } + msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, userAgent, lastBlock) + if err != btcwire.ErrInvalidNetAddr { + t.Errorf("NewMsgVersionFromConn: expected error not received "+ + "- got %v, want %v", err, btcwire.ErrInvalidNetAddr) + } + + // Use a fake connection with remote UDP addresses to force a failure. + conn = &fakeConn{ + localAddr: tcpAddrMe, + remoteAddr: &net.UDPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333}, + } + msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, userAgent, lastBlock) + if err != btcwire.ErrInvalidNetAddr { + t.Errorf("NewMsgVersionFromConn: expected error not received "+ + "- got %v, want %v", err, btcwire.ErrInvalidNetAddr) + } + + return +} + +// TestAlertWire tests the MsgAlert wire encode and decode for various protocol +// versions. +func TestVersionWire(t *testing.T) { + // baseNetAddrYou is used in the various tests as a baseline remote + // NetAddress. + baseNetAddrYou := btcwire.NetAddress{ + Timestamp: time.Time{}, // Zero value -- no timestamp in version + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("192.168.0.1"), + Port: 8333, + } + + // baseNetAddrMe is used in the various tests as a baseline local + // NetAddress. + baseNetAddrMe := btcwire.NetAddress{ + Timestamp: time.Time{}, // Zero value -- no timestamp in version + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("127.0.0.1"), + Port: 8333, + } + + // baseVersion is used in the various tests as a baseline version. + baseVersion := &btcwire.MsgVersion{ + ProtocolVersion: 60002, + Services: btcwire.SFNodeNetwork, + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST) + AddrYou: baseNetAddrYou, + AddrMe: baseNetAddrMe, + Nonce: 123123, // 0x1e0f3 + UserAgent: "/btcdtest:0.0.1/", + LastBlock: 234234, // 0x392fa + } + + baseVersionEncoded := []byte{ + 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp + // AddrYou -- No timestamp for NetAddress in version message + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01, // IP 192.168.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + // AddrMe -- No timestamp for NetAddress in version message + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + 0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Nonce + 0x10, // Varint for user agent length + 0x2f, 0x62, 0x74, 0x63, 0x64, 0x74, 0x65, 0x73, + 0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent + 0xfa, 0x92, 0x03, 0x00, // Last block + } + + tests := []struct { + in *btcwire.MsgVersion // Message to encode + out *btcwire.MsgVersion // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version. + { + baseVersion, + baseVersion, + baseVersionEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version BIP0035Version. + { + baseVersion, + baseVersion, + baseVersionEncoded, + btcwire.BIP0035Version, + }, + + // Protocol version BIP0031Version. + { + baseVersion, + baseVersion, + baseVersionEncoded, + btcwire.BIP0031Version, + }, + + // Protocol version NetAddressTimeVersion. + { + baseVersion, + baseVersion, + baseVersionEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version MultipleAddressVersion. + { + baseVersion, + baseVersion, + baseVersionEncoded, + btcwire.MultipleAddressVersion, + }, + } + + 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.MsgVersion + 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 + } + } +} diff --git a/netaddress.go b/netaddress.go new file mode 100644 index 00000000..b8db7468 --- /dev/null +++ b/netaddress.go @@ -0,0 +1,163 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "encoding/binary" + "errors" + "io" + "net" + "time" +) + +// ErrInvalidNetAddr describes an error that indicates the caller didn't specify +// a TCP address as required. +var ErrInvalidNetAddr = errors.New("provided net.Addr is not a net.TCPAddr") + +// maxNetAddressPayload returns the max payload size for a bitcoin NetAddress +// based on the protocol version. +func maxNetAddressPayload(pver uint32) uint32 { + // Services 8 bytes + ip 16 bytes + port 2 bytes. + plen := uint32(26) + + // NetAddressTimeVersion added a timestamp field. + if pver >= NetAddressTimeVersion { + // Timestamp 4 bytes. + plen += 4 + } + + return plen +} + +// NetAddress defines information about a peer on the network including the time +// it was last seen, the services it supports, its IP address, and port. +type NetAddress struct { + // Last time the address was seen. This is, unfortunately, encoded as a + // uint32 on the wire and therefore is limited to 2106. This field is + // not present in the bitcoin version message (MsgVersion) nor was it + // added until protocol version >= NetAddressTimeVersion. + Timestamp time.Time + + // Bitfield which identifies the services supported by the address. + Services ServiceFlag + + // IP address of the peer. + IP net.IP + + // Port the peer is using. This is encoded in big endian on the wire + // which differs from most everything else. + Port uint16 +} + +// HasService returns whether the specified service is supported by the address. +func (na *NetAddress) HasService(service ServiceFlag) bool { + if na.Services&service == service { + return true + } + return false +} + +// AddService adds service as a supported service by the peer generating the +// message. +func (na *NetAddress) AddService(service ServiceFlag) { + na.Services |= service +} + +// SetAddress is a convenience function to set the IP address and port in one +// call. +func (na *NetAddress) SetAddress(ip net.IP, port uint16) { + na.IP = ip + na.Port = port +} + +// NewNetAddress returns a new NetAddress using the provided TCP address and +// supported services with defaults for the remaining fields. +// +// Note that addr must be a net.TCPAddr. An ErrInvalidNetAddr is returned +// if it is not. +func NewNetAddress(addr net.Addr, services ServiceFlag) (*NetAddress, error) { + tcpAddr, ok := addr.(*net.TCPAddr) + if !ok { + return nil, ErrInvalidNetAddr + } + + na := NetAddress{ + Timestamp: time.Now(), + Services: services, + IP: tcpAddr.IP, + Port: uint16(tcpAddr.Port), + } + return &na, nil +} + +// readNetAddress reads an encoded NetAddress from r depending on the protocol +// version and whether or not the timestamp is included per ts. Some messages +// like version do not include the timestamp. +func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error { + var timestamp time.Time + var services ServiceFlag + var ip [16]byte + var port uint16 + + // NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will + // stop working somewhere around 2106. Also timestamp wasn't added until + // protocol version >= NetAddressTimeVersion + if ts && pver >= NetAddressTimeVersion { + var stamp uint32 + err := readElement(r, &stamp) + if err != nil { + return err + } + timestamp = time.Unix(int64(stamp), 0) + } + + err := readElements(r, &services, &ip) + if err != nil { + return err + } + // Sigh. Bitcoin protocol mixes little and big endian. + err = binary.Read(r, binary.BigEndian, &port) + if err != nil { + return err + } + + na.Timestamp = timestamp + na.Services = services + na.SetAddress(net.IP(ip[:]), port) + return nil +} + +// writeNetAddress serializes a NetAddress to w depending on the protocol +// version and whether or not the timestamp is included per ts. Some messages +// like version do not include the timestamp. +func writeNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error { + // NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will + // stop working somewhere around 2106. Also timestamp wasn't added until + // until protocol version >= NetAddressTimeVersion. + if ts && pver >= NetAddressTimeVersion { + err := writeElement(w, uint32(na.Timestamp.Unix())) + if err != nil { + return err + } + } + + // Ensure to always write 16 bytes even if the ip is nil. + var ip [16]byte + if na.IP != nil { + copy(ip[:], na.IP.To16()) + } + err := writeElements(w, na.Services, ip) + if err != nil { + return err + } + + // Sigh. Bitcoin protocol mixes little and big endian. + err = binary.Write(w, binary.BigEndian, na.Port) + if err != nil { + return err + } + + return nil +} diff --git a/netaddress_test.go b/netaddress_test.go new file mode 100644 index 00000000..692af3c9 --- /dev/null +++ b/netaddress_test.go @@ -0,0 +1,215 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "net" + "reflect" + "testing" + "time" +) + +// TestNetAddress tests the NetAddress API. +func TestNetAddress(t *testing.T) { + ip := net.ParseIP("127.0.0.1") + port := 8333 + + // Test NewNetAddress. + tcpAddr := &net.TCPAddr{ + IP: ip, + Port: port, + } + na, err := btcwire.NewNetAddress(tcpAddr, 0) + if err != nil { + t.Errorf("NewNetAddress: %v", err) + } + + // Ensure we get the same ip, port, and services back out. + if !na.IP.Equal(ip) { + t.Errorf("NetNetAddress: wrong ip - got %v, want %v", na.IP, ip) + } + if na.Port != uint16(port) { + t.Errorf("NetNetAddress: wrong port - got %v, want %v", na.Port, + port) + } + if na.Services != 0 { + t.Errorf("NetNetAddress: wrong services - got %v, want %v", + na.Services, 0) + } + if na.HasService(btcwire.SFNodeNetwork) { + t.Errorf("HasService: SFNodeNetwork service is set") + } + + // Ensure adding the full service node flag works. + na.AddService(btcwire.SFNodeNetwork) + if na.Services != btcwire.SFNodeNetwork { + t.Errorf("AddService: wrong services - got %v, want %v", + na.Services, btcwire.SFNodeNetwork) + } + if !na.HasService(btcwire.SFNodeNetwork) { + t.Errorf("HasService: SFNodeNetwork service not set") + } + + // Ensure max payload is expected value for latest protocol version. + pver := btcwire.ProtocolVersion + wantPayload := uint32(30) + maxPayload := btcwire.TstMaxNetAddressPayload(btcwire.ProtocolVersion) + if maxPayload != wantPayload { + t.Errorf("maxNetAddressPayload: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Protocol version before NetAddressTimeVersion when timestamp was + // added. Ensure max payload is expected value for it. + pver = btcwire.NetAddressTimeVersion - 1 + wantPayload = 26 + maxPayload = btcwire.TstMaxNetAddressPayload(pver) + if maxPayload != wantPayload { + t.Errorf("maxNetAddressPayload: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Check for expected failure on wrong address type. + udpAddr := &net.UDPAddr{} + _, err = btcwire.NewNetAddress(udpAddr, 0) + if err != btcwire.ErrInvalidNetAddr { + t.Errorf("NewNetAddress: expected error not received - "+ + "got %v, want %v", err, btcwire.ErrInvalidNetAddr) + } +} + +// TestNetAddressWire tests the NetAddress wire encode and decode for various +// protocol versions and timestamp flag combinations. +func TestNetAddressWire(t *testing.T) { + // baseNetAddr is used in the various tests as a baseline NetAddress. + baseNetAddr := btcwire.NetAddress{ + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("127.0.0.1"), + Port: 8333, + } + + // baseNetAddrNoTS is baseNetAddr with a zero value for the timestamp. + baseNetAddrNoTS := baseNetAddr + baseNetAddrNoTS.Timestamp = time.Time{} + + // baseNetAddrEncoded is the wire encoded bytes of baseNetAddr. + baseNetAddrEncoded := []byte{ + 0x29, 0xab, 0x5f, 0x49, // Timestamp + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + } + + // baseNetAddrNoTSEncoded is the wire encoded bytes of baseNetAddrNoTS. + baseNetAddrNoTSEncoded := []byte{ + // No timestamp + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + } + + tests := []struct { + in btcwire.NetAddress // NetAddress to encode + out btcwire.NetAddress // Expected decoded NetAddress + ts bool // Include timestamp? + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version without ts flag. + { + baseNetAddr, + baseNetAddrNoTS, + false, + baseNetAddrNoTSEncoded, + btcwire.ProtocolVersion, + }, + + // Latest protocol version with ts flag. + { + baseNetAddr, + baseNetAddr, + true, + baseNetAddrEncoded, + btcwire.ProtocolVersion, + }, + + // Protocol version NetAddressTimeVersion without ts flag. + { + baseNetAddr, + baseNetAddrNoTS, + false, + baseNetAddrNoTSEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion with ts flag. + { + baseNetAddr, + baseNetAddr, + true, + baseNetAddrEncoded, + btcwire.NetAddressTimeVersion, + }, + + // Protocol version NetAddressTimeVersion-1 without ts flag. + { + baseNetAddr, + baseNetAddrNoTS, + false, + baseNetAddrNoTSEncoded, + btcwire.NetAddressTimeVersion - 1, + }, + + // Protocol version NetAddressTimeVersion-1 with timestamp. + // Even though the timestamp flag is set, this shouldn't have a + // timestamp since it is a protocol version before it was + // added. + { + baseNetAddr, + baseNetAddrNoTS, + true, + baseNetAddrNoTSEncoded, + btcwire.NetAddressTimeVersion - 1, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Encode to wire format. + var buf bytes.Buffer + err := btcwire.TstWriteNetAddress(&buf, test.pver, &test.in, test.ts) + if err != nil { + t.Errorf("writeNetAddress #%d error %v", i, err) + continue + } + if !bytes.Equal(buf.Bytes(), test.buf) { + t.Errorf("writeNetAddress #%d\n got: %s want: %s", i, + spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) + continue + } + + // Decode the message from wire format. + var na btcwire.NetAddress + rbuf := bytes.NewBuffer(test.buf) + err = btcwire.TstReadNetAddress(rbuf, test.pver, &na, test.ts) + if err != nil { + t.Errorf("readNetAddress #%d error %v", i, err) + continue + } + if !reflect.DeepEqual(na, test.out) { + t.Errorf("readNetAddress #%d\n got: %s want: %s", i, + spew.Sdump(na), spew.Sdump(test.out)) + continue + } + } +} diff --git a/protocol.go b/protocol.go new file mode 100644 index 00000000..7fe9f601 --- /dev/null +++ b/protocol.go @@ -0,0 +1,83 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "strconv" + "strings" +) + +const ( + MainPort = "8333" + TestNetPort = "18333" + ProtocolVersion uint32 = 60002 + TxVersion = 1 + + // MultipleAddressVersion is the protocol version which added multiple + // addresses per message (pver >= MultipleAddressVersion). + MultipleAddressVersion uint32 = 209 + + // NetAddressTimeVersion is the protocol version which added the + // timestamp field (pver >= NetAddressTimeVersion). + NetAddressTimeVersion uint32 = 31402 + + // BIP0031Version is the protocol version AFTER which a pong message + // and nonce field in ping were added (pver > BIP0031Version). + BIP0031Version uint32 = 60000 + + // BIP0035Version is the protocol version which added the mempool + // message (pver >= BIP0035Version). + BIP0035Version uint32 = 60002 +) + +// ServiceFlag identifies services supported by a bitcoin peer. +type ServiceFlag uint64 + +const ( + SFNodeNetwork ServiceFlag = 1 << iota +) + +// Map of service flags back to their constant names for pretty printing. +var sfStrings = map[ServiceFlag]string{ + SFNodeNetwork: "SFNodeNetwork", +} + +// String returns the ServiceFlag in human-readable form. +func (f ServiceFlag) String() string { + // No flags are set. + if f == 0 { + return "0x0" + } + + // Add individual bit flags. + s := "" + for flag, name := range sfStrings { + if f&flag == flag { + s += name + "|" + f -= flag + } + } + + // Add any remaining flags which aren't accounted for as hex. + s = strings.TrimRight(s, "|") + if f != 0 { + s += "|0x" + strconv.FormatUint(uint64(f), 16) + } + s = strings.TrimLeft(s, "|") + return s +} + +// BitcoinNet represents which bitcoin network a message belongs to. +type BitcoinNet uint32 + +// Constants used to indicate the message bitcoin network. They can also be +// used to seek to the next message when a stream's state is unknown, but +// this package does not provide that functionality since it's generally a +// better idea to simply disconnect clients that are misbehaving over TCP. +const ( + MainNet BitcoinNet = 0xd9b4bef9 + TestNet BitcoinNet = 0xdab5bffa + TestNet3 BitcoinNet = 0x0709110b +) diff --git a/protocol_test.go b/protocol_test.go new file mode 100644 index 00000000..b95515c2 --- /dev/null +++ b/protocol_test.go @@ -0,0 +1,32 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "github.com/conformal/btcwire" + "testing" +) + +// TestServiceFlagStringer tests the stringized output for service flag types. +func TestServiceFlagStringer(t *testing.T) { + tests := []struct { + in btcwire.ServiceFlag + want string + }{ + {0, "0x0"}, + {btcwire.SFNodeNetwork, "SFNodeNetwork"}, + {0xffffffff, "SFNodeNetwork|0xfffffffe"}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + result := test.in.String() + if result != test.want { + t.Errorf("String #%d\n got: %s want: %s", i, result, + test.want) + continue + } + } +} diff --git a/shahash.go b/shahash.go new file mode 100644 index 00000000..2e21439c --- /dev/null +++ b/shahash.go @@ -0,0 +1,106 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "bytes" + "encoding/hex" + "fmt" +) + +// Size of array used to store sha hashes. See ShaHash. +const HashSize = 32 +const MaxHashStringSize = HashSize * 2 + +var ErrHashStrSize = fmt.Errorf("Max hash length is %v chars", MaxHashStringSize) + +// ShaHash is used in several of the bitcoin messages and common structures. It +// typically represents the double sha256 of data. +type ShaHash [HashSize]byte + +// String returns the ShaHash in the standard bitcoin big-endian form. +func (hash *ShaHash) String() string { + hashstr := "" + for i := range hash { + hashstr += fmt.Sprintf("%02x", hash[HashSize-1-i]) + } + + return hashstr +} + +// Bytes returns the bytes which represent the hash as a byte slice. +func (hash *ShaHash) Bytes() []byte { + newHash := make([]byte, HashSize) + copy(newHash, hash[:]) + + return newHash +} + +// SetBytes sets the bytes which represent the hash. An error is returned if +// the number of bytes passed in is not HashSize. +func (hash *ShaHash) SetBytes(newHash []byte) error { + nhlen := len(newHash) + if nhlen != HashSize { + return fmt.Errorf("ShaHash: invalid sha length of %v, want %v", + nhlen, HashSize) + } + copy(hash[:], newHash[0:HashSize]) + + return nil +} + +// IsEqual returns true if target is the same as hash. +func (hash *ShaHash) IsEqual(target *ShaHash) bool { + return bytes.Equal(hash[:], target[:]) +} + +// NewShaHash returns a new ShaHash from a byte slice. An error is returned if +// the number of bytes passed in is not HashSize. +func NewShaHash(newHash []byte) (*ShaHash, error) { + var sh ShaHash + err := sh.SetBytes(newHash) + if err != nil { + return nil, err + } + return &sh, err +} + +// NewShaHashFromStr converts a hash string in the standard bitcoin big-endian +// form to a ShaHash (which is little-endian). +func NewShaHashFromStr(hash string) (*ShaHash, error) { + // Return error is hash string is too long. + if len(hash) > MaxHashStringSize { + return nil, ErrHashStrSize + } + + // Hex decoder expects the hash to be a multiple of two. + if len(hash)%2 != 0 { + hash = "0" + hash + } + + // Convert string hash to bytes. + buf, err := hex.DecodeString(hash) + if err != nil { + return nil, err + } + + // The string was given in big-endian, so reverse the bytes to little + // endian. + blen := len(buf) + for i := 0; i < blen/2; i++ { + buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i] + } + + // Make sure the byte slice is the right length by appending zeros to + // pad it out. + pbuf := buf + if HashSize-blen > 0 { + pbuf = make([]byte, HashSize) + copy(pbuf, buf) + } + + // Create the sha hash using the byte slice and return it. + return NewShaHash(pbuf) +} diff --git a/shahash_test.go b/shahash_test.go new file mode 100644 index 00000000..ea143507 --- /dev/null +++ b/shahash_test.go @@ -0,0 +1,167 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "encoding/hex" + "github.com/conformal/btcwire" + "testing" +) + +// TestShaHash tests the ShaHash API. +func TestShaHash(t *testing.T) { + + // Hash of block 234439. + blockHashStr := "14a0810ac680a3eb3f82edc878cea25ec41d6b790744e5daeef" + blockHash, err := btcwire.NewShaHashFromStr(blockHashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Hash of block 234440 as byte slice. + buf := []byte{ + 0x79, 0xa6, 0x1a, 0xdb, 0xc6, 0xe5, 0xa2, 0xe1, + 0x39, 0xd2, 0x71, 0x3a, 0x54, 0x6e, 0xc7, 0xc8, + 0x75, 0x63, 0x2e, 0x75, 0xf1, 0xdf, 0x9c, 0x3f, + 0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + } + + hash, err := btcwire.NewShaHash(buf) + if err != nil { + t.Errorf("NewShaHash: unexpected error %v", err) + } + + // Ensure proper size. + if len(hash) != btcwire.HashSize { + t.Errorf("NewShaHash: hash length mismatch - got: %v, want: %v", + len(hash), btcwire.HashSize) + } + + // Ensure contents match. + if !bytes.Equal(hash[:], buf) { + t.Errorf("NewShaHash: hash contents mismatch - got: %v, want: %v", + hash[:], buf) + } + + // Ensure contents of hash of block 234440 don't match 234439. + if hash.IsEqual(blockHash) { + t.Errorf("IsEqual: hash contents should not match - got: %v, want: %v", + hash, blockHash) + } + + // Set hash from byte slice and ensure contents match. + err = hash.SetBytes(blockHash.Bytes()) + if err != nil { + t.Errorf("SetBytes: %v", err) + } + if !hash.IsEqual(blockHash) { + t.Errorf("IsEqual: hash contents mismatch - got: %v, want: %v", + hash, blockHash) + } + + // Invalid size for SetBytes. + err = hash.SetBytes([]byte{0x00}) + if err == nil { + t.Errorf("SetBytes: failed to received expected err - got: nil") + } +} + +// TestShaHashString tests the stringized output for sha hashes. +func TestShaHashString(t *testing.T) { + // Block 100000 hash. + wantStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" + hash := &btcwire.ShaHash{ + 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39, + 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2, + 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa, + 0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + } + + hashStr := hash.String() + if hashStr != wantStr { + t.Errorf("String: wrong hash string - got %v, want %v", + hashStr, wantStr) + } +} + +// TestNewShaHashFromStr executes tests against the NewShaHashFromStr function. +func TestNewShaHashFromStr(t *testing.T) { + tests := []struct { + in string + want btcwire.ShaHash + err error + }{ + // Genesis hash. + { + "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + btcwire.GenesisHash, + nil, + }, + + // Genesis hash with stripped leading zeros. + { + "19d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", + btcwire.GenesisHash, + nil, + }, + + // Single digit hash. + { + "1", + btcwire.ShaHash{ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + nil, + }, + + // Block 203707 with stripped leading zeros. + { + "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc", + btcwire.ShaHash{ + 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, + 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, + 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, + 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + nil, + }, + + // Hash string that is too long. + { + "01234567890123456789012345678901234567890123456789012345678912345", + btcwire.ShaHash{}, + btcwire.ErrHashStrSize, + }, + + // Hash string that is contains non-hex chars. + { + "abcdefg", + btcwire.ShaHash{}, + hex.InvalidByteError('g'), + }, + } + + unexpectedErrStr := "NewShaHashFromStr #%d failed to detect expected error - got: %v want: %v" + unexpectedResultStr := "NewShaHashFromStr #%d got: %v want: %v" + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + result, err := btcwire.NewShaHashFromStr(test.in) + if err != test.err { + t.Errorf(unexpectedErrStr, i, err, test.err) + continue + } else if err != nil { + // Got expected error. Move on to the next test. + continue + } + if !test.want.IsEqual(result) { + t.Errorf(unexpectedResultStr, i, result, &test.want) + continue + } + } +} diff --git a/test_coverage.txt b/test_coverage.txt new file mode 100644 index 00000000..9e8a7a68 --- /dev/null +++ b/test_coverage.txt @@ -0,0 +1,152 @@ + +github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) +github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) +github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) +github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) +github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcDecode 100.00% (1/1) +github.com/conformal/btcwire/common.go readElement 100.00% (1/1) +github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) +github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) +github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) +github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) +github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) +github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) +github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) +github.com/conformal/btcwire/msgping.go NewMsgPing 100.00% (1/1) +github.com/conformal/btcwire/msgpong.go MsgPong.Command 100.00% (1/1) +github.com/conformal/btcwire/msgpong.go NewMsgPong 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go NewOutPoint 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go NewTxIn 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go NewTxOut 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go MsgTx.AddTxIn 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go MsgTx.AddTxOut 100.00% (1/1) +github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go MsgTx.Command 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go MsgTx.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go NewMsgTx 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.AddService 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) +github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) +github.com/conformal/btcwire/message.go makeEmptyMessage 94.44% (17/18) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) +github.com/conformal/btcwire/netaddress.go readNetAddress 85.00% (17/20) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 80.00% (8/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 80.00% (8/10) +github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 80.00% (4/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 80.00% (4/5) +github.com/conformal/btcwire/common.go readElements 80.00% (4/5) +github.com/conformal/btcwire/netaddress.go writeNetAddress 78.57% (11/14) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 77.78% (7/9) +github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 76.00% (19/25) +github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 75.00% (6/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) +github.com/conformal/btcwire/invvect.go readInvVect 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) +github.com/conformal/btcwire/invvect.go writeInvVect 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 73.91% (17/23) +github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) +github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) +github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) +github.com/conformal/btcwire/message.go readMessageHeader 70.00% (7/10) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 69.23% (9/13) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 69.23% (9/13) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 69.23% (9/13) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 69.23% (9/13) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) +github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) +github.com/conformal/btcwire/message.go ReadMessage 57.14% (4/7) +github.com/conformal/btcwire/message.go readMessage 53.12% (17/32) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) +github.com/conformal/btcwire/message.go discardInput 0.00% (0/10) +github.com/conformal/btcwire --------------------------------- 78.43% (731/932) + From ff7d582c66340b1872efc8882e8eeabd893ff1d1 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 8 May 2013 22:59:45 -0500 Subject: [PATCH 003/219] Remove a few unused variables and constants. --- msgheaders_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/msgheaders_test.go b/msgheaders_test.go index 67ac3c89..c84ab3a1 100644 --- a/msgheaders_test.go +++ b/msgheaders_test.go @@ -12,12 +12,6 @@ import ( "testing" ) -var dumpmessage bool = false -var checkverbose = true - -const time1 uint32 = 1363020888 -const time2 uint32 = 1363021079 - // TestHeaders tests the MsgHeaders API. func TestHeaders(t *testing.T) { pver := uint32(60002) From e473fd6eb8b63eb26c64ab86218d3cab028ecdb4 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 00:01:29 -0500 Subject: [PATCH 004/219] Add message tests for MsgAlert and MsgMemPool. --- message.go | 6 ++++++ message_test.go | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/message.go b/message.go index dea9668b..9482f95c 100644 --- a/message.go +++ b/message.go @@ -97,6 +97,12 @@ func makeEmptyMessage(command string) (Message, error) { case cmdHeaders: msg = &MsgHeaders{} + case cmdAlert: + msg = &MsgAlert{} + + case cmdMemPool: + msg = &MsgMemPool{} + default: return nil, fmt.Errorf("unhandled command [%s]", command) } diff --git a/message_test.go b/message_test.go index 27756e9e..d3f0b8c0 100644 --- a/message_test.go +++ b/message_test.go @@ -48,6 +48,8 @@ func TestMessage(t *testing.T) { msgPong := btcwire.NewMsgPong(123123) msgGetHeaders := btcwire.NewMsgGetHeaders() msgHeaders := btcwire.NewMsgHeaders() + msgAlert := btcwire.NewMsgAlert("payload", "signature") + msgMemPool := btcwire.NewMsgMemPool() tests := []struct { in btcwire.Message // Value to encode @@ -69,6 +71,8 @@ func TestMessage(t *testing.T) { {msgPong, msgPong, pver, btcwire.MainNet}, {msgGetHeaders, msgGetHeaders, pver, btcwire.MainNet}, {msgHeaders, msgHeaders, pver, btcwire.MainNet}, + {msgAlert, msgAlert, pver, btcwire.MainNet}, + {msgMemPool, msgMemPool, pver, btcwire.MainNet}, } t.Logf("Running %d tests", len(tests)) From bf5c0b58d8e21a3800cdcaed404533f64a6b7ea9 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 00:02:07 -0500 Subject: [PATCH 005/219] Fix a few comment typos. --- blockheader.go | 2 +- common_test.go | 2 +- msgblock.go | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/blockheader.go b/blockheader.go index e2e93228..b8456a42 100644 --- a/blockheader.go +++ b/blockheader.go @@ -14,7 +14,7 @@ import ( const BlockVersion uint32 = 2 // Version 4 bytes + Timestamp 4 bytes + Bits 4 bytes + Nonce 4 bytes + -// TxnCount (varInt) + PrevBlock and MarkleRoot hashes. +// TxnCount (varInt) + PrevBlock and MerkleRoot hashes. const maxBlockHeaderPayload = 16 + maxVarIntPayload + (HashSize * 2) // BlockHeader defines information about a block and is used in the bitcoin diff --git a/common_test.go b/common_test.go index ab6e64de..40556b4d 100644 --- a/common_test.go +++ b/common_test.go @@ -22,7 +22,7 @@ type fakeRandReader struct { } // Read returns the fake reader error and the lesser of the fake reader value -// and the length p. +// and the length of p. func (r *fakeRandReader) Read(p []byte) (int, error) { n := r.n if n > len(p) { diff --git a/msgblock.go b/msgblock.go index cdf15eb2..c01929ab 100644 --- a/msgblock.go +++ b/msgblock.go @@ -104,7 +104,6 @@ func (msg *MsgBlock) BtcDecodeTxLoc(r *bytes.Buffer, pver uint32) ([]TxLoc, erro // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. // This is part of the Message interface implementation. func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32) error { - // XXX: Max transactions? msg.Header.TxnCount = uint64(len(msg.Transactions)) err := writeBlockHeader(w, pver, &msg.Header) From 5e416389b1559751627c65e7c2b3ef9b054ce7be Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 10:41:21 -0500 Subject: [PATCH 006/219] Add negative tests for MsgPing. This commit add tests the error paths when encoding and decoding MsgPing. --- msgping_test.go | 48 ++++++++++++++++++++++++++++++++ test_coverage.txt | 70 +++++++++++++++++++++++------------------------ 2 files changed, 83 insertions(+), 35 deletions(-) diff --git a/msgping_test.go b/msgping_test.go index 8f0d9d18..4b0800f4 100644 --- a/msgping_test.go +++ b/msgping_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" ) @@ -192,3 +193,50 @@ func TestPingWire(t *testing.T) { } } } + +// TestPingWireErrors performs negative tests against wire encode and decode +// of MsgPing to confirm error paths work correctly. +func TestPingWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + + tests := []struct { + in *btcwire.MsgPing // 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. + { + &btcwire.MsgPing{Nonce: 123123}, // 0x1e0f3 + []byte{0xf3, 0xe0, 0x01, 0x00}, + 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 := test.in.BtcEncode(w, test.pver) + 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.MsgPing + r := newFixedReader(test.max, test.buf) + err = msg.BtcDecode(r, test.pver) + if err != test.readErr { + t.Errorf("BtcDecode #%d wrong error got: %v, want :%v", + i, err, test.readErr) + continue + } + } +} diff --git a/test_coverage.txt b/test_coverage.txt index 9e8a7a68..3f776d33 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,39 +1,41 @@ -github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) +github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcDecode 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) @@ -64,8 +66,12 @@ github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) -github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) @@ -81,12 +87,6 @@ github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewMsgTx 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) @@ -98,18 +98,18 @@ github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) -github.com/conformal/btcwire/message.go makeEmptyMessage 94.44% (17/18) +github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) +github.com/conformal/btcwire/message.go makeEmptyMessage 95.00% (19/20) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/netaddress.go readNetAddress 85.00% (17/20) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 80.00% (8/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 80.00% (8/10) -github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 80.00% (4/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 80.00% (4/5) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 80.00% (8/10) github.com/conformal/btcwire/common.go readElements 80.00% (4/5) +github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) github.com/conformal/btcwire/netaddress.go writeNetAddress 78.57% (11/14) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 77.78% (7/9) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) @@ -148,5 +148,5 @@ github.com/conformal/btcwire/message.go ReadMessage 57.14% (4/7) github.com/conformal/btcwire/message.go readMessage 53.12% (17/32) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) github.com/conformal/btcwire/message.go discardInput 0.00% (0/10) -github.com/conformal/btcwire --------------------------------- 78.43% (731/932) +github.com/conformal/btcwire --------------------------------- 78.69% (735/934) From 3cd90355dff06171a1a261f03078c2512f21dd98 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 11:36:29 -0500 Subject: [PATCH 007/219] Correct error output string colon placement. --- common_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common_test.go b/common_test.go index 40556b4d..5235a5c8 100644 --- a/common_test.go +++ b/common_test.go @@ -128,7 +128,7 @@ func TestVarIntWireErrors(t *testing.T) { w := newFixedWriter(test.max) err := btcwire.TstWriteVarInt(w, test.pver, test.in) if err != test.writeErr { - t.Errorf("writeVarInt #%d wrong error got: %v, want :%v", + t.Errorf("writeVarInt #%d wrong error got: %v, want: %v", i, err, test.writeErr) continue } @@ -137,7 +137,7 @@ func TestVarIntWireErrors(t *testing.T) { r := newFixedReader(test.max, test.buf) _, err = btcwire.TstReadVarInt(r, test.pver) if err != test.readErr { - t.Errorf("readVarInt #%d wrong error got: %v, want :%v", + t.Errorf("readVarInt #%d wrong error got: %v, want: %v", i, err, test.readErr) continue } @@ -227,7 +227,7 @@ func TestVarStringWireErrors(t *testing.T) { w := newFixedWriter(test.max) err := btcwire.TstWriteVarString(w, test.pver, test.in) if err != test.writeErr { - t.Errorf("writeVarString #%d wrong error got: %v, want :%v", + t.Errorf("writeVarString #%d wrong error got: %v, want: %v", i, err, test.writeErr) continue } @@ -236,7 +236,7 @@ func TestVarStringWireErrors(t *testing.T) { r := newFixedReader(test.max, test.buf) _, err = btcwire.TstReadVarString(r, test.pver) if err != test.readErr { - t.Errorf("readVarString #%d wrong error got: %v, want :%v", + t.Errorf("readVarString #%d wrong error got: %v, want: %v", i, err, test.readErr) continue } From c369c0c16e1c6fe21dcd7557e9d18ec68ce1d3f4 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 13:00:00 -0500 Subject: [PATCH 008/219] Correct discardInput comment for buffer size. This was pointed out by kaptin on IRC. --- message.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message.go b/message.go index 9482f95c..5d186d3b 100644 --- a/message.go +++ b/message.go @@ -145,7 +145,7 @@ func readMessageHeader(r io.Reader) (*messageHeader, error) { // prevent rogue nodes from causing massive memory allocation through forging // header length. func discardInput(r io.Reader, n uint32) { - maxSize := uint32(10240) // 2k at a time + maxSize := uint32(10 * 1024) // 10k at a time numReads := n / maxSize bytesRemaining := n % maxSize if n > 0 { From cdc17121b8df7a6eefed798a2c71a35e8580bc1f Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 13:19:09 -0500 Subject: [PATCH 009/219] Display correct import path for gocov. This was pointed out by kaptin on IRC. --- cov_report.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cov_report.sh b/cov_report.sh index ef5cf816..5cc6f201 100644 --- a/cov_report.sh +++ b/cov_report.sh @@ -11,7 +11,7 @@ type gocov >/dev/null 2>&1 if [ $? -ne 0 ]; then echo >&2 "This script requires the gocov tool." echo >&2 "You may obtain it with the following command:" - echo >&2 "go get github.com/awx/gocov/gocov" + echo >&2 "go get github.com/axw/gocov/gocov" exit 1 fi gocov test | gocov report From 4fc0089f63c464ea73291027d03f3c68ac554ea6 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 9 May 2013 12:26:23 -0600 Subject: [PATCH 010/219] Fix typo: s/MsgPong/MsgPing/ --- msgping.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgping.go b/msgping.go index 15f6580d..25a7f521 100644 --- a/msgping.go +++ b/msgping.go @@ -8,7 +8,7 @@ import ( "io" ) -// MsgPong implements the Message interface and represents a bitcoin ping +// MsgPing implements the Message interface and represents a bitcoin ping // message. // // For versions BIP0031Version and earlier, it is used primarily to confirm From 4c160efc9699bda6172d5772c90c1664cf4b93d2 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 13:57:44 -0500 Subject: [PATCH 011/219] Fix a minor typo in the package overview doco. --- doc.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc.go b/doc.go index b7086aed..273691d6 100644 --- a/doc.go +++ b/doc.go @@ -80,8 +80,8 @@ negotiated. Bitcoin Network The bitcoin network is a magic number which is used to identify the start of a -and which bitcoin network the message applies to. This package provides the -following constants: +message and which bitcoin network the message applies to. This package provides +the following constants: btcwire.MainNet btcwire.TestNet From 970b9c129d932a24be2691d993ab2c655c72dfc7 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 15:23:31 -0500 Subject: [PATCH 012/219] Remove dead error check. The io.ReadFull function always returns an error if the full payload can't be read, so there is no reason to further check if the payload length matches after a successful read. --- message.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/message.go b/message.go index 5d186d3b..8e107f1b 100644 --- a/message.go +++ b/message.go @@ -117,7 +117,7 @@ type messageHeader struct { checksum [4]byte // 4 bytes } -// readMessageHeader reads a bitcoin messager header from r. +// readMessageHeader reads a bitcoin message header from r. func readMessageHeader(r io.Reader) (*messageHeader, error) { var command [commandSize]byte @@ -195,15 +195,10 @@ func readMessage(r io.Reader, pver uint32, hdr *messageHeader) (Message, []byte, // Read payload. payload := make([]byte, hdr.length) - n, err := io.ReadFull(r, payload) + _, err = io.ReadFull(r, payload) if err != nil { return nil, nil, err } - if uint32(n) != hdr.length { - str := "readMessage: failed to read payload - Read %v " + - "bytes, but payload size is %v bytes." - return nil, nil, fmt.Errorf(str, n, hdr.length) - } // Test checksum. checksum := DoubleSha256(payload)[0:4] From d829f688b984b6bc6ddb2b1c17eb7e8c9be5172d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 18:12:11 -0500 Subject: [PATCH 013/219] Fix comment typo. --- shahash.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shahash.go b/shahash.go index 2e21439c..b698fc20 100644 --- a/shahash.go +++ b/shahash.go @@ -70,7 +70,7 @@ func NewShaHash(newHash []byte) (*ShaHash, error) { // NewShaHashFromStr converts a hash string in the standard bitcoin big-endian // form to a ShaHash (which is little-endian). func NewShaHashFromStr(hash string) (*ShaHash, error) { - // Return error is hash string is too long. + // Return error if hash string is too long. if len(hash) > MaxHashStringSize { return nil, ErrHashStrSize } From 6286a39378e91ec8c92aeb44cb89985e548be640 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 20:15:27 -0500 Subject: [PATCH 014/219] Combine readMessage with ReadMessage. These functions used to be split into multiple files, but since the code was reorganized there is no longer any reason to split them. --- internal_test.go | 6 --- message.go | 111 +++++++++++++++++++++------------------------- test_coverage.txt | 99 +++++++++++++++++++++-------------------- 3 files changed, 101 insertions(+), 115 deletions(-) diff --git a/internal_test.go b/internal_test.go index d57754a5..94b03f7b 100644 --- a/internal_test.go +++ b/internal_test.go @@ -87,12 +87,6 @@ func TstWriteBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { return writeBlockHeader(w, pver, bh) } -// TstReadMessage makes the internal readMessage function available to -// the test package. -func TstReadMessage(r io.Reader, pver uint32, hdr *messageHeader) (Message, []byte, error) { - return readMessage(r, pver, hdr) -} - // TstReadMessageHeader makes the internal readMessageHeader function available // to the test package. func TstReadMessageHeader(r io.Reader) (*messageHeader, error) { diff --git a/message.go b/message.go index 8e107f1b..90afc844 100644 --- a/message.go +++ b/message.go @@ -160,64 +160,6 @@ func discardInput(r io.Reader, n uint32) { } } -// readMessage reads the next bitcoin message from r for the provided protocol -// version and message header. -func readMessage(r io.Reader, pver uint32, hdr *messageHeader) (Message, []byte, error) { - if hdr == nil { - return nil, nil, fmt.Errorf("readMessage: nil header") - } - - command := hdr.command - if !utf8.ValidString(command) { - discardInput(r, hdr.length) - str := "readMessage: invalid command %v" - return nil, nil, fmt.Errorf(str, []byte(command)) - } - - // Create struct of appropriate message type based on the command. - msg, err := makeEmptyMessage(command) - if err != nil { - discardInput(r, hdr.length) - return nil, nil, fmt.Errorf("readMessage: %v", err) - } - - // Check for maximum length based on the message type as a malicious client - // could otherwise create a well-formed header and set the length to max - // numbers in order to exhaust the machine's memory. - mpl := msg.MaxPayloadLength(pver) - if hdr.length > mpl { - discardInput(r, hdr.length) - str := "ReadMessage: payload exceeds max length - Header " + - "indicates %v bytes, but max payload size for messages of type " + - "[%v] is %v." - return nil, nil, fmt.Errorf(str, hdr.length, command, mpl) - } - - // Read payload. - payload := make([]byte, hdr.length) - _, err = io.ReadFull(r, payload) - if err != nil { - return nil, nil, err - } - - // Test checksum. - checksum := DoubleSha256(payload)[0:4] - if !bytes.Equal(checksum[:], hdr.checksum[:]) { - str := "readMessage: payload checksum failed - Header " + - "indicates %v, but actual checksum is %v." - return nil, nil, fmt.Errorf(str, hdr.checksum, checksum) - } - - // Unmarshal message. - pr := bytes.NewBuffer(payload) - err = msg.BtcDecode(pr, pver) - if err != nil { - return nil, nil, err - } - - return msg, payload, nil -} - // WriteMessage writes a bitcoin Message to w including the necessary header // information. func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) error { @@ -271,7 +213,8 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro return nil } -// ReadMessage reads, validates, and parses the next bitcoin Message from r. +// ReadMessage reads, validates, and parses the next bitcoin Message from r for +// the provided protocol version and bitcoin network. func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, error) { hdr, err := readMessageHeader(r) if err != nil { @@ -283,5 +226,53 @@ func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, return nil, nil, fmt.Errorf(str, hdr.magic) } - return readMessage(r, pver, hdr) + command := hdr.command + if !utf8.ValidString(command) { + discardInput(r, hdr.length) + str := "readMessage: invalid command %v" + return nil, nil, fmt.Errorf(str, []byte(command)) + } + + // Create struct of appropriate message type based on the command. + msg, err := makeEmptyMessage(command) + if err != nil { + discardInput(r, hdr.length) + return nil, nil, fmt.Errorf("readMessage: %v", err) + } + + // Check for maximum length based on the message type as a malicious client + // could otherwise create a well-formed header and set the length to max + // numbers in order to exhaust the machine's memory. + mpl := msg.MaxPayloadLength(pver) + if hdr.length > mpl { + discardInput(r, hdr.length) + str := "ReadMessage: payload exceeds max length - Header " + + "indicates %v bytes, but max payload size for messages of type " + + "[%v] is %v." + return nil, nil, fmt.Errorf(str, hdr.length, command, mpl) + } + + // Read payload. + payload := make([]byte, hdr.length) + _, err = io.ReadFull(r, payload) + if err != nil { + return nil, nil, err + } + + // Test checksum. + checksum := DoubleSha256(payload)[0:4] + if !bytes.Equal(checksum[:], hdr.checksum[:]) { + str := "readMessage: payload checksum failed - Header " + + "indicates %v, but actual checksum is %v." + return nil, nil, fmt.Errorf(str, hdr.checksum, checksum) + } + + // Unmarshal message. + pr := bytes.NewBuffer(payload) + err = msg.BtcDecode(pr, pver) + if err != nil { + return nil, nil, err + } + + return msg, payload, nil } diff --git a/test_coverage.txt b/test_coverage.txt index 3f776d33..6d62daef 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -5,50 +5,47 @@ github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) -github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) -github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcDecode 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) +github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) -github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) @@ -59,19 +56,25 @@ github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1 github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) -github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) @@ -83,28 +86,25 @@ github.com/conformal/btcwire/msgtx.go NewTxIn 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewTxOut 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxIn 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxOut 100.00% (1/1) -github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewMsgTx 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.AddService 100.00% (1/1) -github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) -github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) -github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) +github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcDecode 100.00% (1/1) +github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) +github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) +github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.AddService 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) +github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) +github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/message.go makeEmptyMessage 95.00% (19/20) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/netaddress.go readNetAddress 85.00% (17/20) github.com/conformal/btcwire/blockheader.go readBlockHeader 80.00% (8/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 80.00% (8/10) @@ -115,14 +115,14 @@ github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 77.78% (7/9) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 76.00% (19/25) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) -github.com/conformal/btcwire/invvect.go readInvVect 75.00% (3/4) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 75.00% (6/8) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) -github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) +github.com/conformal/btcwire/invvect.go readInvVect 75.00% (3/4) github.com/conformal/btcwire/invvect.go writeInvVect 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 73.91% (17/23) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) @@ -137,16 +137,17 @@ github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 66.67% (8/12) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) -github.com/conformal/btcwire/message.go ReadMessage 57.14% (4/7) -github.com/conformal/btcwire/message.go readMessage 53.12% (17/32) +github.com/conformal/btcwire/message.go ReadMessage 54.55% (18/33) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) github.com/conformal/btcwire/message.go discardInput 0.00% (0/10) -github.com/conformal/btcwire --------------------------------- 78.69% (735/934) +github.com/conformal/btcwire/error.go MessageError.Error 0.00% (0/1) +github.com/conformal/btcwire/error.go messageError 0.00% (0/1) +github.com/conformal/btcwire --------------------------------- 78.71% (732/930) From ec6ebb391610a84c3fedc23d57e63acc827d9e68 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 20:56:03 -0500 Subject: [PATCH 015/219] Add initial implementation of MessageError type. This commit adds a new MessageError type that is intended to allow the caller to differentiate between general io errors and and errors that resulted from malformed messages. --- doc.go | 6 +++--- error.go | 34 ++++++++++++++++++++++++++++++++ message.go | 58 ++++++++++++++++++++++++++++++------------------------ 3 files changed, 69 insertions(+), 29 deletions(-) create mode 100644 error.go diff --git a/doc.go b/doc.go index 273691d6..84175720 100644 --- a/doc.go +++ b/doc.go @@ -103,7 +103,6 @@ switch or type assertion. An example of a type switch follows: case *btcwire.MsgBlock: // The message is a pointer to a MsgBlock struct. fmt.Printf("Number of tx in block: %v", msg.Header.TxnCount) - } Reading Messages @@ -144,8 +143,9 @@ Errors Most errors returned by this package are either the raw errors provided by underlying calls to read/write from streams, or raw strings that describe the error. See the documentation of each function for any exceptions. NOTE: -This will change soon as the package should return errors that can be -programatically tested. +This is currently undergoing change to return errors of type MessageError for +issues which are not io related so the caller can differentiate between +general io errors and malformed messages. Bitcoin Improvement Proposals diff --git a/error.go b/error.go new file mode 100644 index 00000000..da617138 --- /dev/null +++ b/error.go @@ -0,0 +1,34 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" +) + +// MessageError describes an issue with a message. +// An example of some potential issues are messages from the wrong bitcoin +// network, invalid commands, mismatched checksums, and exceeding max payloads. +// +// This provides a mechanism for the caller to type assert the error to +// differentiate between general io errors such as io.EOF and issues that +// resulted from malformed messages. +type MessageError struct { + Func string // Function name + Description string // Human readable description of the issue +} + +// Error satisfies the error interface and prints human-readable errors. +func (e *MessageError) Error() string { + if e.Func != "" { + return fmt.Sprintf("%v: %v", e.Func, e.Description) + } + return e.Description +} + +// messageError creates an error for the given function and description. +func messageError(f string, desc string) *MessageError { + return &MessageError{Func: f, Description: desc} +} diff --git a/message.go b/message.go index 90afc844..00c3b185 100644 --- a/message.go +++ b/message.go @@ -130,13 +130,6 @@ func readMessageHeader(r io.Reader) (*messageHeader, error) { // Strip trailing zeros from command string. hdr.command = string(bytes.TrimRight(command[:], string(0))) - // Enforce maximum message payload. - if hdr.length > maxMessagePayload { - str := "readMessageHeader: message payload is too large - " + - "Header indicates %d bytes, but max message payload is %d bytes." - return nil, fmt.Errorf(str, hdr.length, maxMessagePayload) - } - return &hdr, nil } @@ -182,9 +175,10 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro // Enforce maximum message payload. if lenp > maxMessagePayload { - str := "WriteMessage: message payload is too large - " + - "Encoded %d bytes, but maximum message payload is %d bytes." - return fmt.Errorf(str, lenp, maxMessagePayload) + str := fmt.Sprintf("message payload is too large - encoded "+ + "%d bytes, but maximum message payload is %d bytes", + lenp, maxMessagePayload) + return messageError("WriteMessage", str) } // Create header for the message. @@ -206,9 +200,9 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro return err } if n != lenp { - str := "WriteMessage: failed to write payload. " + - "Wrote %v bytes, but payload size is %v bytes." - return fmt.Errorf(str, n, lenp) + str := fmt.Sprintf("failed to write payload - wrote %v bytes, "+ + "payload size is %v bytes", n, lenp) + return messageError("WriteMessage", str) } return nil } @@ -221,23 +215,34 @@ func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, return nil, nil, err } - if hdr.magic != btcnet { - str := "ReadMessage: message from other network [%v]" - return nil, nil, fmt.Errorf(str, hdr.magic) + // Enforce maximum message payload. + if hdr.length > maxMessagePayload { + str := fmt.Sprintf("message payload is too large - header "+ + "indicates %d bytes, but max message payload is %d "+ + "bytes.", hdr.length, maxMessagePayload) + return nil, nil, messageError("ReadMessage", str) + } + // Check for messages from the wrong bitcoin network. + if hdr.magic != btcnet { + str := fmt.Sprintf("message from other network [%v]", hdr.magic) + return nil, nil, messageError("ReadMessage", str) + } + + // Check for malformed commands. command := hdr.command if !utf8.ValidString(command) { discardInput(r, hdr.length) - str := "readMessage: invalid command %v" - return nil, nil, fmt.Errorf(str, []byte(command)) + str := fmt.Sprintf("invalid command %v", []byte(command)) + return nil, nil, messageError("ReadMessage", str) } // Create struct of appropriate message type based on the command. msg, err := makeEmptyMessage(command) if err != nil { discardInput(r, hdr.length) - return nil, nil, fmt.Errorf("readMessage: %v", err) + return nil, nil, messageError("ReadMessage", err.Error()) } // Check for maximum length based on the message type as a malicious client @@ -246,10 +251,10 @@ func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, mpl := msg.MaxPayloadLength(pver) if hdr.length > mpl { discardInput(r, hdr.length) - str := "ReadMessage: payload exceeds max length - Header " + - "indicates %v bytes, but max payload size for messages of type " + - "[%v] is %v." - return nil, nil, fmt.Errorf(str, hdr.length, command, mpl) + str := fmt.Sprintf("payload exceeds max length - header "+ + "indicates %v bytes, but max payload size for "+ + "messages of type [%v] is %v.", hdr.length, command, mpl) + return nil, nil, messageError("ReadMessage", str) } // Read payload. @@ -262,9 +267,10 @@ func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, // Test checksum. checksum := DoubleSha256(payload)[0:4] if !bytes.Equal(checksum[:], hdr.checksum[:]) { - str := "readMessage: payload checksum failed - Header " + - "indicates %v, but actual checksum is %v." - return nil, nil, fmt.Errorf(str, hdr.checksum, checksum) + str := fmt.Sprintf("payload checksum failed - header "+ + "indicates %v, but actual checksum is %v.", + hdr.checksum, checksum) + return nil, nil, messageError("ReadMessage", str) } // Unmarshal message. From aa4086a1b12fa9fc7a3b5a0e2769a7713602ebeb Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 21:13:37 -0500 Subject: [PATCH 016/219] Update test coverage report. --- test_coverage.txt | 84 +++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/test_coverage.txt b/test_coverage.txt index 6d62daef..2163ef9b 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,46 +1,52 @@ +github.com/conformal/btcwire/message.go ReadMessage 100.00% (36/36) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) +github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) +github.com/conformal/btcwire/error.go messageError 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) @@ -100,54 +106,48 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00 github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/message.go makeEmptyMessage 95.00% (19/20) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) +github.com/conformal/btcwire/netaddress.go readNetAddress 90.00% (18/20) +github.com/conformal/btcwire/message.go discardInput 90.00% (9/10) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) -github.com/conformal/btcwire/netaddress.go readNetAddress 85.00% (17/20) -github.com/conformal/btcwire/blockheader.go readBlockHeader 80.00% (8/10) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 80.00% (8/10) -github.com/conformal/btcwire/common.go readElements 80.00% (4/5) +github.com/conformal/btcwire/blockheader.go readBlockHeader 80.00% (8/10) github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) github.com/conformal/btcwire/netaddress.go writeNetAddress 78.57% (11/14) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 77.78% (7/9) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 76.92% (10/13) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 76.00% (19/25) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 75.00% (6/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 75.00% (6/8) -github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) -github.com/conformal/btcwire/invvect.go readInvVect 75.00% (3/4) -github.com/conformal/btcwire/invvect.go writeInvVect 75.00% (3/4) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) +github.com/conformal/btcwire/invvect.go writeInvVect 75.00% (3/4) +github.com/conformal/btcwire/invvect.go readInvVect 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 73.91% (17/23) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) -github.com/conformal/btcwire/message.go readMessageHeader 70.00% (7/10) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 69.23% (9/13) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 69.23% (9/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 69.23% (9/13) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) -github.com/conformal/btcwire/message.go ReadMessage 54.55% (18/33) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire/message.go discardInput 0.00% (0/10) -github.com/conformal/btcwire/error.go MessageError.Error 0.00% (0/1) -github.com/conformal/btcwire/error.go messageError 0.00% (0/1) -github.com/conformal/btcwire --------------------------------- 78.71% (732/930) +github.com/conformal/btcwire --------------------------------- 82.30% (767/932) From 149d77ad3fc92a96f6991354c0514ca72aaca5c0 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 21:22:35 -0500 Subject: [PATCH 017/219] Add negative tests for ReadMessage. This commit adds tests for the error paths when reading the initial message header and message payload from the wire. --- internal_test.go | 4 + message_test.go | 190 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) diff --git a/internal_test.go b/internal_test.go index 94b03f7b..a9619b50 100644 --- a/internal_test.go +++ b/internal_test.go @@ -15,6 +15,10 @@ import ( "io" ) +// MaxMessagePayload makes the internal maxMessagePayload constant available to +// the test package. +const MaxMessagePayload uint32 = maxMessagePayload + // TstRandomUint64 makes the internal randomUint64 function available to the // test package. func TstRandomUint64(r io.Reader) (uint64, error) { diff --git a/message_test.go b/message_test.go index d3f0b8c0..fa7b6a85 100644 --- a/message_test.go +++ b/message_test.go @@ -6,14 +6,32 @@ package btcwire_test import ( "bytes" + "encoding/binary" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "net" "reflect" "testing" "time" ) +// makeHeader is a convenience function to make a message header in the form of +// a byte slice. It is used to force errors when reading messages. +func makeHeader(btcnet btcwire.BitcoinNet, command string, + payloadLen uint32, checksum uint32) []byte { + + // The length of a bitcoin message header is 24 bytes. + // 4 byte magic number of the bitcoin network + 12 byte command + 4 byte + // payload length + 4 byte checksum. + buf := make([]byte, 24) + binary.LittleEndian.PutUint32(buf, uint32(btcnet)) + copy(buf[4:], []byte(command)) + binary.LittleEndian.PutUint32(buf[16:], payloadLen) + binary.LittleEndian.PutUint32(buf[20:], checksum) + return buf +} + // TestMessage tests the Read/WriteMessage API. func TestMessage(t *testing.T) { pver := btcwire.ProtocolVersion @@ -100,3 +118,175 @@ func TestMessage(t *testing.T) { } } } + +// TestReadMessageWireErrors performs negative tests against wire decoding into +// concrete messages to confirm error paths work correctly. +func TestReadMessageWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + btcnet := btcwire.MainNet + + // Ensure message errors are as expected with no function specified. + wantErr := "something bad happened" + testErr := btcwire.MessageError{Description: wantErr} + if testErr.Error() != wantErr { + t.Errorf("MessageError: wrong error - got %v, want %v", + testErr.Error(), wantErr) + } + + // Ensure message errors are as expected with a function specified. + wantFunc := "foo" + testErr = btcwire.MessageError{Func: wantFunc, Description: wantErr} + if testErr.Error() != wantFunc+": "+wantErr { + t.Errorf("MessageError: wrong error - got %v, want %v", + testErr.Error(), wantErr) + } + + // Wire encoded bytes for main and testnet3 networks magic identifiers. + testNet3Bytes := makeHeader(btcwire.TestNet3, "", 0, 0) + + // Wire encoded bytes for a message that exceeds max overall message + // length. + mpl := btcwire.MaxMessagePayload + exceedMaxPayloadBytes := makeHeader(btcnet, "getaddr", mpl+1, 0) + + // Wire encoded bytes for a command which is invalid utf-8. + badCommandBytes := makeHeader(btcnet, "bogus", 0, 0) + badCommandBytes[4] = 0x81 + + // Wire encoded bytes for a command which is valid, but not supported. + unsupportedCommandBytes := makeHeader(btcnet, "bogus", 0, 0) + + // Wire encoded bytes for a message which exceeds the max payload for + // a specific message type. + exceedTypePayloadBytes := makeHeader(btcnet, "getaddr", 1, 0) + + // Wire encoded bytes for a message which does not deliver the full + // payload according to the header length. + shortPayloadBytes := makeHeader(btcnet, "version", 115, 0) + + // Wire encoded bytes for a message with a bad checksum. + badChecksumBytes := makeHeader(btcnet, "version", 2, 0xbeef) + badChecksumBytes = append(badChecksumBytes, []byte{0x0, 0x0}...) + + // Wire encoded bytes for a message which has a valid header, but is + // the wrong format. An addr starts with a varint of the number of + // contained in the message. Claim there is two, but don't provide + // them. At the same time, forge the header fields so the message is + // otherwise accurate. + badMessageBytes := makeHeader(btcnet, "addr", 1, 0xeaadc31c) + badMessageBytes = append(badMessageBytes, 0x2) + + tests := []struct { + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + btcnet btcwire.BitcoinNet // Bitcoin network for wire encoding + max int // Max size of fixed buffer to induce errors + readErr error // Expected read error + }{ + // Latest protocol version with intentional read errors. + + // Short header. + { + []byte{}, + pver, + btcnet, + 0, + io.EOF, + }, + + // Wrong network. Want MainNet, but giving TestNet3. + { + testNet3Bytes, + pver, + btcnet, + len(testNet3Bytes), + &btcwire.MessageError{}, + }, + + // Exceed max overall message payload length. + { + exceedMaxPayloadBytes, + pver, + btcnet, + len(exceedMaxPayloadBytes), + &btcwire.MessageError{}, + }, + + // Invalid UTF-8 command. + { + badCommandBytes, + pver, + btcnet, + len(badCommandBytes), + &btcwire.MessageError{}, + }, + + // Valid, but unsupported command. + { + unsupportedCommandBytes, + pver, + btcnet, + len(unsupportedCommandBytes), + &btcwire.MessageError{}, + }, + + // Exceed max allowed payload for a message of a specific type. + { + exceedTypePayloadBytes, + pver, + btcnet, + len(exceedTypePayloadBytes), + &btcwire.MessageError{}, + }, + + // Message with a payload shorter than the header indicates. + { + shortPayloadBytes, + pver, + btcnet, + len(shortPayloadBytes), + io.EOF, + }, + + // Message with a bad checksum. + { + badChecksumBytes, + pver, + btcnet, + len(badChecksumBytes), + &btcwire.MessageError{}, + }, + + // Message with a valid header, but wrong format. + { + badMessageBytes, + pver, + btcnet, + len(badMessageBytes), + io.EOF, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Decode from wire format. + r := newFixedReader(test.max, test.buf) + _, _, err := btcwire.ReadMessage(r, test.pver, test.btcnet) + if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { + t.Errorf("ReadMessage #%d wrong error got: %v <%T>, "+ + "want: %T", i, err, 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("ReadMessage #%d wrong error got: %v <%T>, "+ + "want: %v <%T>", i, err, err, + test.readErr, test.readErr) + continue + } + } + } +} From e7abb08b6bfbc309ff59b39575d16b752e1d75ed Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 21:24:47 -0500 Subject: [PATCH 018/219] Fix a comment typo. --- common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.go b/common.go index 28c8f325..649d142d 100644 --- a/common.go +++ b/common.go @@ -151,7 +151,7 @@ func writeVarString(w io.Writer, pver uint32, str string) error { // randomUint64 returns a cryptographically random uint64 value. This // unexported version takes a reader primarily to ensure the error paths -// can be properly by passing a fake reader in the tests. +// can be properly tested by passing a fake reader in the tests. func randomUint64(r io.Reader) (uint64, error) { b := make([]byte, 8) n, err := r.Read(b) From f182e4f3238a9acdcc5f9639fa961fa9544b87d8 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 21:25:19 -0500 Subject: [PATCH 019/219] Correct error output colon string placement. --- msgping_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/msgping_test.go b/msgping_test.go index 4b0800f4..4a6b6819 100644 --- a/msgping_test.go +++ b/msgping_test.go @@ -224,7 +224,7 @@ func TestPingWireErrors(t *testing.T) { w := newFixedWriter(test.max) err := test.in.BtcEncode(w, test.pver) if err != test.writeErr { - t.Errorf("BtcEncode #%d wrong error got: %v, want :%v", + t.Errorf("BtcEncode #%d wrong error got: %v, want: %v", i, err, test.writeErr) continue } @@ -234,7 +234,7 @@ func TestPingWireErrors(t *testing.T) { r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if err != test.readErr { - t.Errorf("BtcDecode #%d wrong error got: %v, want :%v", + t.Errorf("BtcDecode #%d wrong error got: %v, want: %v", i, err, test.readErr) continue } From 2aee754448efbd583905aff39dedc5e4d1f1a323 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 22:25:21 -0500 Subject: [PATCH 020/219] Add test for discarding invalid large messages. --- message.go | 1 + message_test.go | 13 ++++++++++ test_coverage.txt | 64 +++++++++++++++++++++++------------------------ 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/message.go b/message.go index 00c3b185..13d0d77a 100644 --- a/message.go +++ b/message.go @@ -226,6 +226,7 @@ func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, // Check for messages from the wrong bitcoin network. if hdr.magic != btcnet { + discardInput(r, hdr.length) str := fmt.Sprintf("message from other network [%v]", hdr.magic) return nil, nil, messageError("ReadMessage", str) } diff --git a/message_test.go b/message_test.go index fa7b6a85..ea0cd182 100644 --- a/message_test.go +++ b/message_test.go @@ -176,6 +176,10 @@ func TestReadMessageWireErrors(t *testing.T) { badMessageBytes := makeHeader(btcnet, "addr", 1, 0xeaadc31c) badMessageBytes = append(badMessageBytes, 0x2) + // Wire encoded bytes for a message which the header claims has 15k + // bytes of data to discard. + discardBytes := makeHeader(btcnet, "bogus", 15*1024, 0) + tests := []struct { buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding @@ -265,6 +269,15 @@ func TestReadMessageWireErrors(t *testing.T) { len(badMessageBytes), io.EOF, }, + + // 15k bytes of data to discard. + { + discardBytes, + pver, + btcnet, + len(discardBytes), + &btcwire.MessageError{}, + }, } t.Logf("Running %d tests", len(tests)) diff --git a/test_coverage.txt b/test_coverage.txt index 2163ef9b..92a62c0b 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,46 +1,47 @@ -github.com/conformal/btcwire/message.go ReadMessage 100.00% (36/36) -github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) +github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) +github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) @@ -107,13 +108,12 @@ github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/netaddress.go readNetAddress 90.00% (18/20) -github.com/conformal/btcwire/message.go discardInput 90.00% (9/10) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 80.00% (8/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 80.00% (8/10) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 80.00% (8/10) github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) github.com/conformal/btcwire/netaddress.go writeNetAddress 78.57% (11/14) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 77.78% (7/9) @@ -121,33 +121,33 @@ github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 76.92% (10/13) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 76.00% (19/25) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/invvect.go writeInvVect 75.00% (3/4) github.com/conformal/btcwire/invvect.go readInvVect 75.00% (3/4) -github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 73.91% (17/23) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 69.23% (9/13) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 82.30% (767/932) +github.com/conformal/btcwire --------------------------------- 82.42% (769/933) From 4aea957b19571ed30f104d1b5abc7acd76b14af5 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 23:01:09 -0500 Subject: [PATCH 021/219] Add negative tests for NetAddress. This commit adds tests for the error paths when encoding and decoding NetAddress with and without the timestamp field. --- netaddress_test.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 62 ++++++++++++++++++------------------ 2 files changed, 109 insertions(+), 31 deletions(-) diff --git a/netaddress_test.go b/netaddress_test.go index 692af3c9..aed67503 100644 --- a/netaddress_test.go +++ b/netaddress_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "net" "reflect" "testing" @@ -213,3 +214,80 @@ func TestNetAddressWire(t *testing.T) { } } } + +// TestNetAddressWireErrors performs negative tests against wire encode and +// decode NetAddress to confirm error paths work correctly. +func TestNetAddressWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + pverNAT := btcwire.NetAddressTimeVersion - 1 + + // baseNetAddr is used in the various tests as a baseline NetAddress. + baseNetAddr := btcwire.NetAddress{ + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("127.0.0.1"), + Port: 8333, + } + + tests := []struct { + in *btcwire.NetAddress // Value to encode + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + ts bool // Include timestamp flag + max int // Max size of fixed buffer to induce errors + writeErr error // Expected write error + readErr error // Expected read error + }{ + // Latest protocol version with timestamp and intentional + // read/write errors. + // Force errors on timestamp. + {&baseNetAddr, []byte{}, pver, true, 0, io.ErrShortWrite, io.EOF}, + // Force errors on services. + {&baseNetAddr, []byte{}, pver, true, 4, io.ErrShortWrite, io.EOF}, + // Force errors on ip. + {&baseNetAddr, []byte{}, pver, true, 12, io.ErrShortWrite, io.EOF}, + // Force errors on port. + {&baseNetAddr, []byte{}, pver, true, 28, io.ErrShortWrite, io.EOF}, + + // Latest protocol version with no timestamp and intentional + // read/write errors. + // Force errors on services. + {&baseNetAddr, []byte{}, pver, false, 0, io.ErrShortWrite, io.EOF}, + // Force errors on ip. + {&baseNetAddr, []byte{}, pver, false, 8, io.ErrShortWrite, io.EOF}, + // Force errors on port. + {&baseNetAddr, []byte{}, pver, false, 24, io.ErrShortWrite, io.EOF}, + + // Protocol version before NetAddressTimeVersion with timestamp + // flag set (should not have timestamp due to old protocol + // version) and intentional read/write errors. + // Force errors on services. + {&baseNetAddr, []byte{}, pverNAT, true, 0, io.ErrShortWrite, io.EOF}, + // Force errors on ip. + {&baseNetAddr, []byte{}, pverNAT, true, 8, io.ErrShortWrite, io.EOF}, + // Force errors on port. + {&baseNetAddr, []byte{}, pverNAT, true, 24, 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 := btcwire.TstWriteNetAddress(w, test.pver, test.in, test.ts) + if err != test.writeErr { + t.Errorf("writeNetAddress #%d wrong error got: %v, want: %v", + i, err, test.writeErr) + continue + } + + // Decode from wire format. + var na btcwire.NetAddress + r := newFixedReader(test.max, test.buf) + err = btcwire.TstReadNetAddress(r, test.pver, &na, test.ts) + if err != test.readErr { + t.Errorf("readNetAddress #%d wrong error got: %v, want: %v", + i, err, test.readErr) + continue + } + } +} diff --git a/test_coverage.txt b/test_coverage.txt index 92a62c0b..486bffd0 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,45 +1,47 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) -github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) +github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) +github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) +github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) @@ -107,47 +109,45 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00 github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/netaddress.go readNetAddress 90.00% (18/20) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) -github.com/conformal/btcwire/blockheader.go readBlockHeader 80.00% (8/10) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 80.00% (8/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 80.00% (8/10) github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) -github.com/conformal/btcwire/netaddress.go writeNetAddress 78.57% (11/14) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 77.78% (7/9) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 76.92% (10/13) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 76.00% (19/25) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) -github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/invvect.go writeInvVect 75.00% (3/4) github.com/conformal/btcwire/invvect.go readInvVect 75.00% (3/4) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 73.91% (17/23) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 69.23% (9/13) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 82.42% (769/933) +github.com/conformal/btcwire --------------------------------- 82.96% (774/933) From 135552cd728c4c49d7e32f6c78201b91448c5a13 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 9 May 2013 23:47:12 -0500 Subject: [PATCH 022/219] Improve MsgBlock tests. This commit corrects the tests so that the main API functions are tested against the latest protocol version, but the TxSha and BlockSha functions are run against the specific protocol version used to encode the test data. This will help future proof the tests against protocol changes. --- msgblock_test.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index 5693153e..5a55bdff 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -15,7 +15,7 @@ import ( // TestBlock tests the MsgBlock API. func TestBlock(t *testing.T) { - pver := uint32(60002) + pver := btcwire.ProtocolVersion // Block 1 header. prevHash := &blockOne.Header.PrevBlock @@ -67,8 +67,13 @@ func TestBlock(t *testing.T) { return } +// TestBlockTxShas tests the ability to generate a slice of all transaction +// hashes from a block accurately. func TestBlockTxShas(t *testing.T) { - pver := btcwire.ProtocolVersion + // Use protocol version 60002 specifically here instead of the latest + // because the test data is using bytes encoded with that protocol + // version. + pver := uint32(60002) // Block 1, transaction 1 hash. hashStr := "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098" @@ -89,8 +94,12 @@ func TestBlockTxShas(t *testing.T) { } } +// TestBlockSha tests the ability to generate the hash of a block accurately. func TestBlockSha(t *testing.T) { - pver := btcwire.ProtocolVersion + // Use protocol version 60002 specifically here instead of the latest + // because the test data is using bytes encoded with that protocol + // version. + pver := uint32(60002) // Block 1 hash. hashStr := "839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048" @@ -250,6 +259,7 @@ var blockOne btcwire.MsgBlock = btcwire.MsgBlock{ }, } +// Bytes encoded with protocol version 60002. var blockOneBytes = []byte{ 0x01, 0x00, 0x00, 0x00, // Version 1 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, From e026f5048635129e92e3ae7cba0e7e389a9c7b55 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 00:36:49 -0500 Subject: [PATCH 023/219] Improve MsgGetBlocks tests. This commit corrects the MsgGetBlocks tests so that the protocol version in the multiLocators data matches the wire encoded test data. This will help future proof the tests against protocol changes. Also, while here modify the casing of the local vars to be consistent. --- msggetblocks_test.go | 75 ++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/msggetblocks_test.go b/msggetblocks_test.go index 8dc83b80..4c8c972f 100644 --- a/msggetblocks_test.go +++ b/msggetblocks_test.go @@ -108,9 +108,9 @@ func TestGetBlocksWire(t *testing.T) { } // MsgGetBlocks message with no block locators or stop hash. - NoLocators := btcwire.NewMsgGetBlocks(&btcwire.ShaHash{}) - NoLocators.ProtocolVersion = pver - NoLocatorsEncoded := []byte{ + noLocators := btcwire.NewMsgGetBlocks(&btcwire.ShaHash{}) + noLocators.ProtocolVersion = pver + noLocatorsEncoded := []byte{ 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 0x00, // Varint for number of block locator hashes 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -120,10 +120,11 @@ func TestGetBlocksWire(t *testing.T) { } // MsgGetBlocks message with multiple block locators and a stop hash. - MultiLocators := btcwire.NewMsgGetBlocks(hashStop) - MultiLocators.AddBlockLocatorHash(hashLocator2) - MultiLocators.AddBlockLocatorHash(hashLocator) - MultiLocatorsEncoded := []byte{ + multiLocators := btcwire.NewMsgGetBlocks(hashStop) + multiLocators.AddBlockLocatorHash(hashLocator2) + multiLocators.AddBlockLocatorHash(hashLocator) + multiLocators.ProtocolVersion = pver + multiLocatorsEncoded := []byte{ 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 0x02, // Varint for number of block locator hashes 0xe0, 0xde, 0x06, 0x44, 0x68, 0x13, 0x2c, 0x63, @@ -148,81 +149,81 @@ func TestGetBlocksWire(t *testing.T) { }{ // Latest protocol version with no block locators. { - NoLocators, - NoLocators, - NoLocatorsEncoded, + noLocators, + noLocators, + noLocatorsEncoded, btcwire.ProtocolVersion, }, // Latest protocol version with multiple block locators. { - MultiLocators, - MultiLocators, - MultiLocatorsEncoded, + multiLocators, + multiLocators, + multiLocatorsEncoded, btcwire.ProtocolVersion, }, // Protocol version BIP0035Version with no block locators. { - NoLocators, - NoLocators, - NoLocatorsEncoded, + noLocators, + noLocators, + noLocatorsEncoded, btcwire.BIP0035Version, }, // Protocol version BIP0035Version with multiple block locators. { - MultiLocators, - MultiLocators, - MultiLocatorsEncoded, + multiLocators, + multiLocators, + multiLocatorsEncoded, btcwire.BIP0035Version, }, // Protocol version BIP0031Version with no block locators. { - NoLocators, - NoLocators, - NoLocatorsEncoded, + noLocators, + noLocators, + noLocatorsEncoded, btcwire.BIP0031Version, }, // Protocol version BIP0031Versionwith multiple block locators. { - MultiLocators, - MultiLocators, - MultiLocatorsEncoded, + multiLocators, + multiLocators, + multiLocatorsEncoded, btcwire.BIP0031Version, }, // Protocol version NetAddressTimeVersion with no block locators. { - NoLocators, - NoLocators, - NoLocatorsEncoded, + noLocators, + noLocators, + noLocatorsEncoded, btcwire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion multiple block locators. { - MultiLocators, - MultiLocators, - MultiLocatorsEncoded, + multiLocators, + multiLocators, + multiLocatorsEncoded, btcwire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion with no block locators. { - NoLocators, - NoLocators, - NoLocatorsEncoded, + noLocators, + noLocators, + noLocatorsEncoded, btcwire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion multiple block locators. { - MultiLocators, - MultiLocators, - MultiLocatorsEncoded, + multiLocators, + multiLocators, + multiLocatorsEncoded, btcwire.MultipleAddressVersion, }, } From 862374115fc700dba6399658c0e20185e127cf71 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 00:54:56 -0500 Subject: [PATCH 024/219] Bump the protocol version to 70001. As documented in the package overview, this package does not yet support BIP0037 which was the reason for this bump. --- protocol.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/protocol.go b/protocol.go index 7fe9f601..284a6692 100644 --- a/protocol.go +++ b/protocol.go @@ -12,7 +12,7 @@ import ( const ( MainPort = "8333" TestNetPort = "18333" - ProtocolVersion uint32 = 60002 + ProtocolVersion uint32 = 70001 TxVersion = 1 // MultipleAddressVersion is the protocol version which added multiple @@ -30,6 +30,11 @@ const ( // BIP0035Version is the protocol version which added the mempool // message (pver >= BIP0035Version). BIP0035Version uint32 = 60002 + + // BIP0037Version is the protocol version which added new connection + // bloom filtering related messages and extended the version message + // with a relay flag (pver >= BIP0037Version). + BIP0037Version uint32 = 70001 ) // ServiceFlag identifies services supported by a bitcoin peer. From 953a236e2a2951ea6603da9dc4afabcc32abd38e Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 09:12:46 -0500 Subject: [PATCH 025/219] Add negative tests for MsgBlock. This commit adds tests for the error paths when encoded and decoding MsgBlock. --- msgblock_test.go | 59 +++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 64 +++++++++++++++++++++++------------------------ 2 files changed, 91 insertions(+), 32 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index 5a55bdff..ca9f8eac 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" "time" @@ -200,6 +201,64 @@ func TestBlockWire(t *testing.T) { } } +// TestBlockWireErrors performs negative tests against wire encode and decode +// of MsgBlock to confirm error paths work correctly. +func TestBlockWireErrors(t *testing.T) { + // Use protocol version 60002 specifically here instead of the latest + // because the test data is using bytes encoded with that protocol + // version. + pver := uint32(60002) + + tests := []struct { + in *btcwire.MsgBlock // 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 error in version. + {&blockOne, []byte{}, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in prev block hash. + {&blockOne, []byte{}, pver, 4, io.ErrShortWrite, io.EOF}, + // Force error in merkle root. + {&blockOne, []byte{}, pver, 36, io.ErrShortWrite, io.EOF}, + // Force error in timestamp. + {&blockOne, []byte{}, pver, 68, io.ErrShortWrite, io.EOF}, + // Force error in difficulty bits. + {&blockOne, []byte{}, pver, 72, io.ErrShortWrite, io.EOF}, + // Force error in header nonce. + {&blockOne, []byte{}, pver, 76, io.ErrShortWrite, io.EOF}, + // Force error in transaction count. + {&blockOne, []byte{}, pver, 80, io.ErrShortWrite, io.EOF}, + // Force error in transactions. + {&blockOne, blockOneBytes, pver, 81, 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 := test.in.BtcEncode(w, test.pver) + 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.MsgBlock + r := newFixedReader(test.max, test.buf) + err = msg.BtcDecode(r, test.pver) + if err != test.readErr { + t.Errorf("BtcDecode #%d wrong error got: %v, want: %v", + i, err, test.readErr) + continue + } + } +} + var blockOne btcwire.MsgBlock = btcwire.MsgBlock{ Header: btcwire.BlockHeader{ Version: 1, diff --git a/test_coverage.txt b/test_coverage.txt index 486bffd0..7b30d333 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -2,46 +2,50 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) -github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) +github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) @@ -109,45 +113,41 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00 github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 80.00% (8/10) -github.com/conformal/btcwire/blockheader.go readBlockHeader 80.00% (8/10) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 77.78% (7/9) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 76.92% (10/13) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 76.00% (19/25) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) -github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) -github.com/conformal/btcwire/invvect.go writeInvVect 75.00% (3/4) github.com/conformal/btcwire/invvect.go readInvVect 75.00% (3/4) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 73.91% (17/23) +github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) +github.com/conformal/btcwire/invvect.go writeInvVect 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 69.23% (9/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 69.23% (9/13) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 82.96% (774/933) +github.com/conformal/btcwire --------------------------------- 84.03% (784/933) From 036f14ff4971831ef4d8dc76e1685408dc3551f6 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 10:12:45 -0500 Subject: [PATCH 026/219] Convert MsgInv errors to new MessageError type. --- msginv.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/msginv.go b/msginv.go index 9cbb5bf1..8ec0c246 100644 --- a/msginv.go +++ b/msginv.go @@ -25,8 +25,9 @@ type MsgInv struct { // AddInvVect adds an inventory vector to the message. func (msg *MsgInv) AddInvVect(iv *InvVect) error { if len(msg.InvList)+1 > MaxInvPerMsg { - str := "MsgInv.AddAddress: too many invvect in message [max %v]" - return fmt.Errorf(str, MaxInvPerMsg) + str := fmt.Sprintf("too many invvect in message [max %v]", + MaxInvPerMsg) + return messageError("MsgInv.AddAddress", str) } msg.InvList = append(msg.InvList, iv) @@ -43,8 +44,8 @@ func (msg *MsgInv) BtcDecode(r io.Reader, pver uint32) error { // Limit to max inventory vectors per message. if count > MaxInvPerMsg { - str := "MsgInv.BtcDecode: too many invvect in message [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many invvect in message [%v]", count) + return messageError("MsgInv.BtcDecode", str) } for i := uint64(0); i < count; i++ { @@ -65,8 +66,8 @@ func (msg *MsgInv) BtcEncode(w io.Writer, pver uint32) error { // Limit to max inventory vectors per message. count := len(msg.InvList) if count > MaxInvPerMsg { - str := "MsgInv.BtcEncode: too many invvect in message [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many invvect in message [%v]", count) + return messageError("MsgInv.BtcDecode", str) } err := writeVarInt(w, pver, uint64(count)) From 59d64ee07625f180a14af21f6d8f4e4da4d8eefa Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 10:14:13 -0500 Subject: [PATCH 027/219] Add negative tests for MsgInv. This commit adds tests for the error paths when encoded and decoding MsgInv. --- msginv_test.go | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/msginv_test.go b/msginv_test.go index 9852ed2b..056269d2 100644 --- a/msginv_test.go +++ b/msginv_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" ) @@ -220,3 +221,102 @@ func TestInvWire(t *testing.T) { } } } + +// TestInvWireErrors performs negative tests against wire encode and decode +// of MsgInv to confirm error paths work correctly. +func TestInvWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + btcwireErr := &btcwire.MessageError{} + + // Block 203707 hash. + hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" + blockHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) + + // Base inv message used to induce errors. + baseInv := btcwire.NewMsgInv() + baseInv.AddInvVect(iv) + baseInvEncoded := []byte{ + 0x02, // Varint for number of inv vectors + 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, + 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, + 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, + 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash + } + + // Inv message that forces an error by having more than the max allowed + // inv vectors. + maxInv := btcwire.NewMsgInv() + for i := 0; i < btcwire.MaxInvPerMsg; i++ { + maxInv.AddInvVect(iv) + } + maxInv.InvList = append(maxInv.InvList, iv) + maxInvEncoded := []byte{ + 0xfd, 0x51, 0xc3, // Varint for number of inv vectors (50001) + } + + tests := []struct { + in *btcwire.MsgInv // 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 error in inventory vector count + {baseInv, baseInvEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in inventory list. + {baseInv, baseInvEncoded, pver, 1, io.ErrShortWrite, io.EOF}, + // Force error with greater than max inventory vectors. + {maxInv, maxInvEncoded, pver, 3, 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.MsgInv + 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("BtcEncode #%d wrong error got: %v, "+ + "want: %v", i, err, test.readErr) + continue + } + } + + } +} From 72fa9f4b7b4b86bc8e04416b0b5490414f969ad4 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 10:18:34 -0500 Subject: [PATCH 028/219] Update test coverage report. --- test_coverage.txt | 52 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/test_coverage.txt b/test_coverage.txt index 7b30d333..40b56be5 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -7,45 +7,49 @@ github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) @@ -123,31 +127,27 @@ github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 76.92% (10/13) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) -github.com/conformal/btcwire/invvect.go readInvVect 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) -github.com/conformal/btcwire/invvect.go writeInvVect 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 69.23% (9/13) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 69.23% (9/13) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 66.67% (8/12) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 84.03% (784/933) +github.com/conformal/btcwire --------------------------------- 85.10% (794/933) From 29cd3a724668cd1e10d781b333e5b65ef3f816bd Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 10:31:39 -0500 Subject: [PATCH 029/219] Fix comment typo in test coverage report script. --- cov_report.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cov_report.sh b/cov_report.sh index 5cc6f201..873f90e4 100644 --- a/cov_report.sh +++ b/cov_report.sh @@ -4,7 +4,7 @@ # The gocov tool my be obtained with the following command: # go get github.com/awx/gocov/gocov # -# It will be installed it $GOPATH/bin, so ensure that location is in your $PATH. +# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH. # Check for gocov. type gocov >/dev/null 2>&1 From d33fdb2c3ce62f1e253feec35ce8b6f582ba37a8 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 11:04:30 -0500 Subject: [PATCH 030/219] Add additional doco on how btcwire relates to btcd. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index cdacac5e..03e6c44f 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ licensed under the liberal ISC license. There is an associated blog post about the release of this package [here](https://blog.conformal.com/btcwire-the-bitcoin-wire-protocol-package-from-btcd/). +This package is one of the core packages from btcd, an alternative full-node +implementation of bitcoin which is under active development by Conformal. +Although it was primarily written for btcd, this package has intentionally been +designed so it can be used as a standalone package for any projects needing to +interface with bitcoin peers at the wire protocol level. + ## Documentation Full `go doc` style documentation for the project can be viewed online without From e41a3bcaf34234b8d55fd8ceca29d9138268063f Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 11:31:06 -0500 Subject: [PATCH 031/219] Correct a couple of func prefixes in err messages. --- msginv.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/msginv.go b/msginv.go index 8ec0c246..015f4a81 100644 --- a/msginv.go +++ b/msginv.go @@ -27,7 +27,7 @@ func (msg *MsgInv) AddInvVect(iv *InvVect) error { if len(msg.InvList)+1 > MaxInvPerMsg { str := fmt.Sprintf("too many invvect in message [max %v]", MaxInvPerMsg) - return messageError("MsgInv.AddAddress", str) + return messageError("MsgInv.AddInvVect", str) } msg.InvList = append(msg.InvList, iv) @@ -67,7 +67,7 @@ func (msg *MsgInv) BtcEncode(w io.Writer, pver uint32) error { count := len(msg.InvList) if count > MaxInvPerMsg { str := fmt.Sprintf("too many invvect in message [%v]", count) - return messageError("MsgInv.BtcDecode", str) + return messageError("MsgInv.BtcEncode", str) } err := writeVarInt(w, pver, uint64(count)) From 9b798b6306aacb1099fd9f629f3eb3d3fe70b850 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 11:32:20 -0500 Subject: [PATCH 032/219] Convert MsgNotFound errors to MessageError type. --- msgnotfound.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/msgnotfound.go b/msgnotfound.go index c920fe33..1fbfd155 100644 --- a/msgnotfound.go +++ b/msgnotfound.go @@ -23,8 +23,9 @@ type MsgNotFound struct { // AddInvVect adds an inventory vector to the message. func (msg *MsgNotFound) AddInvVect(iv *InvVect) error { if len(msg.InvList)+1 > MaxInvPerMsg { - str := "MsgNotFound.AddAddress: too many invvect in message [max %v]" - return fmt.Errorf(str, MaxInvPerMsg) + str := fmt.Sprintf("too many invvect in message [max %v]", + MaxInvPerMsg) + return messageError("MsgNotFound.AddInvVect", str) } msg.InvList = append(msg.InvList, iv) @@ -41,8 +42,8 @@ func (msg *MsgNotFound) BtcDecode(r io.Reader, pver uint32) error { // Limit to max inventory vectors per message. if count > MaxInvPerMsg { - str := "MsgNotFound.BtcDecode: too many invvect in message [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many invvect in message [%v]", count) + return messageError("MsgNotFound.BtcDecode", str) } for i := uint64(0); i < count; i++ { @@ -63,8 +64,8 @@ func (msg *MsgNotFound) BtcEncode(w io.Writer, pver uint32) error { // Limit to max inventory vectors per message. count := len(msg.InvList) if count > MaxInvPerMsg { - str := "MsgNotFound.BtcEncode: too many invvect in message [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many invvect in message [%v]", count) + return messageError("MsgNotFound.BtcEncode", str) } err := writeVarInt(w, pver, uint64(count)) From 0c65e7da892ccb54b0ca9f58e49bb6cc7236d0c4 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 12:51:45 -0500 Subject: [PATCH 033/219] Add negative tests for MsgNotFound. This commit adds tests for the error paths when encoded and decoding MsgNotFound. --- msgnotfound_test.go | 100 ++++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 64 ++++++++++++++-------------- 2 files changed, 132 insertions(+), 32 deletions(-) diff --git a/msgnotfound_test.go b/msgnotfound_test.go index 190f2da2..b5c411ab 100644 --- a/msgnotfound_test.go +++ b/msgnotfound_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" ) @@ -220,3 +221,102 @@ func TestNotFoundWire(t *testing.T) { } } } + +// TestNotFoundWireErrors performs negative tests against wire encode and decode +// of MsgNotFound to confirm error paths work correctly. +func TestNotFoundWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + btcwireErr := &btcwire.MessageError{} + + // Block 203707 hash. + hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" + blockHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) + + // Base message used to induce errors. + baseNotFound := btcwire.NewMsgNotFound() + baseNotFound.AddInvVect(iv) + baseNotFoundEncoded := []byte{ + 0x02, // Varint for number of inv vectors + 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, + 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, + 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, + 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash + } + + // Message that forces an error by having more than the max allowed inv + // vectors. + maxNotFound := btcwire.NewMsgNotFound() + for i := 0; i < btcwire.MaxInvPerMsg; i++ { + maxNotFound.AddInvVect(iv) + } + maxNotFound.InvList = append(maxNotFound.InvList, iv) + maxNotFoundEncoded := []byte{ + 0xfd, 0x51, 0xc3, // Varint for number of inv vectors (50001) + } + + tests := []struct { + in *btcwire.MsgNotFound // 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 error in inventory vector count + {baseNotFound, baseNotFoundEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in inventory list. + {baseNotFound, baseNotFoundEncoded, pver, 1, io.ErrShortWrite, io.EOF}, + // Force error with greater than max inventory vectors. + {maxNotFound, maxNotFoundEncoded, pver, 3, 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.MsgNotFound + 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("BtcEncode #%d wrong error got: %v, "+ + "want: %v", i, err, test.readErr) + continue + } + } + + } +} diff --git a/test_coverage.txt b/test_coverage.txt index 40b56be5..80710db0 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -8,50 +8,52 @@ github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) @@ -118,8 +120,8 @@ github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) @@ -127,15 +129,14 @@ github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 76.92% (10/13) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) @@ -143,11 +144,10 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/2 github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 66.67% (8/12) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 66.67% (8/12) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 85.10% (794/933) +github.com/conformal/btcwire --------------------------------- 85.96% (802/933) From 7c3129bf8938d62e87f61c9298624bb750d6d176 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 13:04:20 -0500 Subject: [PATCH 034/219] Convert MsgGetData errors to MessageError type. --- msggetdata.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/msggetdata.go b/msggetdata.go index 865c94d4..79a6d502 100644 --- a/msggetdata.go +++ b/msggetdata.go @@ -26,8 +26,9 @@ type MsgGetData struct { // AddInvVect adds an inventory vector to the message. func (msg *MsgGetData) AddInvVect(iv *InvVect) error { if len(msg.InvList)+1 > MaxInvPerMsg { - str := "MsgAddr.AddAddress: too many invvect in message [max %v]" - return fmt.Errorf(str, MaxInvPerMsg) + str := fmt.Sprintf("too many invvect in message [max %v]", + MaxInvPerMsg) + return messageError("MsgAddr.AddInvVect", str) } msg.InvList = append(msg.InvList, iv) @@ -44,8 +45,8 @@ func (msg *MsgGetData) BtcDecode(r io.Reader, pver uint32) error { // Limit to max inventory vectors per message. if count > MaxInvPerMsg { - str := "MsgGetData.BtcDecode: too many invvect in message [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many invvect in message [%v]", count) + return messageError("MsgGetData.BtcDecode", str) } for i := uint64(0); i < count; i++ { @@ -66,8 +67,8 @@ func (msg *MsgGetData) BtcEncode(w io.Writer, pver uint32) error { // Limit to max inventory vectors per message. count := len(msg.InvList) if count > MaxInvPerMsg { - str := "MsgGetData.BtcDecode: too many invvect in message [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many invvect in message [%v]", count) + return messageError("MsgGetData.BtcEncode", str) } err := writeVarInt(w, pver, uint64(count)) From 2665b4358ec5b924e25689a925b0d15b4d3c43c7 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 13:14:19 -0500 Subject: [PATCH 035/219] Add negative tests for MsgGetData. This commit adds tests for the error paths when encoded and decoding MsgGetData. --- msggetdata_test.go | 100 +++++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 50 +++++++++++------------ 2 files changed, 125 insertions(+), 25 deletions(-) diff --git a/msggetdata_test.go b/msggetdata_test.go index b800af7c..f9e00b10 100644 --- a/msggetdata_test.go +++ b/msggetdata_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" ) @@ -220,3 +221,102 @@ func TestGetDataWire(t *testing.T) { } } } + +// TestGetDataWireErrors performs negative tests against wire encode and decode +// of MsgGetData to confirm error paths work correctly. +func TestGetDataWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + btcwireErr := &btcwire.MessageError{} + + // Block 203707 hash. + hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" + blockHash, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) + + // Base message used to induce errors. + baseGetData := btcwire.NewMsgGetData() + baseGetData.AddInvVect(iv) + baseGetDataEncoded := []byte{ + 0x02, // Varint for number of inv vectors + 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, + 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, + 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, + 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash + } + + // Message that forces an error by having more than the max allowed inv + // vectors. + maxGetData := btcwire.NewMsgGetData() + for i := 0; i < btcwire.MaxInvPerMsg; i++ { + maxGetData.AddInvVect(iv) + } + maxGetData.InvList = append(maxGetData.InvList, iv) + maxGetDataEncoded := []byte{ + 0xfd, 0x51, 0xc3, // Varint for number of inv vectors (50001) + } + + tests := []struct { + in *btcwire.MsgGetData // 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 error in inventory vector count + {baseGetData, baseGetDataEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + //// Force error in inventory list. + {baseGetData, baseGetDataEncoded, pver, 1, io.ErrShortWrite, io.EOF}, + //// Force error with greater than max inventory vectors. + {maxGetData, maxGetDataEncoded, pver, 3, 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.MsgGetData + 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("BtcEncode #%d wrong error got: %v, "+ + "want: %v", i, err, test.readErr) + continue + } + } + + } +} diff --git a/test_coverage.txt b/test_coverage.txt index 80710db0..4056c685 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -7,23 +7,25 @@ github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) +github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) @@ -35,23 +37,23 @@ github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) @@ -120,34 +122,32 @@ github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 76.92% (10/13) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 69.23% (9/13) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 66.67% (8/12) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 85.96% (802/933) +github.com/conformal/btcwire --------------------------------- 86.82% (810/933) From 72348986c9011e6955a9ef253cbd099188093a5f Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 13:37:55 -0500 Subject: [PATCH 036/219] Correct func prefix in GetData error message. --- msggetdata.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msggetdata.go b/msggetdata.go index 79a6d502..e4f546eb 100644 --- a/msggetdata.go +++ b/msggetdata.go @@ -28,7 +28,7 @@ func (msg *MsgGetData) AddInvVect(iv *InvVect) error { if len(msg.InvList)+1 > MaxInvPerMsg { str := fmt.Sprintf("too many invvect in message [max %v]", MaxInvPerMsg) - return messageError("MsgAddr.AddInvVect", str) + return messageError("MsgGetData.AddInvVect", str) } msg.InvList = append(msg.InvList, iv) From 1f72b408234d47f3ebdcfc116c9791bd79ef133b Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 14:54:36 -0500 Subject: [PATCH 037/219] Convert MsgAddr errors to MessageError type. --- msgaddr.go | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/msgaddr.go b/msgaddr.go index 54eb4e6c..13371c5c 100644 --- a/msgaddr.go +++ b/msgaddr.go @@ -30,8 +30,9 @@ type MsgAddr struct { // AddAddress adds a known active peer to the message. func (msg *MsgAddr) AddAddress(na *NetAddress) error { if len(msg.AddrList)+1 > MaxAddrPerMsg { - str := "MsgAddr.AddAddress: too many addresses for message [max %v]" - return fmt.Errorf(str, MaxAddrPerMsg) + str := fmt.Sprintf("too many addresses in message [max %v]", + MaxAddrPerMsg) + return messageError("MsgAddr.AddAddress", str) } msg.AddrList = append(msg.AddrList, na) @@ -64,8 +65,9 @@ func (msg *MsgAddr) BtcDecode(r io.Reader, pver uint32) error { // Limit to max addresses per message. if count > MaxAddrPerMsg { - str := "MsgAddr.BtcDecode: too many addresses in message [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many addresses for message "+ + "[count %v, max %v]", count, MaxAddrPerMsg) + return messageError("MsgAddr.BtcDecode", str) } for i := uint64(0); i < count; i++ { @@ -86,14 +88,15 @@ func (msg *MsgAddr) BtcEncode(w io.Writer, pver uint32) error { // per message. count := len(msg.AddrList) if pver < MultipleAddressVersion && count > 1 { - str := "MsgAddr.BtcDecode: too many addresses in message " + - "for protocol version [version %v max 1]" - return fmt.Errorf(str, pver) + str := fmt.Sprintf("too many addresses for message of "+ + "protocol version %v [count %v, max 1]", pver, count) + return messageError("MsgAddr.BtcEncode", str) } if count > MaxAddrPerMsg { - str := "MsgAddr.BtcDecode: too many addresses in message [max %v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many addresses for message "+ + "[count %v, max %v]", count, MaxAddrPerMsg) + return messageError("MsgAddr.BtcEncode", str) } err := writeVarInt(w, pver, uint64(count)) From e699ca0bef5b9ec3d249cdc4033bd2602a10d712 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 15:39:37 -0500 Subject: [PATCH 038/219] Cleanup a few comments. --- msggetdata_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/msggetdata_test.go b/msggetdata_test.go index f9e00b10..bfa31e20 100644 --- a/msggetdata_test.go +++ b/msggetdata_test.go @@ -268,12 +268,12 @@ func TestGetDataWireErrors(t *testing.T) { writeErr error // Expected write error readErr error // Expected read error }{ - //// Latest protocol version with intentional read/write errors. - //// Force error in inventory vector count + // Latest protocol version with intentional read/write errors. + // Force error in inventory vector count {baseGetData, baseGetDataEncoded, pver, 0, io.ErrShortWrite, io.EOF}, - //// Force error in inventory list. + // Force error in inventory list. {baseGetData, baseGetDataEncoded, pver, 1, io.ErrShortWrite, io.EOF}, - //// Force error with greater than max inventory vectors. + // Force error with greater than max inventory vectors. {maxGetData, maxGetDataEncoded, pver, 3, btcwireErr, btcwireErr}, } From cfb17f7da4db4cb4c766b037d53617aa38d773d6 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 15:58:05 -0500 Subject: [PATCH 039/219] Update gocov path in comments to correct path. --- cov_report.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cov_report.sh b/cov_report.sh index 873f90e4..307f05b7 100644 --- a/cov_report.sh +++ b/cov_report.sh @@ -2,7 +2,7 @@ # This script uses gocov to generate a test coverage report. # The gocov tool my be obtained with the following command: -# go get github.com/awx/gocov/gocov +# go get github.com/axw/gocov/gocov # # It will be installed to $GOPATH/bin, so ensure that location is in your $PATH. From 1220e72f35ad5e18a1b6e2b1a013f034d3275ef6 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 18:09:10 -0500 Subject: [PATCH 040/219] Add negative tests for MsgAddr. This commit adds tests for the error paths when encoded and decoding MsgAddr. --- msgaddr_test.go | 115 ++++++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 68 +++++++++++++-------------- 2 files changed, 149 insertions(+), 34 deletions(-) diff --git a/msgaddr_test.go b/msgaddr_test.go index fd741ac5..dd147b23 100644 --- a/msgaddr_test.go +++ b/msgaddr_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "net" "reflect" "testing" @@ -203,3 +204,117 @@ func TestAddrWire(t *testing.T) { } } } + +// TestAddrWireErrors performs negative tests against wire encode and decode +// of MsgAddr to confirm error paths work correctly. +func TestAddrWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + pverMA := btcwire.MultipleAddressVersion + btcwireErr := &btcwire.MessageError{} + + // A couple of NetAddresses to use for testing. + na := &btcwire.NetAddress{ + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("127.0.0.1"), + Port: 8333, + } + na2 := &btcwire.NetAddress{ + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("192.168.0.1"), + Port: 8334, + } + + // Address message with multiple addresses. + baseAddr := btcwire.NewMsgAddr() + baseAddr.AddAddresses(na, na2) + baseAddrEncoded := []byte{ + 0x02, // Varint for number of addresses + 0x29, 0xab, 0x5f, 0x49, // Timestamp + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + 0x29, 0xab, 0x5f, 0x49, // Timestamp + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01, // IP 192.168.0.1 + 0x20, 0x8e, // Port 8334 in big-endian + + } + + // Message that forces an error by having more than the max allowed + // addresses. + maxAddr := btcwire.NewMsgAddr() + for i := 0; i < btcwire.MaxAddrPerMsg; i++ { + maxAddr.AddAddress(na) + } + maxAddr.AddrList = append(maxAddr.AddrList, na) + maxAddrEncoded := []byte{ + 0xfd, 0x03, 0xe9, // Varint for number of addresses (1001) + } + + tests := []struct { + in *btcwire.MsgAddr // 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 error in addresses count + {baseAddr, baseAddrEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in address list. + {baseAddr, baseAddrEncoded, pver, 1, io.ErrShortWrite, io.EOF}, + // Force error with greater than max inventory vectors. + {maxAddr, maxAddrEncoded, pver, 3, btcwireErr, btcwireErr}, + // Force error with greater than max inventory vectors for + // protocol versions before multiple addresses were allowed. + {maxAddr, maxAddrEncoded, pverMA - 1, 3, 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.MsgAddr + 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("BtcEncode #%d wrong error got: %v, "+ + "want: %v", i, err, test.readErr) + continue + } + } + + } +} diff --git a/test_coverage.txt b/test_coverage.txt index 4056c685..cb252cc5 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -2,58 +2,60 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) -github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) +github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) @@ -121,33 +123,31 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00 github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 76.92% (10/13) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) -github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 86.82% (810/933) +github.com/conformal/btcwire --------------------------------- 87.78% (819/933) From cbb28edb30f361f6e56213b8b4adae1142c2c56a Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 21:31:56 -0500 Subject: [PATCH 041/219] Convert MsgPong errors to MessageError type. --- msgpong.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/msgpong.go b/msgpong.go index 8794ebd5..70127726 100644 --- a/msgpong.go +++ b/msgpong.go @@ -26,9 +26,9 @@ func (msg *MsgPong) BtcDecode(r io.Reader, pver uint32) error { // NOTE: <= is not a mistake here. The BIP0031 was defined as AFTER // the version unlike most others. if pver <= BIP0031Version { - err := fmt.Errorf("pong message invalid for protocol version: %d", - pver) - return err + str := fmt.Sprintf("pong message invalid for protocol "+ + "version %d", pver) + return messageError("MsgPong.BtcDecode", str) } err := readElement(r, &msg.Nonce) @@ -45,9 +45,9 @@ func (msg *MsgPong) BtcEncode(w io.Writer, pver uint32) error { // NOTE: <= is not a mistake here. The BIP0031 was defined as AFTER // the version unlike most others. if pver <= BIP0031Version { - err := fmt.Errorf("pong message invalid for protocol version: %d", - pver) - return err + str := fmt.Sprintf("pong message invalid for protocol "+ + "version %d", pver) + return messageError("MsgPong.BtcEncode", str) } err := writeElement(w, msg.Nonce) From 88e1d7634fd0b4e7979d7b6feafa11f63e029009 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 21:46:41 -0500 Subject: [PATCH 042/219] Add negative tests for MsgPong. This commit adds tests for the error paths when encoded and decoding MsgPong. --- msgpong_test.go | 88 +++++++++++++++++++++++++++++++++++++++-------- test_coverage.txt | 68 ++++++++++++++++++------------------ 2 files changed, 108 insertions(+), 48 deletions(-) diff --git a/msgpong_test.go b/msgpong_test.go index 0297888d..21bdf198 100644 --- a/msgpong_test.go +++ b/msgpong_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" ) @@ -153,7 +154,6 @@ func TestPongWire(t *testing.T) { out btcwire.MsgPong // Expected decoded message buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding - err error // expected error }{ // Latest protocol version. { @@ -161,7 +161,6 @@ func TestPongWire(t *testing.T) { btcwire.MsgPong{Nonce: 123123}, // 0x1e0f3 []byte{0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}, btcwire.ProtocolVersion, - nil, }, // Protocol version BIP0031Version+1 @@ -170,17 +169,7 @@ func TestPongWire(t *testing.T) { btcwire.MsgPong{Nonce: 456456}, // 0x6f708 []byte{0x08, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, btcwire.BIP0031Version + 1, - nil, }, - - // Protocol version BIP0031Version - //{ - // btcwire.MsgPong{Nonce: 789789}, // 0xc0d1d - // btcwire.MsgPong{Nonce: 0}, // No nonce for pver - // []byte{}, // No nonce for pver - // btcwire.BIP0031Version, - // nil, /// Need err type.... - //}, } t.Logf("Running %d tests", len(tests)) @@ -188,7 +177,7 @@ func TestPongWire(t *testing.T) { // Encode the message to wire format. var buf bytes.Buffer err := test.in.BtcEncode(&buf, test.pver) - if err != test.err { + if err != nil { t.Errorf("BtcEncode #%d error %v", i, err) continue } @@ -202,7 +191,7 @@ func TestPongWire(t *testing.T) { var msg btcwire.MsgPong rbuf := bytes.NewBuffer(test.buf) err = msg.BtcDecode(rbuf, test.pver) - if err != test.err { + if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) continue } @@ -213,3 +202,74 @@ func TestPongWire(t *testing.T) { } } } + +// TestPongWireErrors performs negative tests against wire encode and decode +// of MsgPong to confirm error paths work correctly. +func TestPongWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + pverNoPong := btcwire.BIP0031Version + btcwireErr := &btcwire.MessageError{} + + basePong := btcwire.NewMsgPong(123123) // 0x1e0f3 + basePongEncoded := []byte{ + 0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + } + + tests := []struct { + in *btcwire.MsgPong // 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 error in nonce. + {basePong, basePongEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error due to unsupported protocol version. + {basePong, basePongEncoded, pverNoPong, 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.MsgPong + 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("BtcEncode #%d wrong error got: %v, "+ + "want: %v", i, err, test.readErr) + continue + } + } + + } +} diff --git a/test_coverage.txt b/test_coverage.txt index cb252cc5..20ee4632 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,17 +1,17 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) -github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) +github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) @@ -20,42 +20,44 @@ github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) @@ -123,25 +125,23 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00 github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 85.71% (6/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 85.71% (6/7) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) -github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) @@ -149,5 +149,5 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/2 github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 87.78% (819/933) +github.com/conformal/btcwire --------------------------------- 88.00% (821/933) From 40a9a90e4b30a48f599f1fd0b0fea798ae0a7529 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 23:10:59 -0500 Subject: [PATCH 043/219] Convert MsgHeaders errors to MessageError type. --- msgheaders.go | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/msgheaders.go b/msgheaders.go index dd416651..c507a90b 100644 --- a/msgheaders.go +++ b/msgheaders.go @@ -25,9 +25,9 @@ type MsgHeaders struct { // AddBlockHeader adds a new block header to the message. func (msg *MsgHeaders) AddBlockHeader(bh *BlockHeader) error { if len(msg.Headers)+1 > MaxBlockHeadersPerMsg { - str := "MsgHeaders.AddBlockHeader: too many block headers " + - "for message [max %v]" - return fmt.Errorf(str, MaxBlockHeadersPerMsg) + str := fmt.Sprintf("too many block headers in message [max %v]", + MaxBlockHeadersPerMsg) + return messageError("MsgHeaders.AddBlockHeader", str) } msg.Headers = append(msg.Headers, bh) @@ -44,8 +44,9 @@ func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32) error { // Limit to max block headers per message. if count > MaxBlockHeadersPerMsg { - str := "MsgHeaders.BtcDecode: too many block headers in message [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many block headers for message "+ + "[count %v, max %v]", count, MaxBlockHeadersPerMsg) + return messageError("MsgHeaders.BtcDecode", str) } for i := uint64(0); i < count; i++ { @@ -57,9 +58,9 @@ func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32) error { // Ensure the transaction count is zero for headers. if bh.TxnCount > 0 { - str := "MsgHeaders.BtcDecode: block headers may not " + - "contain transactions [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("block headers may not contain "+ + "transactions [count %v]", bh.TxnCount) + return messageError("MsgHeaders.BtcDecode", str) } msg.AddBlockHeader(&bh) } @@ -73,8 +74,9 @@ func (msg *MsgHeaders) BtcEncode(w io.Writer, pver uint32) error { // Limit to max block headers per message. count := len(msg.Headers) if count > MaxBlockHeadersPerMsg { - str := "MsgHeaders.BtcEncode: too many block headers in message [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many block headers for message "+ + "[count %v, max %v]", count, MaxBlockHeadersPerMsg) + return messageError("MsgHeaders.BtcEncode", str) } err := writeVarInt(w, pver, uint64(count)) @@ -85,9 +87,9 @@ func (msg *MsgHeaders) BtcEncode(w io.Writer, pver uint32) error { for _, bh := range msg.Headers { // Ensure block headers do not contain a transaction count. if bh.TxnCount > 0 { - str := "MsgHeaders.BtcEncode: block headers " + - "may not contain transactions [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("block headers may not contain "+ + "transactions [count %v]", bh.TxnCount) + return messageError("MsgHeaders.BtcEncode", str) } err := writeBlockHeader(w, pver, bh) From 95aa4a7da8d066c6b36cc32d8e45f099a717d0ac Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 23:12:55 -0500 Subject: [PATCH 044/219] Add negative tests for MsgHeaders. This commit adds tests for the error paths when encoded and decoding MsgHeaders. --- msgheaders_test.go | 135 +++++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 68 +++++++++++------------ 2 files changed, 169 insertions(+), 34 deletions(-) diff --git a/msgheaders_test.go b/msgheaders_test.go index c84ab3a1..07a58b3b 100644 --- a/msgheaders_test.go +++ b/msgheaders_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" ) @@ -211,3 +212,137 @@ func TestHeadersWire(t *testing.T) { } } } + +// TestHeadersWireErrors performs negative tests against wire encode and decode +// of MsgHeaders to confirm error paths work correctly. +func TestHeadersWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + btcwireErr := &btcwire.MessageError{} + + hash := btcwire.GenesisHash + merkleHash := blockOne.Header.MerkleRoot + bits := uint32(0x1d00ffff) + nonce := uint32(0x9962e301) + bh := btcwire.NewBlockHeader(&hash, &merkleHash, bits, nonce) + bh.Version = blockOne.Header.Version + bh.Timestamp = blockOne.Header.Timestamp + + // Headers message with one header. + oneHeader := btcwire.NewMsgHeaders() + oneHeader.AddBlockHeader(bh) + oneHeaderEncoded := []byte{ + 0x01, // VarInt for number of headers. + 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 + 0x00, // TxnCount (0 for headers message) + } + + // Message that forces an error by having more than the max allowed + // headers. + maxHeaders := btcwire.NewMsgHeaders() + for i := 0; i < btcwire.MaxBlockHeadersPerMsg; i++ { + maxHeaders.AddBlockHeader(bh) + } + maxHeaders.Headers = append(maxHeaders.Headers, bh) + maxHeadersEncoded := []byte{ + 0xfd, 0xd1, 0x07, // Varint for number of addresses (2001)7D1 + } + + // Intentionally invalid block header that has a transaction count used + // to force errors. + bhTrans := btcwire.NewBlockHeader(&hash, &merkleHash, bits, nonce) + bhTrans.Version = blockOne.Header.Version + bhTrans.Timestamp = blockOne.Header.Timestamp + bhTrans.TxnCount = 1 + + transHeader := btcwire.NewMsgHeaders() + transHeader.AddBlockHeader(bhTrans) + transHeaderEncoded := []byte{ + 0x01, // VarInt for number of headers. + 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, // TxnCount (should be 0 for headers message, but 1 to force error) + } + + tests := []struct { + in *btcwire.MsgHeaders // 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 error in header count. + {oneHeader, oneHeaderEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in block header. + {oneHeader, oneHeaderEncoded, pver, 5, io.ErrShortWrite, io.EOF}, + // Force error with greater than max headers. + {maxHeaders, maxHeadersEncoded, pver, 3, btcwireErr, btcwireErr}, + // Force error with included transactions. + {transHeader, transHeaderEncoded, pver, len(transHeaderEncoded), 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.MsgHeaders + 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("BtcEncode #%d wrong error got: %v, "+ + "want: %v", i, err, test.readErr) + continue + } + } + + } +} diff --git a/test_coverage.txt b/test_coverage.txt index 20ee4632..d2e4e5c2 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -2,64 +2,66 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) -github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) +github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) -github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) +github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) @@ -132,22 +134,20 @@ github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 62.50% (10/16) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 60.00% (9/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 88.00% (821/933) +github.com/conformal/btcwire --------------------------------- 89.28% (833/933) From 9bd97a59723931f34ba2171634050f1f941b95f1 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 10 May 2013 23:58:10 -0500 Subject: [PATCH 045/219] Convert MsgGetHeaders errors to MessageError type. --- msggetheaders.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/msggetheaders.go b/msggetheaders.go index 0caeaf83..50a6b023 100644 --- a/msggetheaders.go +++ b/msggetheaders.go @@ -34,9 +34,9 @@ type MsgGetHeaders struct { // AddBlockLocatorHash adds a new block locator hash to the message. func (msg *MsgGetHeaders) AddBlockLocatorHash(hash *ShaHash) error { if len(msg.BlockLocatorHashes)+1 > MaxBlockLocatorsPerMsg { - str := "MsgGetHeaders.AddBlockLocatorHash: too many block " + - "locator hashes for message [max %v]" - return fmt.Errorf(str, MaxBlockLocatorsPerMsg) + str := fmt.Sprintf("too many block locator hashes for message [max %v]", + MaxBlockLocatorsPerMsg) + return messageError("MsgGetHeaders.AddBlockLocatorHash", str) } msg.BlockLocatorHashes = append(msg.BlockLocatorHashes, hash) @@ -57,8 +57,9 @@ func (msg *MsgGetHeaders) BtcDecode(r io.Reader, pver uint32) error { return err } if count > MaxBlockLocatorsPerMsg { - str := "%v: too many block locator hashes in message [%v]" - return fmt.Errorf(str, "MsgGetHeaders.BtcDecode", count) + str := fmt.Sprintf("too many block locator hashes for message "+ + "[count %v, max %v]", count, MaxBlockLocatorsPerMsg) + return messageError("MsgGetHeaders.BtcDecode", str) } for i := uint64(0); i < count; i++ { @@ -84,9 +85,9 @@ func (msg *MsgGetHeaders) BtcEncode(w io.Writer, pver uint32) error { // Limit to max block locator hashes per message. count := len(msg.BlockLocatorHashes) if count > MaxBlockLocatorsPerMsg { - str := "MsgGetHeaders.BtcEncode: too many block locator " + - "hashes in message [%v]" - return fmt.Errorf(str, count) + str := fmt.Sprintf("too many block locator hashes for message "+ + "[count %v, max %v]", count, MaxBlockLocatorsPerMsg) + return messageError("MsgGetHeaders.BtcEncode", str) } err := writeElement(w, msg.ProtocolVersion) From bd1dcf8a0c92b0d6fdf90bf5eac31b2f5cb37c44 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 02:15:50 -0500 Subject: [PATCH 046/219] Convert MsgGetBlocks errors to MessageError type. --- msggetblocks.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/msggetblocks.go b/msggetblocks.go index 9d301614..b10eb7e6 100644 --- a/msggetblocks.go +++ b/msggetblocks.go @@ -37,9 +37,9 @@ type MsgGetBlocks struct { // AddBlockLocatorHash adds a new block locator hash to the message. func (msg *MsgGetBlocks) AddBlockLocatorHash(hash *ShaHash) error { if len(msg.BlockLocatorHashes)+1 > MaxBlockLocatorsPerMsg { - str := "MsgGetBlocks.AddBlockLocatorHash: too many block " + - "locator hashes for message [max %v]" - return fmt.Errorf(str, MaxBlockLocatorsPerMsg) + str := fmt.Sprintf("too many block locator hashes for message [max %v]", + MaxBlockLocatorsPerMsg) + return messageError("MsgGetBlocks.AddBlockLocatorHash", str) } msg.BlockLocatorHashes = append(msg.BlockLocatorHashes, hash) @@ -60,8 +60,9 @@ func (msg *MsgGetBlocks) BtcDecode(r io.Reader, pver uint32) error { return err } if count > MaxBlockLocatorsPerMsg { - str := "%v: too many block locator hashes in message [%v]" - return fmt.Errorf(str, "MsgGetBlocks.BtcDecode", count) + str := fmt.Sprintf("too many block locator hashes for message "+ + "[count %v, max %v]", count, MaxBlockLocatorsPerMsg) + return messageError("MsgGetBlocks.BtcDecode", str) } for i := uint64(0); i < count; i++ { @@ -86,8 +87,9 @@ func (msg *MsgGetBlocks) BtcDecode(r io.Reader, pver uint32) error { func (msg *MsgGetBlocks) BtcEncode(w io.Writer, pver uint32) error { count := len(msg.BlockLocatorHashes) if count > MaxBlockLocatorsPerMsg { - str := "%v: too many block locator hashes in message [%v]" - return fmt.Errorf(str, "MsgGetBlocks.BtcEncode", count) + str := fmt.Sprintf("too many block locator hashes for message "+ + "[count %v, max %v]", count, MaxBlockLocatorsPerMsg) + return messageError("MsgGetBlocks.BtcEncode", str) } err := writeElement(w, msg.ProtocolVersion) From f6cdbd430e1c3f0e2c7d5ca023666a8fdb425f2d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 02:18:03 -0500 Subject: [PATCH 047/219] Convert MsgMemPool errors to MessageError type. --- msgmempool.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/msgmempool.go b/msgmempool.go index 36eaf7f5..b816d9f0 100644 --- a/msgmempool.go +++ b/msgmempool.go @@ -21,8 +21,9 @@ type MsgMemPool struct{} // This is part of the Message interface implementation. func (msg *MsgMemPool) BtcDecode(r io.Reader, pver uint32) error { if pver < BIP0035Version { - err := fmt.Errorf("mempool message invalid for protocol version: %d", pver) - return err + str := fmt.Sprintf("mempool message invalid for protocol "+ + "version %d", pver) + return messageError("MsgMemPool.BtcDecode", str) } return nil @@ -32,8 +33,9 @@ func (msg *MsgMemPool) BtcDecode(r io.Reader, pver uint32) error { // This is part of the Message interface implementation. func (msg *MsgMemPool) BtcEncode(w io.Writer, pver uint32) error { if pver < BIP0035Version { - err := fmt.Errorf("mempool message invalid for protocol version: %d", pver) - return err + str := fmt.Sprintf("mempool message invalid for protocol "+ + "version %d", pver) + return messageError("MsgMemPool.BtcEncode", str) } return nil From cbcbe5eb43793e2b8207c0587acb0b6a23da9ba0 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 02:23:45 -0500 Subject: [PATCH 048/219] Convert MsgVersion errors to MessageError type. --- msgversion.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/msgversion.go b/msgversion.go index d9b13e37..5330ca66 100644 --- a/msgversion.go +++ b/msgversion.go @@ -95,8 +95,9 @@ func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error { return err } if len(userAgent) > MaxUserAgentLen { - str := "MsgVersion.BtcDecode: user agent too long [max %v]" - return fmt.Errorf(str, MaxUserAgentLen) + str := fmt.Sprintf("user agent too long [len %v, max %v]", + len(userAgent), MaxUserAgentLen) + return messageError("MsgVersion.BtcDecode", str) } msg.UserAgent = userAgent @@ -112,8 +113,9 @@ func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error { // This is part of the Message interface implementation. func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32) error { if len(msg.UserAgent) > MaxUserAgentLen { - str := "MsgVersion.BtcEncode: user agent too long [max %v]" - return fmt.Errorf(str, MaxUserAgentLen) + str := fmt.Sprintf("user agent too long [len %v, max %v]", + len(msg.UserAgent), MaxUserAgentLen) + return messageError("MsgVersion.BtcEncode", str) } err := writeElements(w, msg.ProtocolVersion, msg.Services, From 20bebc13a5d2c14266cc80d2bac646475ca4b5e8 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 02:29:11 -0500 Subject: [PATCH 049/219] Convert WriteMessage errors to MessgeError type. --- message.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/message.go b/message.go index 13d0d77a..f1ee1f4f 100644 --- a/message.go +++ b/message.go @@ -160,8 +160,9 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro cmd := msg.Command() if len(cmd) > commandSize { - str := "WriteMessage: command is too long [%s]" - return fmt.Errorf(str, command) + str := fmt.Sprintf("command [%s] is too long [max %v]", + cmd, commandSize) + return messageError("WriteMessage", str) } copy(command[:], []byte(cmd)) From 2a2745d0d3acf1ae6c2ecbcac2e21b02f55ae50f Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 10:52:22 -0500 Subject: [PATCH 050/219] Add negative tests for MsgGetHeaders. This commit adds tests for the error paths when encoded and decoding MsgHeaders. Also, while here modify the casing of the local vars to be consistent. --- msggetheaders_test.go | 213 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 173 insertions(+), 40 deletions(-) diff --git a/msggetheaders_test.go b/msggetheaders_test.go index 86a0f8f5..063ad2d4 100644 --- a/msggetheaders_test.go +++ b/msggetheaders_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" ) @@ -70,7 +71,9 @@ func TestGetHeaders(t *testing.T) { // TestGetHeadersWire tests the MsgGetHeaders wire encode and decode for various // numbers of block locator hashes and protocol versions. func TestGetHeadersWire(t *testing.T) { - // Set protocol inside getheaders message. + // Set protocol inside getheaders message. Use protocol version 60002 + // specifically here instead of the latest because the test data is + // using bytes encoded with that protocol version. pver := uint32(60002) // Block 99499 hash. @@ -95,9 +98,9 @@ func TestGetHeadersWire(t *testing.T) { } // MsgGetHeaders message with no block locators or stop hash. - NoLocators := btcwire.NewMsgGetHeaders() - NoLocators.ProtocolVersion = pver - NoLocatorsEncoded := []byte{ + noLocators := btcwire.NewMsgGetHeaders() + noLocators.ProtocolVersion = pver + noLocatorsEncoded := []byte{ 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 0x00, // Varint for number of block locator hashes 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -107,12 +110,12 @@ func TestGetHeadersWire(t *testing.T) { } // MsgGetHeaders message with multiple block locators and a stop hash. - MultiLocators := btcwire.NewMsgGetHeaders() - MultiLocators.ProtocolVersion = pver - MultiLocators.HashStop = *hashStop - MultiLocators.AddBlockLocatorHash(hashLocator2) - MultiLocators.AddBlockLocatorHash(hashLocator) - MultiLocatorsEncoded := []byte{ + multiLocators := btcwire.NewMsgGetHeaders() + multiLocators.ProtocolVersion = pver + multiLocators.HashStop = *hashStop + multiLocators.AddBlockLocatorHash(hashLocator2) + multiLocators.AddBlockLocatorHash(hashLocator) + multiLocatorsEncoded := []byte{ 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 0x02, // Varint for number of block locator hashes 0xe0, 0xde, 0x06, 0x44, 0x68, 0x13, 0x2c, 0x63, @@ -137,81 +140,81 @@ func TestGetHeadersWire(t *testing.T) { }{ // Latest protocol version with no block locators. { - NoLocators, - NoLocators, - NoLocatorsEncoded, + noLocators, + noLocators, + noLocatorsEncoded, btcwire.ProtocolVersion, }, // Latest protocol version with multiple block locators. { - MultiLocators, - MultiLocators, - MultiLocatorsEncoded, + multiLocators, + multiLocators, + multiLocatorsEncoded, btcwire.ProtocolVersion, }, // Protocol version BIP0035Version with no block locators. { - NoLocators, - NoLocators, - NoLocatorsEncoded, + noLocators, + noLocators, + noLocatorsEncoded, btcwire.BIP0035Version, }, // Protocol version BIP0035Version with multiple block locators. { - MultiLocators, - MultiLocators, - MultiLocatorsEncoded, + multiLocators, + multiLocators, + multiLocatorsEncoded, btcwire.BIP0035Version, }, // Protocol version BIP0031Version with no block locators. { - NoLocators, - NoLocators, - NoLocatorsEncoded, + noLocators, + noLocators, + noLocatorsEncoded, btcwire.BIP0031Version, }, // Protocol version BIP0031Versionwith multiple block locators. { - MultiLocators, - MultiLocators, - MultiLocatorsEncoded, + multiLocators, + multiLocators, + multiLocatorsEncoded, btcwire.BIP0031Version, }, // Protocol version NetAddressTimeVersion with no block locators. { - NoLocators, - NoLocators, - NoLocatorsEncoded, + noLocators, + noLocators, + noLocatorsEncoded, btcwire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion multiple block locators. { - MultiLocators, - MultiLocators, - MultiLocatorsEncoded, + multiLocators, + multiLocators, + multiLocatorsEncoded, btcwire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion with no block locators. { - NoLocators, - NoLocators, - NoLocatorsEncoded, + noLocators, + noLocators, + noLocatorsEncoded, btcwire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion multiple block locators. { - MultiLocators, - MultiLocators, - MultiLocatorsEncoded, + multiLocators, + multiLocators, + multiLocatorsEncoded, btcwire.MultipleAddressVersion, }, } @@ -246,3 +249,133 @@ func TestGetHeadersWire(t *testing.T) { } } } + +// TestGetHeadersWireErrors performs negative tests against wire encode and +// decode of MsgGetHeaders to confirm error paths work correctly. +func TestGetHeadersWireErrors(t *testing.T) { + // Set protocol inside getheaders message. Use protocol version 60002 + // specifically here instead of the latest because the test data is + // using bytes encoded with that protocol version. + pver := uint32(60002) + btcwireErr := &btcwire.MessageError{} + + // Block 99499 hash. + hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535" + hashLocator, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Block 99500 hash. + hashStr = "2e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" + hashLocator2, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Block 100000 hash. + hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" + hashStop, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // MsgGetHeaders message with multiple block locators and a stop hash. + baseGetHeaders := btcwire.NewMsgGetHeaders() + baseGetHeaders.ProtocolVersion = pver + baseGetHeaders.HashStop = *hashStop + baseGetHeaders.AddBlockLocatorHash(hashLocator2) + baseGetHeaders.AddBlockLocatorHash(hashLocator) + baseGetHeadersEncoded := []byte{ + 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 + 0x02, // Varint for number of block locator hashes + 0xe0, 0xde, 0x06, 0x44, 0x68, 0x13, 0x2c, 0x63, + 0xd2, 0x20, 0xcc, 0x69, 0x12, 0x83, 0xcb, 0x65, + 0xbc, 0xaa, 0xe4, 0x79, 0x94, 0xef, 0x9e, 0x7b, + 0xad, 0xe7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99500 hash + 0x35, 0x75, 0x95, 0xb7, 0xf6, 0x8c, 0xb1, 0x60, + 0xcc, 0xba, 0x2c, 0x9a, 0xc5, 0x42, 0x5f, 0xd9, + 0x6f, 0x0a, 0x01, 0x3d, 0xc9, 0x7e, 0xc8, 0x40, + 0x0f, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99499 hash + 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39, + 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2, + 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa, + 0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // Hash stop + } + + // Message that forces an error by having more than the max allowed + // block locator hashes. + maxGetHeaders := btcwire.NewMsgGetHeaders() + for i := 0; i < btcwire.MaxBlockLocatorsPerMsg; i++ { + maxGetHeaders.AddBlockLocatorHash(&btcwire.GenesisHash) + } + maxGetHeaders.BlockLocatorHashes = append(maxGetHeaders.BlockLocatorHashes, + &btcwire.GenesisHash) + //maxGetHeaders.InvList = append(maxGetData.InvList, iv) + maxGetHeadersEncoded := []byte{ + 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 + 0xfd, 0xf5, 0x01, // Varint for number of block loc hashes (501) + } + + tests := []struct { + in *btcwire.MsgGetHeaders // 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 protocol version. + {baseGetHeaders, baseGetHeadersEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in block locator hash count. + {baseGetHeaders, baseGetHeadersEncoded, pver, 4, io.ErrShortWrite, io.EOF}, + // Force error in block locator hashes. + {baseGetHeaders, baseGetHeadersEncoded, pver, 5, io.ErrShortWrite, io.EOF}, + // Force error in stop hash. + {baseGetHeaders, baseGetHeadersEncoded, pver, 69, io.ErrShortWrite, io.EOF}, + // Force error with greater than max block locator hashes. + {maxGetHeaders, maxGetHeadersEncoded, pver, 7, 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.MsgGetHeaders + 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("BtcEncode #%d wrong error got: %v, "+ + "want: %v", i, err, test.readErr) + continue + } + } + } +} From 61b86b1bb582dfb9bea2cf331a960240f253db13 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 11:06:52 -0500 Subject: [PATCH 051/219] Add negative tests for MsgGetBlocks. This commit adds tests for the error paths when encoded and decoding MsgGetBlocks. --- msggetblocks_test.go | 129 +++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 68 +++++++++++------------ 2 files changed, 163 insertions(+), 34 deletions(-) diff --git a/msggetblocks_test.go b/msggetblocks_test.go index 4c8c972f..49cdb42a 100644 --- a/msggetblocks_test.go +++ b/msggetblocks_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" ) @@ -258,3 +259,131 @@ func TestGetBlocksWire(t *testing.T) { } } } + +// TestGetBlocksWireErrors performs negative tests against wire encode and +// decode of MsgGetBlocks to confirm error paths work correctly. +func TestGetBlocksWireErrors(t *testing.T) { + // Set protocol inside getheaders message. Use protocol version 60002 + // specifically here instead of the latest because the test data is + // using bytes encoded with that protocol version. + pver := uint32(60002) + btcwireErr := &btcwire.MessageError{} + + // Block 99499 hash. + hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535" + hashLocator, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Block 99500 hash. + hashStr = "2e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" + hashLocator2, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // Block 100000 hash. + hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" + hashStop, err := btcwire.NewShaHashFromStr(hashStr) + if err != nil { + t.Errorf("NewShaHashFromStr: %v", err) + } + + // MsgGetBlocks message with multiple block locators and a stop hash. + baseGetBlocks := btcwire.NewMsgGetBlocks(hashStop) + baseGetBlocks.ProtocolVersion = pver + baseGetBlocks.AddBlockLocatorHash(hashLocator2) + baseGetBlocks.AddBlockLocatorHash(hashLocator) + baseGetBlocksEncoded := []byte{ + 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 + 0x02, // Varint for number of block locator hashes + 0xe0, 0xde, 0x06, 0x44, 0x68, 0x13, 0x2c, 0x63, + 0xd2, 0x20, 0xcc, 0x69, 0x12, 0x83, 0xcb, 0x65, + 0xbc, 0xaa, 0xe4, 0x79, 0x94, 0xef, 0x9e, 0x7b, + 0xad, 0xe7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99500 hash + 0x35, 0x75, 0x95, 0xb7, 0xf6, 0x8c, 0xb1, 0x60, + 0xcc, 0xba, 0x2c, 0x9a, 0xc5, 0x42, 0x5f, 0xd9, + 0x6f, 0x0a, 0x01, 0x3d, 0xc9, 0x7e, 0xc8, 0x40, + 0x0f, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 99499 hash + 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39, + 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2, + 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa, + 0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // Hash stop + } + + // Message that forces an error by having more than the max allowed + // block locator hashes. + maxGetBlocks := btcwire.NewMsgGetBlocks(hashStop) + for i := 0; i < btcwire.MaxBlockLocatorsPerMsg; i++ { + maxGetBlocks.AddBlockLocatorHash(&btcwire.GenesisHash) + } + maxGetBlocks.BlockLocatorHashes = append(maxGetBlocks.BlockLocatorHashes, + &btcwire.GenesisHash) + maxGetBlocksEncoded := []byte{ + 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 + 0xfd, 0xf5, 0x01, // Varint for number of block loc hashes (501) + } + + tests := []struct { + in *btcwire.MsgGetBlocks // 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 protocol version. + {baseGetBlocks, baseGetBlocksEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in block locator hash count. + {baseGetBlocks, baseGetBlocksEncoded, pver, 4, io.ErrShortWrite, io.EOF}, + // Force error in block locator hashes. + {baseGetBlocks, baseGetBlocksEncoded, pver, 5, io.ErrShortWrite, io.EOF}, + // Force error in stop hash. + {baseGetBlocks, baseGetBlocksEncoded, pver, 69, io.ErrShortWrite, io.EOF}, + // Force error with greater than max block locator hashes. + {maxGetBlocks, maxGetBlocksEncoded, pver, 7, 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.MsgGetBlocks + 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("BtcEncode #%d wrong error got: %v, "+ + "want: %v", i, err, test.readErr) + continue + } + } + } +} diff --git a/test_coverage.txt b/test_coverage.txt index d2e4e5c2..4653d9c5 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -4,62 +4,66 @@ github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) +github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) @@ -134,20 +138,16 @@ github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) -github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 68.42% (13/19) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 68.42% (13/19) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 66.67% (12/18) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 66.67% (12/18) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 89.28% (833/933) +github.com/conformal/btcwire --------------------------------- 91.85% (857/933) From 3d303feefba1839c8665fedc32570286a819c0d7 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 11:19:46 -0500 Subject: [PATCH 052/219] Add negative test for NewShaHash. This commit adds a test to ensure NewShaHash fails as expected when the passed buffer has too many bytes to be a valid sha hash. --- shahash_test.go | 7 ++++++ test_coverage.txt | 62 +++++++++++++++++++++++------------------------ 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/shahash_test.go b/shahash_test.go index ea143507..e99f4542 100644 --- a/shahash_test.go +++ b/shahash_test.go @@ -67,6 +67,13 @@ func TestShaHash(t *testing.T) { if err == nil { t.Errorf("SetBytes: failed to received expected err - got: nil") } + + // Invalid size for NewShaHash. + invalidHash := make([]byte, btcwire.HashSize+1) + _, err = btcwire.NewShaHash(invalidHash) + if err == nil { + t.Errorf("NewShaHash: failed to received expected err - got: nil") + } } // TestShaHashString tests the stringized output for sha hashes. diff --git a/test_coverage.txt b/test_coverage.txt index 4653d9c5..68d52699 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -2,70 +2,71 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) -github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) +github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) @@ -134,13 +135,12 @@ github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) -github.com/conformal/btcwire/shahash.go NewShaHash 80.00% (4/5) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) @@ -149,5 +149,5 @@ github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 91.85% (857/933) +github.com/conformal/btcwire --------------------------------- 91.96% (858/933) From 93070ef9605721034006485e5bc66868437ec2d6 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 12:49:22 -0500 Subject: [PATCH 053/219] Add negative tests for MsgAlert. This commit adds tests for the error paths when encoding and decoding MsgAlert. --- msgalert_test.go | 76 +++++++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 62 +++++++++++++++++++------------------- 2 files changed, 107 insertions(+), 31 deletions(-) diff --git a/msgalert_test.go b/msgalert_test.go index b2b2d8c6..99e602a1 100644 --- a/msgalert_test.go +++ b/msgalert_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" ) @@ -137,3 +138,78 @@ func TestAlertWire(t *testing.T) { } } } + +// TestAlertWireErrors performs negative tests against wire encode and decode +// of MsgAlert to confirm error paths work correctly. +func TestAlertWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + + baseAlert := btcwire.NewMsgAlert("some payload", "somesig") + baseAlertEncoded := []byte{ + 0x0c, // Varint for payload length + 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, // "some payload" + 0x07, // Varint for signature length + 0x73, 0x6f, 0x6d, 0x65, 0x73, 0x69, 0x67, // "somesig" + } + + tests := []struct { + in *btcwire.MsgAlert // 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 payload length. + {baseAlert, baseAlertEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in payload. + {baseAlert, baseAlertEncoded, pver, 1, io.ErrShortWrite, io.EOF}, + // Force error in signature length. + {baseAlert, baseAlertEncoded, pver, 13, io.ErrShortWrite, io.EOF}, + // Force error in signature. + {baseAlert, baseAlertEncoded, pver, 14, 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 := 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.MsgAlert + 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 + } + } + } +} diff --git a/test_coverage.txt b/test_coverage.txt index 68d52699..51f2138e 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -4,8 +4,8 @@ github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) @@ -14,59 +14,61 @@ github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) @@ -138,9 +140,7 @@ github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 75.00% (6/8) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 75.00% (6/8) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) @@ -149,5 +149,5 @@ github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 91.96% (858/933) +github.com/conformal/btcwire --------------------------------- 92.39% (862/933) From 7385f6ff24af8215bd058f99e9852935b5d2c9e4 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 12:55:50 -0500 Subject: [PATCH 054/219] Correct several test error messages. --- msgaddr_test.go | 2 +- msggetblocks_test.go | 2 +- msggetdata_test.go | 3 +-- msggetheaders_test.go | 2 +- msgheaders_test.go | 2 +- msginv_test.go | 2 +- msgnotfound_test.go | 3 +-- msgpong_test.go | 2 +- 8 files changed, 8 insertions(+), 10 deletions(-) diff --git a/msgaddr_test.go b/msgaddr_test.go index dd147b23..32790211 100644 --- a/msgaddr_test.go +++ b/msgaddr_test.go @@ -310,7 +310,7 @@ func TestAddrWireErrors(t *testing.T) { // them for equality. if _, ok := err.(*btcwire.MessageError); !ok { if err != test.readErr { - t.Errorf("BtcEncode #%d wrong error got: %v, "+ + t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) continue } diff --git a/msggetblocks_test.go b/msggetblocks_test.go index 49cdb42a..8420f15b 100644 --- a/msggetblocks_test.go +++ b/msggetblocks_test.go @@ -380,7 +380,7 @@ func TestGetBlocksWireErrors(t *testing.T) { // them for equality. if _, ok := err.(*btcwire.MessageError); !ok { if err != test.readErr { - t.Errorf("BtcEncode #%d wrong error got: %v, "+ + t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) continue } diff --git a/msggetdata_test.go b/msggetdata_test.go index bfa31e20..47822e68 100644 --- a/msggetdata_test.go +++ b/msggetdata_test.go @@ -312,11 +312,10 @@ func TestGetDataWireErrors(t *testing.T) { // them for equality. if _, ok := err.(*btcwire.MessageError); !ok { if err != test.readErr { - t.Errorf("BtcEncode #%d wrong error got: %v, "+ + t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) continue } } - } } diff --git a/msggetheaders_test.go b/msggetheaders_test.go index 063ad2d4..1a1210db 100644 --- a/msggetheaders_test.go +++ b/msggetheaders_test.go @@ -372,7 +372,7 @@ func TestGetHeadersWireErrors(t *testing.T) { // them for equality. if _, ok := err.(*btcwire.MessageError); !ok { if err != test.readErr { - t.Errorf("BtcEncode #%d wrong error got: %v, "+ + t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) continue } diff --git a/msgheaders_test.go b/msgheaders_test.go index 07a58b3b..e3142f98 100644 --- a/msgheaders_test.go +++ b/msgheaders_test.go @@ -338,7 +338,7 @@ func TestHeadersWireErrors(t *testing.T) { // them for equality. if _, ok := err.(*btcwire.MessageError); !ok { if err != test.readErr { - t.Errorf("BtcEncode #%d wrong error got: %v, "+ + t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) continue } diff --git a/msginv_test.go b/msginv_test.go index 056269d2..6d0c9460 100644 --- a/msginv_test.go +++ b/msginv_test.go @@ -312,7 +312,7 @@ func TestInvWireErrors(t *testing.T) { // them for equality. if _, ok := err.(*btcwire.MessageError); !ok { if err != test.readErr { - t.Errorf("BtcEncode #%d wrong error got: %v, "+ + t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) continue } diff --git a/msgnotfound_test.go b/msgnotfound_test.go index b5c411ab..48741094 100644 --- a/msgnotfound_test.go +++ b/msgnotfound_test.go @@ -312,11 +312,10 @@ func TestNotFoundWireErrors(t *testing.T) { // them for equality. if _, ok := err.(*btcwire.MessageError); !ok { if err != test.readErr { - t.Errorf("BtcEncode #%d wrong error got: %v, "+ + t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) continue } } - } } diff --git a/msgpong_test.go b/msgpong_test.go index 21bdf198..81be02c3 100644 --- a/msgpong_test.go +++ b/msgpong_test.go @@ -265,7 +265,7 @@ func TestPongWireErrors(t *testing.T) { // them for equality. if _, ok := err.(*btcwire.MessageError); !ok { if err != test.readErr { - t.Errorf("BtcEncode #%d wrong error got: %v, "+ + t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) continue } From 0400d0cec317824cd9bbaa85c7de75d1c82a0127 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 23:22:09 -0500 Subject: [PATCH 055/219] Remove dead error check in WriteMessage. The io.Writer.Write function always returns an error if the bytes written is less than provided, so there is no reason to further check if the payload length matches after a successful write. --- message.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/message.go b/message.go index f1ee1f4f..80b748a9 100644 --- a/message.go +++ b/message.go @@ -196,15 +196,10 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro } // Write payload. - n, err := w.Write(payload) + _, err = w.Write(payload) if err != nil { return err } - if n != lenp { - str := fmt.Sprintf("failed to write payload - wrote %v bytes, "+ - "payload size is %v bytes", n, lenp) - return messageError("WriteMessage", str) - } return nil } From c9d2dfea3d509418a16fe1515c7960158a6d3260 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 11 May 2013 23:32:20 -0500 Subject: [PATCH 056/219] Add negative tests for WriteMessage. This commit adds tests for the error paths when writing a message to the wire. --- fakemessage_test.go | 28 +++++++++++++------ message_test.go | 63 +++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 66 ++++++++++++++++++++++----------------------- 3 files changed, 116 insertions(+), 41 deletions(-) diff --git a/fakemessage_test.go b/fakemessage_test.go index 3288d93e..36eac01a 100644 --- a/fakemessage_test.go +++ b/fakemessage_test.go @@ -5,14 +5,16 @@ package btcwire_test import ( + "github.com/conformal/btcwire" "io" ) // fakeMessage implements the btcwire.Message interface and is used to force -// errors. +// encode errors in messages. type fakeMessage struct { - command string - maxPayload uint32 + command string + payload []byte + forceEncodeErr bool } // BtcDecode doesn't do anything. It just satisfies the btcwire.Message @@ -21,10 +23,20 @@ func (msg *fakeMessage) BtcDecode(r io.Reader, pver uint32) error { return nil } -// BtcEncode doesn't do anything. It just satisfies the btcwire.Message -// interface. +// BtcEncode writes the payload field of the fake message or forces an error +// if the forceEncodeErr flag of the fake message is set. It also satisfies the +// btcwire.Message interface. func (msg *fakeMessage) BtcEncode(w io.Writer, pver uint32) error { - return nil + if msg.forceEncodeErr { + err := &btcwire.MessageError{ + Func: "fakeMessage.BtcEncode", + Description: "intentional error", + } + return err + } + + _, err := w.Write(msg.payload) + return err } // Command returns the command field of the fake message and satisfies the @@ -33,8 +45,8 @@ func (msg *fakeMessage) Command() string { return msg.command } -// Command returns the maxPayload field of the fake message and satisfies the +// MaxPayloadLength simply returns 0. It is only here to satisfy the // btcwire.Message interface. func (msg *fakeMessage) MaxPayloadLength(pver uint32) uint32 { - return msg.maxPayload + return 0 } diff --git a/message_test.go b/message_test.go index ea0cd182..e3483fc2 100644 --- a/message_test.go +++ b/message_test.go @@ -303,3 +303,66 @@ func TestReadMessageWireErrors(t *testing.T) { } } } + +// TestWriteMessageWireErrors performs negative tests against wire encoding from +// concrete messages to confirm error paths work correctly. +func TestWriteMessageWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + btcnet := btcwire.MainNet + btcwireErr := &btcwire.MessageError{} + + // Fake message with a command that is too long. + badCommandMsg := &fakeMessage{command: "somethingtoolong"} + + // Fake message with a problem during encoding + encodeErrMsg := &fakeMessage{forceEncodeErr: true} + + // Fake message that has a payload which exceed max. + exceedPayload := make([]byte, btcwire.MaxMessagePayload+1) + exceedPayloadErrMsg := &fakeMessage{payload: exceedPayload} + + bogusPayload := []byte{0x01, 0x02, 0x03, 0x04} + bogusMsg := &fakeMessage{command: "bogus", payload: bogusPayload} + + tests := []struct { + msg btcwire.Message // Message to encode + pver uint32 // Protocol version for wire encoding + btcnet btcwire.BitcoinNet // Bitcoin network for wire encoding + max int // Max size of fixed buffer to induce errors + err error // Expected error + }{ + // Command too long. + {badCommandMsg, pver, btcnet, 0, btcwireErr}, + // Force error in payload encode. + {encodeErrMsg, pver, btcnet, 0, btcwireErr}, + // Force error due to exceeding max payload size. + {exceedPayloadErrMsg, pver, btcnet, 0, btcwireErr}, + // Force error in header write. + {bogusMsg, pver, btcnet, 0, io.ErrShortWrite}, + // Force error in payload write. + {bogusMsg, pver, btcnet, 24, io.ErrShortWrite}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Encode wire format. + w := newFixedWriter(test.max) + err := btcwire.WriteMessage(w, test.msg, test.pver, test.btcnet) + if reflect.TypeOf(err) != reflect.TypeOf(test.err) { + t.Errorf("WriteMessage #%d wrong error got: %v <%T>, "+ + "want: %T", i, err, err, test.err) + continue + } + + // For errors which are not of type btcwire.MessageError, check + // them for equality. + if _, ok := err.(*btcwire.MessageError); !ok { + if err != test.err { + t.Errorf("ReadMessage #%d wrong error got: %v <%T>, "+ + "want: %v <%T>", i, err, err, + test.err, test.err) + continue + } + } + } +} diff --git a/test_coverage.txt b/test_coverage.txt index 51f2138e..6ce16682 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,74 +1,75 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) +github.com/conformal/btcwire/message.go WriteMessage 100.00% (27/27) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) @@ -141,13 +142,12 @@ github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) -github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) -github.com/conformal/btcwire/message.go WriteMessage 70.00% (21/30) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 92.39% (862/933) +github.com/conformal/btcwire --------------------------------- 93.33% (868/930) From 4e16030fe8cf66fbecd63da45ef81058fd35f9df Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 12 May 2013 11:50:31 -0500 Subject: [PATCH 057/219] Add tests for MsgBlock transaction location decode. --- msgblock_test.go | 40 +++++++++++++++++++++++++++++++++++----- test_coverage.txt | 4 ++-- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index ca9f8eac..2cfffe74 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -124,16 +124,18 @@ func TestBlockSha(t *testing.T) { // of transaction inputs and outputs and protocol versions. func TestBlockWire(t *testing.T) { tests := []struct { - in *btcwire.MsgBlock // Message to encode - out *btcwire.MsgBlock // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *btcwire.MsgBlock // Message to encode + out *btcwire.MsgBlock // Expected decoded message + buf []byte // Wire encoding + txLocs []btcwire.TxLoc // Expected transaction locations + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { &blockOne, &blockOne, blockOneBytes, + blockOneTxLocs, btcwire.ProtocolVersion, }, @@ -142,6 +144,7 @@ func TestBlockWire(t *testing.T) { &blockOne, &blockOne, blockOneBytes, + blockOneTxLocs, btcwire.BIP0035Version, }, @@ -150,6 +153,7 @@ func TestBlockWire(t *testing.T) { &blockOne, &blockOne, blockOneBytes, + blockOneTxLocs, btcwire.BIP0031Version, }, @@ -158,6 +162,7 @@ func TestBlockWire(t *testing.T) { &blockOne, &blockOne, blockOneBytes, + blockOneTxLocs, btcwire.NetAddressTimeVersion, }, @@ -166,6 +171,7 @@ func TestBlockWire(t *testing.T) { &blockOne, &blockOne, blockOneBytes, + blockOneTxLocs, btcwire.MultipleAddressVersion, }, } @@ -198,6 +204,24 @@ func TestBlockWire(t *testing.T) { spew.Sdump(&msg), spew.Sdump(test.out)) continue } + + var txLocMsg btcwire.MsgBlock + rbuf = bytes.NewBuffer(test.buf) + txLocs, err := txLocMsg.BtcDecodeTxLoc(rbuf, test.pver) + if err != nil { + t.Errorf("BtcDecodeTxLoc #%d error %v", i, err) + continue + } + if !reflect.DeepEqual(&txLocMsg, test.out) { + t.Errorf("BtcDecodeTxLoc #%d\n got: %s want: %s", i, + spew.Sdump(&txLocMsg), spew.Sdump(test.out)) + continue + } + if !reflect.DeepEqual(txLocs, test.txLocs) { + t.Errorf("BtcDecodeTxLoc #%d\n got: %s want: %s", i, + spew.Sdump(txLocs), spew.Sdump(test.txLocs)) + continue + } } } @@ -318,7 +342,7 @@ var blockOne btcwire.MsgBlock = btcwire.MsgBlock{ }, } -// Bytes encoded with protocol version 60002. +// Block one bytes encoded with protocol version 60002. var blockOneBytes = []byte{ 0x01, 0x00, 0x00, 0x00, // Version 1 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, @@ -359,3 +383,9 @@ var blockOneBytes = []byte{ 0xac, // OP_CHECKSIG 0x00, 0x00, 0x00, 0x00, // Lock time } + +// Transaction location information for block one trasnactions as encoded with +// protocol version 60002. +var blockOneTxLocs = []btcwire.TxLoc{ + btcwire.TxLoc{TxStart: 81, TxLen: 134}, +} diff --git a/test_coverage.txt b/test_coverage.txt index 6ce16682..945e01ed 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -135,6 +135,7 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00 github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 87.50% (14/16) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) @@ -148,6 +149,5 @@ github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 0.00% (0/16) -github.com/conformal/btcwire --------------------------------- 93.33% (868/930) +github.com/conformal/btcwire --------------------------------- 94.84% (882/930) From 0e033023bf585394209234b5af6dbce3efc586cf Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 12 May 2013 12:43:01 -0500 Subject: [PATCH 058/219] Improve MsgBlock negative tests. Rather than decoding from a zero-filled buffer, use valid block encoded test data. --- msgblock_test.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index 2cfffe74..0ad8ceb7 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -241,21 +241,20 @@ func TestBlockWireErrors(t *testing.T) { writeErr error // Expected write error readErr error // Expected read error }{ - // Latest protocol version with intentional read/write errors. // Force error in version. - {&blockOne, []byte{}, pver, 0, io.ErrShortWrite, io.EOF}, + {&blockOne, blockOneBytes, pver, 0, io.ErrShortWrite, io.EOF}, // Force error in prev block hash. - {&blockOne, []byte{}, pver, 4, io.ErrShortWrite, io.EOF}, + {&blockOne, blockOneBytes, pver, 4, io.ErrShortWrite, io.EOF}, // Force error in merkle root. - {&blockOne, []byte{}, pver, 36, io.ErrShortWrite, io.EOF}, + {&blockOne, blockOneBytes, pver, 36, io.ErrShortWrite, io.EOF}, // Force error in timestamp. - {&blockOne, []byte{}, pver, 68, io.ErrShortWrite, io.EOF}, + {&blockOne, blockOneBytes, pver, 68, io.ErrShortWrite, io.EOF}, // Force error in difficulty bits. - {&blockOne, []byte{}, pver, 72, io.ErrShortWrite, io.EOF}, + {&blockOne, blockOneBytes, pver, 72, io.ErrShortWrite, io.EOF}, // Force error in header nonce. - {&blockOne, []byte{}, pver, 76, io.ErrShortWrite, io.EOF}, + {&blockOne, blockOneBytes, pver, 76, io.ErrShortWrite, io.EOF}, // Force error in transaction count. - {&blockOne, []byte{}, pver, 80, io.ErrShortWrite, io.EOF}, + {&blockOne, blockOneBytes, pver, 80, io.ErrShortWrite, io.EOF}, // Force error in transactions. {&blockOne, blockOneBytes, pver, 81, io.ErrShortWrite, io.EOF}, } From 1ca8015ea0e639b78c9ad55b63047e47e228b447 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 12 May 2013 12:47:43 -0500 Subject: [PATCH 059/219] Add negative tests for MsgBlock tx location decode. This commit adds tests for the error paths when decoding MsgBlock via the transaction location decode variant. --- msgblock_test.go | 9 +++++ test_coverage.txt | 84 +++++++++++++++++++++++------------------------ 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index 0ad8ceb7..bd5082a5 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -279,6 +279,15 @@ func TestBlockWireErrors(t *testing.T) { i, err, test.readErr) continue } + + var txLocMsg btcwire.MsgBlock + rbuf := bytes.NewBuffer(test.buf[0:test.max]) + _, err = txLocMsg.BtcDecodeTxLoc(rbuf, test.pver) + if err != test.readErr { + t.Errorf("BtcDecodeTxLoc #%d wrong error got: %v, want: %v", + i, err, test.readErr) + continue + } } } diff --git a/test_coverage.txt b/test_coverage.txt index 945e01ed..3fde17bf 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -3,73 +3,74 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/message.go WriteMessage 100.00% (27/27) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) -github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) +github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 100.00% (16/16) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) -github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) +github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) -github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) +github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) @@ -135,7 +136,6 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00 github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 87.50% (14/16) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) @@ -143,11 +143,11 @@ github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) -github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) -github.com/conformal/btcwire --------------------------------- 94.84% (882/930) +github.com/conformal/btcwire --------------------------------- 95.05% (884/930) From 1bab947596206109cbe2411af4145de95cf31081 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 12 May 2013 14:01:50 -0500 Subject: [PATCH 060/219] Remove a few dead error checks. The functions for generating transaction and block hashes contained a few error checks for conditions which could never fail without run-time panics. This commit removes those superfluous checks and adds explanatory comments. --- blockheader.go | 25 ++++++++------- msgblock.go | 11 +++---- msgtx.go | 22 ++++++++----- test_coverage.txt | 80 +++++++++++++++++++++++------------------------ 4 files changed, 73 insertions(+), 65 deletions(-) diff --git a/blockheader.go b/blockheader.go index b8456a42..3294d566 100644 --- a/blockheader.go +++ b/blockheader.go @@ -50,19 +50,22 @@ type BlockHeader struct { const blockHashLen = 80 // BlockSha computes the block identifier hash for the given block header. -func (h *BlockHeader) BlockSha(pver uint32) (sha ShaHash, err error) { +func (h *BlockHeader) BlockSha(pver uint32) (ShaHash, error) { + // Encode the header and run double sha256 everything prior to the + // number of transactions. Ignore the error returns since there is no + // way the encode could fail except being out of memory which would + // cause a run-time panic. Also, SetBytes can't fail here due to the + // fact DoubleSha256 always returns a []byte of the right size + // regardless of input. var buf bytes.Buffer - err = writeBlockHeader(&buf, pver, h) - if err != nil { - return - } + var sha ShaHash + _ = writeBlockHeader(&buf, pver, h) + _ = sha.SetBytes(DoubleSha256(buf.Bytes()[0:blockHashLen])) - err = sha.SetBytes(DoubleSha256(buf.Bytes()[0:blockHashLen])) - if err != nil { - return - } - - return + // Even though this function can't currently fail, it still returns + // a potential error to help future proof the API should a failure + // become possible. + return sha, nil } // NewBlockHeader returns a new BlockHeader using the provided previous block diff --git a/msgblock.go b/msgblock.go index c01929ab..b87496c2 100644 --- a/msgblock.go +++ b/msgblock.go @@ -73,8 +73,8 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32) error { } // BtcDecodeTxLoc decodes r using the bitcoin protocol encoding into the -// receiver and returns a slice containing the start and length each transaction -// within the raw data. +// receiver and returns a slice containing the start and length of each +// transaction within the raw data. func (msg *MsgBlock) BtcDecodeTxLoc(r *bytes.Buffer, pver uint32) ([]TxLoc, error) { var fullLen int fullLen = r.Len() @@ -144,10 +144,9 @@ func (msg *MsgBlock) BlockSha(pver uint32) (ShaHash, error) { func (msg *MsgBlock) TxShas(pver uint32) ([]ShaHash, error) { var shaList []ShaHash for _, tx := range msg.Transactions { - sha, err := tx.TxSha(pver) - if err != nil { - return nil, err - } + // Ignore error here since TxSha can't fail in the current + // implementation except due to run-time panics. + sha, _ := tx.TxSha(pver) shaList = append(shaList, sha) } return shaList, nil diff --git a/msgtx.go b/msgtx.go index 27110f0c..bda97f9d 100644 --- a/msgtx.go +++ b/msgtx.go @@ -87,15 +87,21 @@ func (msg *MsgTx) AddTxOut(to *TxOut) { // TxSha generates the ShaHash name for the transaction. func (tx *MsgTx) TxSha(pver uint32) (ShaHash, error) { - var txsha ShaHash - var wbuf bytes.Buffer - err := tx.BtcEncode(&wbuf, pver) - if err != nil { - return txsha, err - } - txsha.SetBytes(DoubleSha256(wbuf.Bytes())) + // Encode the transaction and calculate double sha256 on the result. + // Ignore the error returns since the only way the encode could fail + // is being out of memory or due to nil pointers, both of which would + // cause a run-time panic. Also, SetBytes can't fail here due to the + // fact DoubleSha256 always returns a []byte of the right size + // regardless of input. + var buf bytes.Buffer + var sha ShaHash + _ = tx.BtcEncode(&buf, pver) + _ = sha.SetBytes(DoubleSha256(buf.Bytes())) - return txsha, nil + // Even though this function can't currently fail, it still returns + // a potential error to help future proof the API should a failure + // become possible. + return sha, nil } // Copy creates a deep copy of a transaction so that the original does not get diff --git a/test_coverage.txt b/test_coverage.txt index 3fde17bf..87b8b131 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -3,84 +3,87 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/message.go WriteMessage 100.00% (27/27) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) -github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) +github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) -github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 100.00% (16/16) +github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) +github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) -github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) +github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) github.com/conformal/btcwire/error.go messageError 100.00% (1/1) -github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) @@ -136,18 +139,15 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00 github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 85.71% (6/7) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 85.71% (6/7) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 75.00% (6/8) github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) -github.com/conformal/btcwire --------------------------------- 95.05% (884/930) +github.com/conformal/btcwire --------------------------------- 95.45% (881/923) From 3aef93f442c9f4d6d5fc5b78336d49f76823e31d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 12 May 2013 20:56:30 -0500 Subject: [PATCH 061/219] Make MsgVersion test data available to all funcs. Rather than having to repeat the same data for positive and negative tests, make the same test data available to both. --- msgversion_test.go | 96 ++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/msgversion_test.go b/msgversion_test.go index f9071b84..7cc2f493 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -147,57 +147,6 @@ func TestVersion(t *testing.T) { // TestAlertWire tests the MsgAlert wire encode and decode for various protocol // versions. func TestVersionWire(t *testing.T) { - // baseNetAddrYou is used in the various tests as a baseline remote - // NetAddress. - baseNetAddrYou := btcwire.NetAddress{ - Timestamp: time.Time{}, // Zero value -- no timestamp in version - Services: btcwire.SFNodeNetwork, - IP: net.ParseIP("192.168.0.1"), - Port: 8333, - } - - // baseNetAddrMe is used in the various tests as a baseline local - // NetAddress. - baseNetAddrMe := btcwire.NetAddress{ - Timestamp: time.Time{}, // Zero value -- no timestamp in version - Services: btcwire.SFNodeNetwork, - IP: net.ParseIP("127.0.0.1"), - Port: 8333, - } - - // baseVersion is used in the various tests as a baseline version. - baseVersion := &btcwire.MsgVersion{ - ProtocolVersion: 60002, - Services: btcwire.SFNodeNetwork, - Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST) - AddrYou: baseNetAddrYou, - AddrMe: baseNetAddrMe, - Nonce: 123123, // 0x1e0f3 - UserAgent: "/btcdtest:0.0.1/", - LastBlock: 234234, // 0x392fa - } - - baseVersionEncoded := []byte{ - 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork - 0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp - // AddrYou -- No timestamp for NetAddress in version message - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01, // IP 192.168.0.1 - 0x20, 0x8d, // Port 8333 in big-endian - // AddrMe -- No timestamp for NetAddress in version message - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1 - 0x20, 0x8d, // Port 8333 in big-endian - 0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Nonce - 0x10, // Varint for user agent length - 0x2f, 0x62, 0x74, 0x63, 0x64, 0x74, 0x65, 0x73, - 0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent - 0xfa, 0x92, 0x03, 0x00, // Last block - } - tests := []struct { in *btcwire.MsgVersion // Message to encode out *btcwire.MsgVersion // Expected decoded message @@ -275,3 +224,48 @@ func TestVersionWire(t *testing.T) { } } } + +// baseVersion is used in the various tests as a baseline MsgVersion. +var baseVersion *btcwire.MsgVersion = &btcwire.MsgVersion{ + ProtocolVersion: 60002, + Services: btcwire.SFNodeNetwork, + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST) + AddrYou: btcwire.NetAddress{ + Timestamp: time.Time{}, // Zero value -- no timestamp in version + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("192.168.0.1"), + Port: 8333, + }, + AddrMe: btcwire.NetAddress{ + Timestamp: time.Time{}, // Zero value -- no timestamp in version + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("127.0.0.1"), + Port: 8333, + }, + Nonce: 123123, // 0x1e0f3 + UserAgent: "/btcdtest:0.0.1/", + LastBlock: 234234, // 0x392fa +} + +// baseVersionEncoded is the wire encoded bytes for baseVersion using protocol +// version 60002 and is used in the various tests. +var baseVersionEncoded []byte = []byte{ + 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp + // AddrYou -- No timestamp for NetAddress in version message + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01, // IP 192.168.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + // AddrMe -- No timestamp for NetAddress in version message + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + 0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Nonce + 0x10, // Varint for user agent length + 0x2f, 0x62, 0x74, 0x63, 0x64, 0x74, 0x65, 0x73, + 0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent + 0xfa, 0x92, 0x03, 0x00, // Last block +} From f9b6375d5be12b0eabbd21c061edc824affc3d20 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 12 May 2013 21:47:36 -0500 Subject: [PATCH 062/219] Add negative tests for MsgVersion. This commit adds tests for the error paths when encoding and decoding MsgVersion. --- msgversion_test.go | 108 +++++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 62 +++++++++++++------------- 2 files changed, 139 insertions(+), 31 deletions(-) diff --git a/msgversion_test.go b/msgversion_test.go index 7cc2f493..cbb3bce4 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -8,8 +8,10 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "net" "reflect" + "strings" "testing" "time" ) @@ -225,6 +227,112 @@ func TestVersionWire(t *testing.T) { } } +// TestVersionWireErrors performs negative tests against wire encode and +// decode of MsgGetHeaders to confirm error paths work correctly. +func TestVersionWireErrors(t *testing.T) { + // Use protocol version 60002 specifically here instead of the latest + // because the test data is using bytes encoded with that protocol + // version. + pver := uint32(60002) + btcwireErr := &btcwire.MessageError{} + + // Copy the base version and change the user agent to exceed max limits. + bvc := *baseVersion + exceedUAVer := &bvc + newUA := "/" + strings.Repeat("t", btcwire.MaxUserAgentLen-8+1) + ":0.0.1/" + exceedUAVer.UserAgent = newUA + + // Encode the new UA length as a varint. + var newUAVarIntBuf bytes.Buffer + err := btcwire.TstWriteVarInt(&newUAVarIntBuf, pver, uint64(len(newUA))) + if err != nil { + t.Errorf("writeVarInt: error %v", err) + } + + // Make a new buffer big enough to hold the base version plus the new + // bytes for the bigger varint to hold the new size of the user agent + // and the new user agent string. Then stich it all together. + newLen := len(baseVersionEncoded) - len(baseVersion.UserAgent) + newLen = newLen + len(newUAVarIntBuf.Bytes()) - 1 + len(newUA) + exceedUAVerEncoded := make([]byte, newLen) + copy(exceedUAVerEncoded, baseVersionEncoded[0:80]) + copy(exceedUAVerEncoded[80:], newUAVarIntBuf.Bytes()) + copy(exceedUAVerEncoded[83:], []byte(newUA)) + copy(exceedUAVerEncoded[83+len(newUA):], baseVersionEncoded[97:100]) + + tests := []struct { + in *btcwire.MsgVersion // 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 protocol version. + {baseVersion, baseVersionEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in services. + {baseVersion, baseVersionEncoded, pver, 4, io.ErrShortWrite, io.EOF}, + // Force error in timestamp. + {baseVersion, baseVersionEncoded, pver, 12, io.ErrShortWrite, io.EOF}, + // Force error in remote address. + {baseVersion, baseVersionEncoded, pver, 20, io.ErrShortWrite, io.EOF}, + // Force error in local address. + {baseVersion, baseVersionEncoded, pver, 46, io.ErrShortWrite, io.EOF}, + // Force error in nonce. + {baseVersion, baseVersionEncoded, pver, 72, io.ErrShortWrite, io.EOF}, + // Force error in user agent length. + {baseVersion, baseVersionEncoded, pver, 80, io.ErrShortWrite, io.EOF}, + // Force error in user agent. + {baseVersion, baseVersionEncoded, pver, 81, io.ErrShortWrite, io.EOF}, + // Force error in last block. + {baseVersion, baseVersionEncoded, pver, 97, io.ErrShortWrite, io.EOF}, + // Force error due to user agent too big. + {exceedUAVer, exceedUAVerEncoded, pver, newLen, 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.MsgVersion + 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 + } + } + } +} + // baseVersion is used in the various tests as a baseline MsgVersion. var baseVersion *btcwire.MsgVersion = &btcwire.MsgVersion{ ProtocolVersion: 60002, diff --git a/test_coverage.txt b/test_coverage.txt index 87b8b131..77e4f0a0 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,10 +1,12 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/message.go WriteMessage 100.00% (27/27) +github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) -github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) +github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) +github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) @@ -12,35 +14,34 @@ github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 100.00% (16/16) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) +github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) -github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) @@ -48,33 +49,34 @@ github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) -github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) +github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) @@ -104,7 +106,6 @@ github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) @@ -139,15 +140,14 @@ github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00 github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) +github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) +github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) -github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 68.00% (17/25) -github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 63.64% (14/22) -github.com/conformal/btcwire --------------------------------- 95.45% (881/923) +github.com/conformal/btcwire --------------------------------- 97.18% (897/923) From 6f511eb75d9635d9dca34787899adab137fccc0a Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 13 May 2013 02:08:14 -0500 Subject: [PATCH 063/219] Make MsgTx test data available to all funcs. Rather than having to repeat the same data for positive and negative tests, make the same test data available to both. --- msgtx_test.go | 125 ++++++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 59 deletions(-) diff --git a/msgtx_test.go b/msgtx_test.go index 66449bd5..d813d52a 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -173,32 +173,6 @@ func TestTxSha(t *testing.T) { // TestTxWire tests the MsgTx wire encode and decode for various numbers // of transaction inputs and outputs and protocol versions. func TestTxWire(t *testing.T) { - // Previous transaction output point for coinbase to test. - prevOutIndex := uint32(0xffffffff) - prevOut := btcwire.NewOutPoint(&btcwire.ShaHash{}, prevOutIndex) - - // Transaction input to test. - sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62} - txIn := btcwire.NewTxIn(prevOut, sigScript) - txIn.Sequence = 0xffffffff - - // Transaction output to test. - txValue := int64(5000000000) - pkScript := []byte{ - 0x41, // OP_DATA_65 - 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, - 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, - 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, - 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, - 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, - 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, - 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, - 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, - 0xa6, // 65-byte signature - 0xac, // OP_CHECKSIG - } - txOut := btcwire.NewTxOut(txValue, pkScript) - // Empty tx message. noTx := btcwire.NewMsgTx() noTx.Version = 1 @@ -209,39 +183,6 @@ func TestTxWire(t *testing.T) { 0x00, 0x00, 0x00, 0x00, // Lock time } - multiTx := btcwire.NewMsgTx() - multiTx.Version = 1 - multiTx.AddTxIn(txIn) - multiTx.AddTxOut(txOut) - multiTx.LockTime = 0 - multiTxEncoded := []byte{ - 0x01, 0x00, 0x00, 0x00, // Version - 0x01, // Varint for number of input transactions - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash - 0xff, 0xff, 0xff, 0xff, // Prevous output index - 0x07, // Varint for length of signature script - 0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62, // Signature script - 0xff, 0xff, 0xff, 0xff, // Sequence - 0x01, // Varint for number of output transactions - 0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount - 0x43, // Varint for length of pk script - 0x41, // OP_DATA_65 - 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, - 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, - 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, - 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, - 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, - 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, - 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, - 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, - 0xa6, // 65-byte signature - 0xac, // OP_CHECKSIG - 0x00, 0x00, 0x00, 0x00, // Lock time - } - tests := []struct { in *btcwire.MsgTx // Message to encode out *btcwire.MsgTx // Expected decoded message @@ -359,3 +300,69 @@ func TestTxWire(t *testing.T) { } } } + +// multiTx is a MsgTx with an input and output and used in various tests. +var multiTx *btcwire.MsgTx = &btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + &btcwire.TxIn{ + PreviousOutpoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + 0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62, + }, + Sequence: 0xffffffff, + }, + }, + TxOut: []*btcwire.TxOut{ + &btcwire.TxOut{ + Value: 0x12a05f200, + PkScript: []byte{ + 0x41, // OP_DATA_65 + 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, + 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, + 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, + 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, + 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, + 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, + 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, + 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, + 0xa6, // 65-byte signature + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, +} + +// multiTxEncoded is the wire encoded bytes for multiTx using protocol version +// 60002 and is used in the various tests. +var multiTxEncoded []byte = []byte{ + 0x01, 0x00, 0x00, 0x00, // Version + 0x01, // Varint for number of input transactions + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash + 0xff, 0xff, 0xff, 0xff, // Prevous output index + 0x07, // Varint for length of signature script + 0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62, // Signature script + 0xff, 0xff, 0xff, 0xff, // Sequence + 0x01, // Varint for number of output transactions + 0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount + 0x43, // Varint for length of pk script + 0x41, // OP_DATA_65 + 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, + 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, + 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, + 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, + 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, + 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, + 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, + 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, + 0xa6, // 65-byte signature + 0xac, // OP_CHECKSIG + 0x00, 0x00, 0x00, 0x00, // Lock time +} From 5b78dee7e1aa11199fdd56a5621692c847c0de97 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 13 May 2013 02:09:55 -0500 Subject: [PATCH 064/219] Add negative tests for MsgTx. This commit adds tests for the error paths when encoding and decoding MsgTx. This commit also achieves 100% test coverage. --- msgtx_test.go | 68 ++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 76 +++++++++++++++++++++++------------------------ 2 files changed, 106 insertions(+), 38 deletions(-) diff --git a/msgtx_test.go b/msgtx_test.go index d813d52a..5ccc61b6 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -8,6 +8,7 @@ import ( "bytes" "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" + "io" "reflect" "testing" ) @@ -301,6 +302,73 @@ func TestTxWire(t *testing.T) { } } +// TestTxWireErrors performs negative tests against wire encode and decode +// of MsgTx to confirm error paths work correctly. +func TestTxWireErrors(t *testing.T) { + // Use protocol version 60002 specifically here instead of the latest + // because the test data is using bytes encoded with that protocol + // version. + pver := uint32(60002) + + tests := []struct { + in *btcwire.MsgTx // 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. + {multiTx, multiTxEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in number of transaction inputs. + {multiTx, multiTxEncoded, pver, 4, io.ErrShortWrite, io.EOF}, + // Force error in transaction input previous block hash. + {multiTx, multiTxEncoded, pver, 5, io.ErrShortWrite, io.EOF}, + // Force error in transaction input previous block hash. + {multiTx, multiTxEncoded, pver, 5, io.ErrShortWrite, io.EOF}, + // Force error in transaction input previous block output index. + {multiTx, multiTxEncoded, pver, 37, io.ErrShortWrite, io.EOF}, + // Force error in transaction input signature script length. + {multiTx, multiTxEncoded, pver, 41, io.ErrShortWrite, io.EOF}, + // Force error in transaction input signature script. + {multiTx, multiTxEncoded, pver, 42, io.ErrShortWrite, io.EOF}, + // Force error in transaction input sequence. + {multiTx, multiTxEncoded, pver, 49, io.ErrShortWrite, io.EOF}, + // Force error in number of transaction outputs. + {multiTx, multiTxEncoded, pver, 53, io.ErrShortWrite, io.EOF}, + // Force error in transaction output value. + {multiTx, multiTxEncoded, pver, 54, io.ErrShortWrite, io.EOF}, + // Force error in transaction output pk script length. + {multiTx, multiTxEncoded, pver, 62, io.ErrShortWrite, io.EOF}, + // Force error in transaction output pk script. + {multiTx, multiTxEncoded, pver, 63, io.ErrShortWrite, io.EOF}, + // Force error in transaction output lock time. + {multiTx, multiTxEncoded, pver, 130, 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 := test.in.BtcEncode(w, test.pver) + 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.MsgTx + r := newFixedReader(test.max, test.buf) + err = msg.BtcDecode(r, test.pver) + if err != test.readErr { + t.Errorf("BtcDecode #%d wrong error got: %v, want: %v", + i, err, test.readErr) + continue + } + } +} + // multiTx is a MsgTx with an input and output and used in various tests. var multiTx *btcwire.MsgTx = &btcwire.MsgTx{ Version: 1, diff --git a/test_coverage.txt b/test_coverage.txt index 77e4f0a0..69c5b942 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,81 +1,89 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/message.go WriteMessage 100.00% (27/27) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (23/23) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) +github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (17/17) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 100.00% (16/16) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) -github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) +github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) +github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (12/12) +github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) @@ -141,13 +149,5 @@ github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 80.00% (20/25) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 78.26% (18/23) -github.com/conformal/btcwire/msgtx.go readTxIn 76.47% (13/17) -github.com/conformal/btcwire/msgtx.go readTxOut 75.00% (9/12) -github.com/conformal/btcwire/msgtx.go readOutPoint 75.00% (3/4) -github.com/conformal/btcwire/msgtx.go writeOutPoint 75.00% (3/4) -github.com/conformal/btcwire/msgtx.go writeTxIn 73.33% (11/15) -github.com/conformal/btcwire/msgtx.go writeTxOut 72.73% (8/11) -github.com/conformal/btcwire --------------------------------- 97.18% (897/923) +github.com/conformal/btcwire --------------------------------- 100.00% (923/923) From a3226897f09aa3ffe5e43c123054f67f4e5109dc Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 13 May 2013 02:19:57 -0500 Subject: [PATCH 065/219] Update package overview Errors section. Now that all errors are either underlying IO errors or of type MessageError, update the package overview documentation accordingly. --- doc.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/doc.go b/doc.go index 84175720..e33528a8 100644 --- a/doc.go +++ b/doc.go @@ -140,12 +140,11 @@ from a remote peer is: Errors -Most errors returned by this package are either the raw errors provided by -underlying calls to read/write from streams, or raw strings that describe -the error. See the documentation of each function for any exceptions. NOTE: -This is currently undergoing change to return errors of type MessageError for -issues which are not io related so the caller can differentiate between -general io errors and malformed messages. +Errors returned by this package are either the raw errors provided by underlying +calls to read/write from streams such as io.EOF, io.ErrUnexpectedEOF, and +io.ErrShortWrite, or of type btcwire.MessageError. This allows the caller to +differentiate between general IO errors and malformed messages through type +assertions. Bitcoin Improvement Proposals From f8553b4a578d34f98ed837da8d100c5cba52f0e8 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 13 May 2013 13:55:07 -0500 Subject: [PATCH 066/219] Remove test coverage TODO since it's now 100%. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 03e6c44f..f9c31153 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,6 @@ from a remote peer is: - 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) -- Increase test coverage to 100% ## GPG Verification Key From c164de16927926e04383d7f2eb56e4ebc539fa4c Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 15 May 2013 13:57:29 -0500 Subject: [PATCH 067/219] Fix version typos in README. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f9c31153..78cfc005 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ function. It accepts any `io.Reader`, but typically this will be a `net.Conn` to a remote node running a bitcoin peer. Example syntax is: ```Go - // Use the most recent protocol verison supported by the package and the + // Use the most recent protocol version supported by the package and the // main bitcoin network. pver := btcwire.ProtocolVersion btcnet := btcwire.MainNet @@ -80,7 +80,7 @@ to a remote node running a bitcoin peer. Example syntax to request addresses from a remote peer is: ```Go - // Use the most recent protocol verison supported by the package and the + // Use the most recent protocol version supported by the package and the // main bitcoin network. pver := btcwire.ProtocolVersion btcnet := btcwire.MainNet From d8007e938728a5e33a1871ef36dbe221726caaf2 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 15 May 2013 14:00:06 -0500 Subject: [PATCH 068/219] Update README to reflect 100% test coverage. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 78cfc005..2902a612 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ btcwire ======= Package btcwire implements the bitcoin wire protocol. A comprehensive suite of -tests is provided to ensure proper functionality. See `test_coverage.txt` for -the gocov coverage report. Alternatively, if you are running a POSIX OS, you -can run the `cov_report.sh` script for a real-time report. Package btcwire is -licensed under the liberal ISC license. +tests with 100% test coverage is provided to ensure proper functionality. See +`test_coverage.txt` for the gocov coverage report. Alternatively, if you are +running a POSIX OS, you can run the `cov_report.sh` script for a real-time +report. Package btcwire is licensed under the liberal ISC license. There is an associated blog post about the release of this package [here](https://blog.conformal.com/btcwire-the-bitcoin-wire-protocol-package-from-btcd/). From 14a1da417fff2540f5b8df781df04526af6e208b Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 16 May 2013 09:07:04 -0500 Subject: [PATCH 069/219] Enforce max block payload size of 1MB. This commit changes MsgBlock to enforce a 1MB max payload per the spec. Previously it was only limited to the max overall message size. While here, also enforce max payloads per message type (instead of only the max overall message payload) when writing messages. --- fakemessage_test.go | 13 ++++++++++--- message.go | 15 +++++++++++++-- message_test.go | 16 ++++++++++++---- msgblock.go | 7 +++++-- msgblock_test.go | 2 +- test_coverage.txt | 4 ++-- 6 files changed, 43 insertions(+), 14 deletions(-) diff --git a/fakemessage_test.go b/fakemessage_test.go index 36eac01a..c1676ee9 100644 --- a/fakemessage_test.go +++ b/fakemessage_test.go @@ -15,6 +15,7 @@ type fakeMessage struct { command string payload []byte forceEncodeErr bool + forceLenErr bool } // BtcDecode doesn't do anything. It just satisfies the btcwire.Message @@ -45,8 +46,14 @@ func (msg *fakeMessage) Command() string { return msg.command } -// MaxPayloadLength simply returns 0. It is only here to satisfy the -// btcwire.Message interface. +// MaxPayloadLength returns the length of the payload field of fake message +// or a smaller value if the forceLenErr flag of the fake message is set. It +// satisfies the btcwire.Message interface. func (msg *fakeMessage) MaxPayloadLength(pver uint32) uint32 { - return 0 + lenp := uint32(len(msg.payload)) + if msg.forceLenErr { + return lenp - 1 + } + + return lenp } diff --git a/message.go b/message.go index 80b748a9..06c65f1a 100644 --- a/message.go +++ b/message.go @@ -15,7 +15,7 @@ import ( // header. Shorter commands must be zero padded. const commandSize = 12 -// maxMessagePayload is the maximum byes a message can be regardless of other +// maxMessagePayload is the maximum bytes a message can be regardless of other // individual limits imposed by messages themselves. const maxMessagePayload = (1024 * 1024 * 32) // 32MB @@ -158,6 +158,7 @@ func discardInput(r io.Reader, n uint32) { func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) error { var command [commandSize]byte + // Enforce max command size. cmd := msg.Command() if len(cmd) > commandSize { str := fmt.Sprintf("command [%s] is too long [max %v]", @@ -166,6 +167,7 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro } copy(command[:], []byte(cmd)) + // Encode the message payload. var bw bytes.Buffer err := msg.BtcEncode(&bw, pver) if err != nil { @@ -174,7 +176,7 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro payload := bw.Bytes() lenp := len(payload) - // Enforce maximum message payload. + // Enforce maximum overall message payload. if lenp > maxMessagePayload { str := fmt.Sprintf("message payload is too large - encoded "+ "%d bytes, but maximum message payload is %d bytes", @@ -182,6 +184,15 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro return messageError("WriteMessage", str) } + // Enforce maximum message payload based on the message type. + mpl := msg.MaxPayloadLength(pver) + if uint32(lenp) > mpl { + str := fmt.Sprintf("message payload is too large - encoded "+ + "%d bytes, but maximum message payload size for "+ + "messages of type [%s] is %d.", lenp, cmd, mpl) + return messageError("WriteMessage", str) + } + // Create header for the message. hdr := messageHeader{} hdr.magic = btcnet diff --git a/message_test.go b/message_test.go index e3483fc2..9186bdbd 100644 --- a/message_test.go +++ b/message_test.go @@ -317,10 +317,16 @@ func TestWriteMessageWireErrors(t *testing.T) { // Fake message with a problem during encoding encodeErrMsg := &fakeMessage{forceEncodeErr: true} - // Fake message that has a payload which exceed max. - exceedPayload := make([]byte, btcwire.MaxMessagePayload+1) - exceedPayloadErrMsg := &fakeMessage{payload: exceedPayload} + // Fake message that has payload which exceeds max overall message size. + exceedOverallPayload := make([]byte, btcwire.MaxMessagePayload+1) + exceedOverallPayloadErrMsg := &fakeMessage{payload: exceedOverallPayload} + // Fake message that has payload which exceeds max allowed per message. + exceedPayload := make([]byte, 1) + exceedPayloadErrMsg := &fakeMessage{payload: exceedPayload, forceLenErr: true} + + // Fake message that is used to force errors in the header and payload + // writes. bogusPayload := []byte{0x01, 0x02, 0x03, 0x04} bogusMsg := &fakeMessage{command: "bogus", payload: bogusPayload} @@ -335,7 +341,9 @@ func TestWriteMessageWireErrors(t *testing.T) { {badCommandMsg, pver, btcnet, 0, btcwireErr}, // Force error in payload encode. {encodeErrMsg, pver, btcnet, 0, btcwireErr}, - // Force error due to exceeding max payload size. + // Force error due to exceeding max overall message payload size. + {exceedOverallPayloadErrMsg, pver, btcnet, 0, btcwireErr}, + // Force error due to exceeding max payload for message type. {exceedPayloadErrMsg, pver, btcnet, 0, btcwireErr}, // Force error in header write. {bogusMsg, pver, btcnet, 0, io.ErrShortWrite}, diff --git a/msgblock.go b/msgblock.go index b87496c2..e3ecc488 100644 --- a/msgblock.go +++ b/msgblock.go @@ -12,6 +12,9 @@ import ( // MaxBlocksPerMsg is the maximum number of blocks allowed per message. const MaxBlocksPerMsg = 500 +// maxBlockPayload is the maximum bytes a block message can be. +const maxBlockPayload = (1024 * 1024) // 1MB + // TxLoc holds locator data for the offset and length of where a transaction is // located within a MsgBlock data buffer. type TxLoc struct { @@ -131,8 +134,8 @@ func (msg *MsgBlock) Command() string { // receiver. This is part of the Message interface implementation. func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 { // Block header at 81 bytes + max transactions which can vary up to the - // max message payload. - return maxMessagePayload + // maxBlockPayload (including the block header). + return maxBlockPayload } // BlockSha computes the block identifier hash for this block. diff --git a/msgblock_test.go b/msgblock_test.go index bd5082a5..780a657e 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -35,7 +35,7 @@ func TestBlock(t *testing.T) { // Ensure max payload is expected value for latest protocol version. // Num addresses (varInt) + max allowed addresses. - wantPayload := uint32(1024 * 1024 * 32) + wantPayload := uint32(1024 * 1024) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { t.Errorf("MaxPayloadLength: wrong max payload length for "+ diff --git a/test_coverage.txt b/test_coverage.txt index 69c5b942..fce68621 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,6 +1,6 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) -github.com/conformal/btcwire/message.go WriteMessage 100.00% (27/27) +github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) @@ -149,5 +149,5 @@ github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (923/923) +github.com/conformal/btcwire --------------------------------- 100.00% (927/927) From 7630a957246e49184ff28d6c906676480132e45d Mon Sep 17 00:00:00 2001 From: mischief Date: Wed, 29 May 2013 11:51:13 -0700 Subject: [PATCH 070/219] fix Stringer interface for ShaHash. http://golang.org/ref/spec#Method_sets for why this is necessary --- shahash.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shahash.go b/shahash.go index b698fc20..090b2e41 100644 --- a/shahash.go +++ b/shahash.go @@ -21,7 +21,7 @@ var ErrHashStrSize = fmt.Errorf("Max hash length is %v chars", MaxHashStringSize type ShaHash [HashSize]byte // String returns the ShaHash in the standard bitcoin big-endian form. -func (hash *ShaHash) String() string { +func (hash ShaHash) String() string { hashstr := "" for i := range hash { hashstr += fmt.Sprintf("%02x", hash[HashSize-1-i]) From d54fba85b473b57d1805c82a400ed531e482f3a9 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 20 Jun 2013 13:09:18 -0500 Subject: [PATCH 071/219] Export the MaxBlockPayload constant. Although you can technically get at this value via the MaxPayloadLength function on a block, it is less overhead for any consumers that need to know the value to simply export it directly. --- msgblock.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/msgblock.go b/msgblock.go index e3ecc488..a4a3208d 100644 --- a/msgblock.go +++ b/msgblock.go @@ -12,8 +12,8 @@ import ( // MaxBlocksPerMsg is the maximum number of blocks allowed per message. const MaxBlocksPerMsg = 500 -// maxBlockPayload is the maximum bytes a block message can be. -const maxBlockPayload = (1024 * 1024) // 1MB +// MaxBlockPayload is the maximum bytes a block message can be. +const MaxBlockPayload = (1024 * 1024) // 1MB // TxLoc holds locator data for the offset and length of where a transaction is // located within a MsgBlock data buffer. @@ -135,7 +135,7 @@ func (msg *MsgBlock) Command() string { func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 { // Block header at 81 bytes + max transactions which can vary up to the // maxBlockPayload (including the block header). - return maxBlockPayload + return MaxBlockPayload } // BlockSha computes the block identifier hash for this block. From 65eae1828559d8f93b86b4dae06fa39765b9c997 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 24 Jul 2013 00:34:38 -0500 Subject: [PATCH 072/219] Remove a couple of incorrect comments. --- common_test.go | 1 - msggetheaders_test.go | 1 - msgnotfound_test.go | 1 - 3 files changed, 3 deletions(-) diff --git a/common_test.go b/common_test.go index 5235a5c8..8a191c34 100644 --- a/common_test.go +++ b/common_test.go @@ -111,7 +111,6 @@ func TestVarIntWireErrors(t *testing.T) { writeErr error // Expected write error readErr error // Expected read error }{ - // Latest protocol version with intentional read/write errors. // Force errors on discriminant. {0, []byte{0x00}, pver, 0, io.ErrShortWrite, io.EOF}, // Force errors on 2-byte read/write. diff --git a/msggetheaders_test.go b/msggetheaders_test.go index 1a1210db..3afd7619 100644 --- a/msggetheaders_test.go +++ b/msggetheaders_test.go @@ -311,7 +311,6 @@ func TestGetHeadersWireErrors(t *testing.T) { } maxGetHeaders.BlockLocatorHashes = append(maxGetHeaders.BlockLocatorHashes, &btcwire.GenesisHash) - //maxGetHeaders.InvList = append(maxGetData.InvList, iv) maxGetHeadersEncoded := []byte{ 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 0xfd, 0xf5, 0x01, // Varint for number of block loc hashes (501) diff --git a/msgnotfound_test.go b/msgnotfound_test.go index 48741094..9dc50866 100644 --- a/msgnotfound_test.go +++ b/msgnotfound_test.go @@ -268,7 +268,6 @@ func TestNotFoundWireErrors(t *testing.T) { writeErr error // Expected write error readErr error // Expected read error }{ - // Latest protocol version with intentional read/write errors. // Force error in inventory vector count {baseNotFound, baseNotFoundEncoded, pver, 0, io.ErrShortWrite, io.EOF}, // Force error in inventory list. From a90a8bf341a0615d6ad9393e399168285aaaf3c4 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 24 Jul 2013 01:32:43 -0500 Subject: [PATCH 073/219] Add genesis block for the regression test network. --- genesis.go | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/genesis.go b/genesis.go index 0ab72fa3..3e575863 100644 --- a/genesis.go +++ b/genesis.go @@ -8,8 +8,8 @@ import ( "time" ) -// GenesisHash is the hash of the first block in the block chain (genesis -// block). +// GenesisHash is the hash of the first block in the block chain for the main +// network (genesis block). var GenesisHash ShaHash = ShaHash{ 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, @@ -17,7 +17,8 @@ var GenesisHash ShaHash = ShaHash{ 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, } -// GenesisMerkleRoot is the hash of the first transaction in the genesis block. +// GenesisMerkleRoot is the hash of the first transaction in the genesis block +// for the main network. var GenesisMerkleRoot ShaHash = ShaHash{ 0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61, @@ -26,14 +27,14 @@ var GenesisMerkleRoot ShaHash = ShaHash{ } // GenesisBlock defines the genesis block of the block chain which serves as the -// public transaction ledger. +// public transaction ledger for the main network. var GenesisBlock MsgBlock = MsgBlock{ Header: BlockHeader{ Version: 1, PrevBlock: ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 MerkleRoot: GenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b - Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST - Bits: 0x1d00ffff, // 486604799 + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 18:15:05 +0000 UTC + Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] Nonce: 0x7c2bac1d, // 2083236893 TxnCount: 1, }, @@ -81,3 +82,74 @@ var GenesisBlock MsgBlock = MsgBlock{ }, }, } + +// TestNetGenesisHash is the hash of the first block in the block chain for the +// regression test network (genesis block). +var TestNetGenesisHash ShaHash = ShaHash{ + 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, + 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, + 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, + 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, +} + +// TestNetGenesisMerkleRoot is the hash of the first transaction in the genesis +// block for the regression test network. It is the same as the merkle root for +// the main network. +var TestNetGenesisMerkleRoot ShaHash = GenesisMerkleRoot + +// TestNetGenesisBlock defines the genesis block of the block chain which serves +// as the public transaction ledger for the regression test network. +var TestNetGenesisBlock MsgBlock = MsgBlock{ + Header: BlockHeader{ + Version: 1, + PrevBlock: ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 + MerkleRoot: TestNetGenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC + Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000] + Nonce: 2, + TxnCount: 1, + }, + Transactions: []*MsgTx{ + &MsgTx{ + Version: 1, + TxIn: []*TxIn{ + &TxIn{ + PreviousOutpoint: OutPoint{ + Hash: ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ + 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ + 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ + 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ + 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ + 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ + 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ + 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ + 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ + }, + Sequence: 0xffffffff, + }, + }, + TxOut: []*TxOut{ + &TxOut{ + Value: 0x12a05f200, + PkScript: []byte{ + 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ + 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ + 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ + 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ + 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ + 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ + 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ + 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ + 0x1d, 0x5f, 0xac, /* |._.| */ + }, + }, + }, + LockTime: 0, + }, + }, +} From b8f80da5126999d48c7bbc56a7549031d3484222 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 24 Jul 2013 01:33:24 -0500 Subject: [PATCH 074/219] Add tests for genesis block of regression testnet. --- genesis_test.go | 84 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/genesis_test.go b/genesis_test.go index 75bd6bdf..79983f22 100644 --- a/genesis_test.go +++ b/genesis_test.go @@ -11,8 +11,8 @@ import ( "testing" ) -// TestGenesisBlock tests the genesis block for validity by checking the encoded -// bytes and hashes. +// TestGenesisBlock tests the genesis block of the main network for validity by +// checking the encoded bytes and hashes. func TestGenesisBlock(t *testing.T) { pver := uint32(60002) @@ -45,8 +45,43 @@ func TestGenesisBlock(t *testing.T) { } } -// genesisBlockBytes are the wire encoded bytes for the genesis block as of -// protocol version 60002. +// TestTestNetGenesisBlock tests the genesis block of the regression test +// network for validity by checking the encoded bytes and hashes. +func TestTestNetGenesisBlock(t *testing.T) { + pver := uint32(60002) + + // Encode the genesis block to raw bytes. + var buf bytes.Buffer + err := btcwire.TestNetGenesisBlock.BtcEncode(&buf, pver) + if err != nil { + t.Errorf("TestTestNetGenesisBlock: %v", err) + return + } + + // Ensure the encoded block matches the expected bytes. + if !bytes.Equal(buf.Bytes(), testNetGenesisBlockBytes) { + t.Errorf("TestTestNetGenesisBlock: Genesis block does not "+ + "appear valid - got %v, want %v", + spew.Sdump(buf.Bytes()), + spew.Sdump(testNetGenesisBlockBytes)) + return + } + + // Check hash of the block against expected hash. + hash, err := btcwire.TestNetGenesisBlock.Header.BlockSha(pver) + if err != nil { + t.Errorf("BlockSha: %v", err) + } + if !btcwire.TestNetGenesisHash.IsEqual(&hash) { + t.Errorf("TestTestNetGenesisBlock: Genesis block hash does "+ + "not appear valid - got %v, want %v", spew.Sdump(hash), + spew.Sdump(btcwire.GenesisHash)) + return + } +} + +// genesisBlockBytes are the wire encoded bytes for the genesis block of the +// main network as of protocol version 60002. var genesisBlockBytes = []byte{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ @@ -85,3 +120,44 @@ var genesisBlockBytes = []byte{ 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ } + +// testNetGenesisBlockBytes are the wire encoded bytes for the genesis block of +// the regression test network as of protocol version 60002. +var testNetGenesisBlockBytes = []byte{ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */ + 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */ + 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */ + 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */ + 0x4b, 0x1e, 0x5e, 0x4a, 0xda, 0xe5, 0x49, 0x4d, /* |K.^J)._I| */ + 0xff, 0xff, 0x7f, 0x20, 0x02, 0x00, 0x00, 0x00, /* |......+|| */ + 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */ + 0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */ + 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */ + 0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */ + 0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */ + 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */ + 0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */ + 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */ + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */ + 0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */ + 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */ + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */ + 0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */ + 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */ + 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */ + 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */ + 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */ + 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */ + 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */ + 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */ + 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ + 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ +} From 166123ae790923d06e8b86bb530e2b15abb50fca Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 24 Jul 2013 01:45:30 -0500 Subject: [PATCH 075/219] Add genesis block for the test network (version 3). --- genesis.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/genesis.go b/genesis.go index 3e575863..8d7973f8 100644 --- a/genesis.go +++ b/genesis.go @@ -153,3 +153,74 @@ var TestNetGenesisBlock MsgBlock = MsgBlock{ }, }, } + +// TestNet3GenesisHash is the hash of the first block in the block chain for the +// test network (version 3). +var TestNet3GenesisHash ShaHash = ShaHash{ + 0x43, 0x49, 0x7f, 0xd7, 0xf8, 0x26, 0x95, 0x71, + 0x08, 0xf4, 0xa3, 0x0f, 0xd9, 0xce, 0xc3, 0xae, + 0xba, 0x79, 0x97, 0x20, 0x84, 0xe9, 0x0e, 0xad, + 0x01, 0xea, 0x33, 0x09, 0x00, 0x00, 0x00, 0x00, +} + +// TestNet3GenesisMerkleRoot is the hash of the first transaction in the genesis +// block for the test network (version 3). It is the same as the merkle root +// for the main network. +var TestNet3GenesisMerkleRoot ShaHash = GenesisMerkleRoot + +// TestNet3GenesisBlock defines the genesis block of the block chain which +// serves as the public transaction ledger for the test network (version 3). +var TestNet3GenesisBlock MsgBlock = MsgBlock{ + Header: BlockHeader{ + Version: 1, + PrevBlock: ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 + MerkleRoot: TestNet3GenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC + Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] + Nonce: 0x18aea41a, // 414098458 + TxnCount: 1, + }, + Transactions: []*MsgTx{ + &MsgTx{ + Version: 1, + TxIn: []*TxIn{ + &TxIn{ + PreviousOutpoint: OutPoint{ + Hash: ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ + 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ + 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ + 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ + 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ + 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ + 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ + 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ + 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ + }, + Sequence: 0xffffffff, + }, + }, + TxOut: []*TxOut{ + &TxOut{ + Value: 0x12a05f200, + PkScript: []byte{ + 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ + 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ + 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ + 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ + 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ + 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ + 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ + 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ + 0x1d, 0x5f, 0xac, /* |._.| */ + }, + }, + }, + LockTime: 0, + }, + }, +} From ab064fd4d479c92e802bb521710571f585c63def Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 24 Jul 2013 01:47:11 -0500 Subject: [PATCH 076/219] Add tests for genesis block of testnet (version 3). --- genesis_test.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/genesis_test.go b/genesis_test.go index 79983f22..85771a0d 100644 --- a/genesis_test.go +++ b/genesis_test.go @@ -75,7 +75,42 @@ func TestTestNetGenesisBlock(t *testing.T) { if !btcwire.TestNetGenesisHash.IsEqual(&hash) { t.Errorf("TestTestNetGenesisBlock: Genesis block hash does "+ "not appear valid - got %v, want %v", spew.Sdump(hash), - spew.Sdump(btcwire.GenesisHash)) + spew.Sdump(btcwire.TestNetGenesisHash)) + return + } +} + +// TestTestNet3GenesisBlock tests the genesis block of the test network (version +// 3) for validity by checking the encoded bytes and hashes. +func TestTestNet3GenesisBlock(t *testing.T) { + pver := uint32(60002) + + // Encode the genesis block to raw bytes. + var buf bytes.Buffer + err := btcwire.TestNet3GenesisBlock.BtcEncode(&buf, pver) + if err != nil { + t.Errorf("TestTestNet3GenesisBlock: %v", err) + return + } + + // Ensure the encoded block matches the expected bytes. + if !bytes.Equal(buf.Bytes(), testNet3GenesisBlockBytes) { + t.Errorf("TestTestNet3GenesisBlock: Genesis block does not "+ + "appear valid - got %v, want %v", + spew.Sdump(buf.Bytes()), + spew.Sdump(testNet3GenesisBlockBytes)) + return + } + + // Check hash of the block against expected hash. + hash, err := btcwire.TestNet3GenesisBlock.Header.BlockSha(pver) + if err != nil { + t.Errorf("BlockSha: %v", err) + } + if !btcwire.TestNet3GenesisHash.IsEqual(&hash) { + t.Errorf("TestTestNet3GenesisBlock: Genesis block hash does "+ + "not appear valid - got %v, want %v", spew.Sdump(hash), + spew.Sdump(btcwire.TestNet3GenesisHash)) return } } @@ -161,3 +196,44 @@ var testNetGenesisBlockBytes = []byte{ 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ } + +// testNet3GenesisBlockBytes are the wire encoded bytes for the genesis block of +// the test network (version 3) as of protocol version 60002. +var testNet3GenesisBlockBytes = []byte{ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */ + 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */ + 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */ + 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */ + 0x4b, 0x1e, 0x5e, 0x4a, 0xda, 0xe5, 0x49, 0x4d, /* |K.^J)._I| */ + 0xff, 0xff, 0x00, 0x1d, 0x1a, 0xa4, 0xae, 0x18, /* |......+|| */ + 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */ + 0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */ + 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */ + 0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */ + 0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */ + 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */ + 0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */ + 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */ + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */ + 0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */ + 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */ + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */ + 0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */ + 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */ + 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */ + 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */ + 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */ + 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */ + 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */ + 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */ + 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ + 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ +} From 60dfddc9d05436981f68ba7d2b04312cf98ad956 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 24 Jul 2013 09:09:18 -0500 Subject: [PATCH 077/219] Use common coinbase transaction for Genesis blocks. Since the same coinbase transaction is used for the genesis blocks of all three currently supposed networks, separate it into its own var and use a reference to it in each of the genesis block defintions. --- genesis.go | 176 ++++++++++++++--------------------------------------- 1 file changed, 47 insertions(+), 129 deletions(-) diff --git a/genesis.go b/genesis.go index 8d7973f8..9eec1b4f 100644 --- a/genesis.go +++ b/genesis.go @@ -8,6 +8,50 @@ import ( "time" ) +// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for +// the main network, regression test network, and test network (version 3). +var genesisCoinbaseTx = MsgTx{ + Version: 1, + TxIn: []*TxIn{ + &TxIn{ + PreviousOutpoint: OutPoint{ + Hash: ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ + 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ + 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ + 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ + 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ + 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ + 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ + 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ + 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ + }, + Sequence: 0xffffffff, + }, + }, + TxOut: []*TxOut{ + &TxOut{ + Value: 0x12a05f200, + PkScript: []byte{ + 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ + 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ + 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ + 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ + 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ + 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ + 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ + 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ + 0x1d, 0x5f, 0xac, /* |._.| */ + }, + }, + }, + LockTime: 0, +} + // GenesisHash is the hash of the first block in the block chain for the main // network (genesis block). var GenesisHash ShaHash = ShaHash{ @@ -38,49 +82,7 @@ var GenesisBlock MsgBlock = MsgBlock{ Nonce: 0x7c2bac1d, // 2083236893 TxnCount: 1, }, - Transactions: []*MsgTx{ - &MsgTx{ - Version: 1, - TxIn: []*TxIn{ - &TxIn{ - PreviousOutpoint: OutPoint{ - Hash: ShaHash{}, - Index: 0xffffffff, - }, - SignatureScript: []byte{ - 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ - 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ - 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ - 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ - 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ - 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ - 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ - 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ - 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ - }, - Sequence: 0xffffffff, - }, - }, - TxOut: []*TxOut{ - &TxOut{ - Value: 0x12a05f200, - PkScript: []byte{ - 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ - 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ - 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ - 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ - 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ - 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ - 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ - 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ - 0x1d, 0x5f, 0xac, /* |._.| */ - }, - }, - }, - LockTime: 0, - }, - }, + Transactions: []*MsgTx{&genesisCoinbaseTx}, } // TestNetGenesisHash is the hash of the first block in the block chain for the @@ -109,49 +111,7 @@ var TestNetGenesisBlock MsgBlock = MsgBlock{ Nonce: 2, TxnCount: 1, }, - Transactions: []*MsgTx{ - &MsgTx{ - Version: 1, - TxIn: []*TxIn{ - &TxIn{ - PreviousOutpoint: OutPoint{ - Hash: ShaHash{}, - Index: 0xffffffff, - }, - SignatureScript: []byte{ - 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ - 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ - 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ - 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ - 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ - 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ - 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ - 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ - 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ - }, - Sequence: 0xffffffff, - }, - }, - TxOut: []*TxOut{ - &TxOut{ - Value: 0x12a05f200, - PkScript: []byte{ - 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ - 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ - 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ - 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ - 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ - 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ - 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ - 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ - 0x1d, 0x5f, 0xac, /* |._.| */ - }, - }, - }, - LockTime: 0, - }, - }, + Transactions: []*MsgTx{&genesisCoinbaseTx}, } // TestNet3GenesisHash is the hash of the first block in the block chain for the @@ -180,47 +140,5 @@ var TestNet3GenesisBlock MsgBlock = MsgBlock{ Nonce: 0x18aea41a, // 414098458 TxnCount: 1, }, - Transactions: []*MsgTx{ - &MsgTx{ - Version: 1, - TxIn: []*TxIn{ - &TxIn{ - PreviousOutpoint: OutPoint{ - Hash: ShaHash{}, - Index: 0xffffffff, - }, - SignatureScript: []byte{ - 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ - 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ - 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ - 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ - 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ - 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ - 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ - 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ - 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ - }, - Sequence: 0xffffffff, - }, - }, - TxOut: []*TxOut{ - &TxOut{ - Value: 0x12a05f200, - PkScript: []byte{ - 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ - 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ - 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ - 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ - 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ - 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ - 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ - 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ - 0x1d, 0x5f, 0xac, /* |._.| */ - }, - }, - }, - LockTime: 0, - }, - }, + Transactions: []*MsgTx{&genesisCoinbaseTx}, } From 4e6b649be65ba20510cb75b99ef23fab48479664 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 25 Jul 2013 19:04:02 -0500 Subject: [PATCH 078/219] Add constant for regression test netowrk port. --- protocol.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/protocol.go b/protocol.go index 284a6692..60935110 100644 --- a/protocol.go +++ b/protocol.go @@ -10,10 +10,11 @@ import ( ) const ( - MainPort = "8333" - TestNetPort = "18333" - ProtocolVersion uint32 = 70001 - TxVersion = 1 + MainPort = "8333" + TestNetPort = "18333" + RegressionTestPort = "18444" + ProtocolVersion uint32 = 70001 + TxVersion = 1 // MultipleAddressVersion is the protocol version which added multiple // addresses per message (pver >= MultipleAddressVersion). From ea3107d962098c6d92c139b5c4e9e55e3eee9be7 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 25 Jul 2013 19:04:58 -0500 Subject: [PATCH 079/219] Add comments and doco to clairfy test networks. There was not much documentation about the difference between testnet and testnet3, so make it clear that testnet is used for regression tests and testnet3 is the public test network (version 3). --- doc.go | 4 ++-- protocol.go | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/doc.go b/doc.go index e33528a8..0a6ecd1b 100644 --- a/doc.go +++ b/doc.go @@ -84,8 +84,8 @@ message and which bitcoin network the message applies to. This package provides the following constants: btcwire.MainNet - btcwire.TestNet - btcwire.TestNet3 + btcwire.TestNet (Regression test network) + btcwire.TestNet3 (Test network version 3) Determining Message Type diff --git a/protocol.go b/protocol.go index 60935110..b005d371 100644 --- a/protocol.go +++ b/protocol.go @@ -83,7 +83,12 @@ type BitcoinNet uint32 // this package does not provide that functionality since it's generally a // better idea to simply disconnect clients that are misbehaving over TCP. const ( - MainNet BitcoinNet = 0xd9b4bef9 - TestNet BitcoinNet = 0xdab5bffa + // Main bitcoin network. + MainNet BitcoinNet = 0xd9b4bef9 + + // Regression test network. + TestNet BitcoinNet = 0xdab5bffa + + // Test network version 3. TestNet3 BitcoinNet = 0x0709110b ) From 9989865fa2f6268b22b15c4054732dfe2b36c87e Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 27 Jul 2013 15:25:05 -0500 Subject: [PATCH 080/219] Use correct max block payload size. The maximum block payload size is actually 1000000 bytes, not 1MB. --- msgblock.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/msgblock.go b/msgblock.go index a4a3208d..5e57bf73 100644 --- a/msgblock.go +++ b/msgblock.go @@ -12,8 +12,8 @@ import ( // MaxBlocksPerMsg is the maximum number of blocks allowed per message. const MaxBlocksPerMsg = 500 -// MaxBlockPayload is the maximum bytes a block message can be. -const MaxBlockPayload = (1024 * 1024) // 1MB +// MaxBlockPayload is the maximum bytes a block message can be in bytes. +const MaxBlockPayload = 1000000 // Not actually 1MB which would be 1024 * 1024 // TxLoc holds locator data for the offset and length of where a transaction is // located within a MsgBlock data buffer. From 90bf9e7449bffcf1814f06b625f8de92b7636247 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 27 Jul 2013 15:32:01 -0500 Subject: [PATCH 081/219] Update tests for corrected max block payload size. --- msgblock_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgblock_test.go b/msgblock_test.go index 780a657e..5196e17a 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -35,7 +35,7 @@ func TestBlock(t *testing.T) { // Ensure max payload is expected value for latest protocol version. // Num addresses (varInt) + max allowed addresses. - wantPayload := uint32(1024 * 1024) + wantPayload := uint32(1000000) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { t.Errorf("MaxPayloadLength: wrong max payload length for "+ From 562bde6902726ef306ed426268f61b97230b19c4 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 27 Jul 2013 15:38:03 -0500 Subject: [PATCH 082/219] Use byte literals in tests to make go vet happy. The go vet command complains about untagged struct initializers when defining a ShaHash directly. This seems to be a limitation where go vet does not exclude the warning for types which are a constant size byte array like it does for normal constant size byte array definition. This commit simply modifies the tests to use a constant definition cast to a ShaHash to overcome the limitation of go vet. --- msgblock_test.go | 8 ++++---- msgtx_test.go | 2 +- shahash_test.go | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index 5196e17a..68925720 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -294,18 +294,18 @@ func TestBlockWireErrors(t *testing.T) { var blockOne btcwire.MsgBlock = btcwire.MsgBlock{ Header: btcwire.BlockHeader{ Version: 1, - PrevBlock: btcwire.ShaHash{ + 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{ + }), + 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 diff --git a/msgtx_test.go b/msgtx_test.go index 5ccc61b6..6f631aac 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -134,7 +134,7 @@ func TestTxSha(t *testing.T) { msgTx := btcwire.NewMsgTx() txIn := btcwire.TxIn{ PreviousOutpoint: btcwire.OutPoint{ - Hash: btcwire.ShaHash{0x00}, + Hash: btcwire.ShaHash{}, Index: 0xffffffff, }, SignatureScript: []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62}, diff --git a/shahash_test.go b/shahash_test.go index e99f4542..a1f5774c 100644 --- a/shahash_test.go +++ b/shahash_test.go @@ -80,12 +80,12 @@ func TestShaHash(t *testing.T) { func TestShaHashString(t *testing.T) { // Block 100000 hash. wantStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" - hash := &btcwire.ShaHash{ + hash := btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39, 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2, 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa, 0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - } + }) hashStr := hash.String() if hashStr != wantStr { @@ -118,24 +118,24 @@ func TestNewShaHashFromStr(t *testing.T) { // Single digit hash. { "1", - btcwire.ShaHash{ + btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, + }), nil, }, // Block 203707 with stripped leading zeros. { "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc", - btcwire.ShaHash{ + btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, + }), nil, }, From 99b06f8bce894796b27045c4aea626c62290d78d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 27 Jul 2013 15:56:17 -0500 Subject: [PATCH 083/219] Add format specifier in pong test error output. The error message did not have a format specifier even though it was passing an argument to show. Found by go vet. --- msgpong_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgpong_test.go b/msgpong_test.go index 81be02c3..fb10d51e 100644 --- a/msgpong_test.go +++ b/msgpong_test.go @@ -99,7 +99,7 @@ func TestPongBIP0031(t *testing.T) { readmsg := btcwire.NewMsgPong(0) err = readmsg.BtcDecode(&buf, pver) if err == nil { - t.Errorf("decode of MsgPong succeeded when it shouldn't have", + t.Errorf("decode of MsgPong succeeded when it shouldn't have %v", spew.Sdump(buf)) } From bfbc08beed9ad6daf9b16fc1f0cf610d8eb0886a Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 27 Jul 2013 16:10:38 -0500 Subject: [PATCH 084/219] Allow var defs to infer type from right-hand side. Found by golint. --- genesis.go | 18 +++++++++--------- msgblock_test.go | 2 +- msgtx_test.go | 4 ++-- msgversion_test.go | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/genesis.go b/genesis.go index 9eec1b4f..1703f5ee 100644 --- a/genesis.go +++ b/genesis.go @@ -54,7 +54,7 @@ var genesisCoinbaseTx = MsgTx{ // GenesisHash is the hash of the first block in the block chain for the main // network (genesis block). -var GenesisHash ShaHash = ShaHash{ +var GenesisHash = ShaHash{ 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, @@ -63,7 +63,7 @@ var GenesisHash ShaHash = ShaHash{ // GenesisMerkleRoot is the hash of the first transaction in the genesis block // for the main network. -var GenesisMerkleRoot ShaHash = ShaHash{ +var GenesisMerkleRoot = ShaHash{ 0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32, @@ -72,7 +72,7 @@ var GenesisMerkleRoot ShaHash = ShaHash{ // GenesisBlock defines the genesis block of the block chain which serves as the // public transaction ledger for the main network. -var GenesisBlock MsgBlock = MsgBlock{ +var GenesisBlock = MsgBlock{ Header: BlockHeader{ Version: 1, PrevBlock: ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 @@ -87,7 +87,7 @@ var GenesisBlock MsgBlock = MsgBlock{ // TestNetGenesisHash is the hash of the first block in the block chain for the // regression test network (genesis block). -var TestNetGenesisHash ShaHash = ShaHash{ +var TestNetGenesisHash = ShaHash{ 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, @@ -97,11 +97,11 @@ var TestNetGenesisHash ShaHash = ShaHash{ // TestNetGenesisMerkleRoot is the hash of the first transaction in the genesis // block for the regression test network. It is the same as the merkle root for // the main network. -var TestNetGenesisMerkleRoot ShaHash = GenesisMerkleRoot +var TestNetGenesisMerkleRoot = GenesisMerkleRoot // TestNetGenesisBlock defines the genesis block of the block chain which serves // as the public transaction ledger for the regression test network. -var TestNetGenesisBlock MsgBlock = MsgBlock{ +var TestNetGenesisBlock = MsgBlock{ Header: BlockHeader{ Version: 1, PrevBlock: ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 @@ -116,7 +116,7 @@ var TestNetGenesisBlock MsgBlock = MsgBlock{ // TestNet3GenesisHash is the hash of the first block in the block chain for the // test network (version 3). -var TestNet3GenesisHash ShaHash = ShaHash{ +var TestNet3GenesisHash = ShaHash{ 0x43, 0x49, 0x7f, 0xd7, 0xf8, 0x26, 0x95, 0x71, 0x08, 0xf4, 0xa3, 0x0f, 0xd9, 0xce, 0xc3, 0xae, 0xba, 0x79, 0x97, 0x20, 0x84, 0xe9, 0x0e, 0xad, @@ -126,11 +126,11 @@ var TestNet3GenesisHash ShaHash = ShaHash{ // TestNet3GenesisMerkleRoot is the hash of the first transaction in the genesis // block for the test network (version 3). It is the same as the merkle root // for the main network. -var TestNet3GenesisMerkleRoot ShaHash = GenesisMerkleRoot +var TestNet3GenesisMerkleRoot = GenesisMerkleRoot // TestNet3GenesisBlock defines the genesis block of the block chain which // serves as the public transaction ledger for the test network (version 3). -var TestNet3GenesisBlock MsgBlock = MsgBlock{ +var TestNet3GenesisBlock = MsgBlock{ Header: BlockHeader{ Version: 1, PrevBlock: ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 diff --git a/msgblock_test.go b/msgblock_test.go index 68925720..6a16ed7d 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -291,7 +291,7 @@ func TestBlockWireErrors(t *testing.T) { } } -var blockOne btcwire.MsgBlock = btcwire.MsgBlock{ +var blockOne = btcwire.MsgBlock{ Header: btcwire.BlockHeader{ Version: 1, PrevBlock: btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. diff --git a/msgtx_test.go b/msgtx_test.go index 6f631aac..d7149e08 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -370,7 +370,7 @@ func TestTxWireErrors(t *testing.T) { } // multiTx is a MsgTx with an input and output and used in various tests. -var multiTx *btcwire.MsgTx = &btcwire.MsgTx{ +var multiTx = &btcwire.MsgTx{ Version: 1, TxIn: []*btcwire.TxIn{ &btcwire.TxIn{ @@ -407,7 +407,7 @@ var multiTx *btcwire.MsgTx = &btcwire.MsgTx{ // multiTxEncoded is the wire encoded bytes for multiTx using protocol version // 60002 and is used in the various tests. -var multiTxEncoded []byte = []byte{ +var multiTxEncoded = []byte{ 0x01, 0x00, 0x00, 0x00, // Version 0x01, // Varint for number of input transactions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/msgversion_test.go b/msgversion_test.go index cbb3bce4..5f524e73 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -334,7 +334,7 @@ func TestVersionWireErrors(t *testing.T) { } // baseVersion is used in the various tests as a baseline MsgVersion. -var baseVersion *btcwire.MsgVersion = &btcwire.MsgVersion{ +var baseVersion = &btcwire.MsgVersion{ ProtocolVersion: 60002, Services: btcwire.SFNodeNetwork, Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST) @@ -357,7 +357,7 @@ var baseVersion *btcwire.MsgVersion = &btcwire.MsgVersion{ // baseVersionEncoded is the wire encoded bytes for baseVersion using protocol // version 60002 and is used in the various tests. -var baseVersionEncoded []byte = []byte{ +var baseVersionEncoded = []byte{ 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork 0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp From d6752d8f997b6cb27fdfb3cf332c59f11a4d1a03 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 27 Jul 2013 16:18:13 -0500 Subject: [PATCH 085/219] Update comments to fix typos and use proper form. --- msgheaders.go | 2 +- msgmempool.go | 2 +- msgtx.go | 2 +- protocol.go | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/msgheaders.go b/msgheaders.go index c507a90b..3aa5d160 100644 --- a/msgheaders.go +++ b/msgheaders.go @@ -114,7 +114,7 @@ func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 { return maxVarIntPayload + (maxBlockHeaderPayload * MaxBlockHeadersPerMsg) } -// NewMsgGetHeaders returns a new bitcoin headers message that conforms to the +// NewMsgHeaders returns a new bitcoin headers message that conforms to the // Message interface. See MsgHeaders for details. func NewMsgHeaders() *MsgHeaders { return &MsgHeaders{} diff --git a/msgmempool.go b/msgmempool.go index b816d9f0..9a75f839 100644 --- a/msgmempool.go +++ b/msgmempool.go @@ -53,7 +53,7 @@ func (msg *MsgMemPool) MaxPayloadLength(pver uint32) uint32 { return 0 } -// NewMsgPong returns a new bitcoin pong message that conforms to the Message +// NewMsgMemPool returns a new bitcoin pong message that conforms to the Message // interface. See MsgPong for details. func NewMsgMemPool() *MsgMemPool { return &MsgMemPool{} diff --git a/msgtx.go b/msgtx.go index bda97f9d..a8181e74 100644 --- a/msgtx.go +++ b/msgtx.go @@ -13,7 +13,7 @@ import ( // of a transaction input can be. const MaxTxInSequenceNum uint32 = 0xffffffff -// Outpoint defines a bitcoin data type that is used to track previous +// OutPoint defines a bitcoin data type that is used to track previous // transaction outputs. type OutPoint struct { Hash ShaHash diff --git a/protocol.go b/protocol.go index b005d371..2d4d9e2b 100644 --- a/protocol.go +++ b/protocol.go @@ -83,12 +83,12 @@ type BitcoinNet uint32 // this package does not provide that functionality since it's generally a // better idea to simply disconnect clients that are misbehaving over TCP. const ( - // Main bitcoin network. + // MainNet represents the main bitcoin network. MainNet BitcoinNet = 0xd9b4bef9 - // Regression test network. + // TestNet represents the regression test network. TestNet BitcoinNet = 0xdab5bffa - // Test network version 3. + // TestNet3 represents the test network (version 3). TestNet3 BitcoinNet = 0x0709110b ) From 035a9c3dc36d00e69d1db2d2c1b71ca3e5539e3d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 27 Jul 2013 16:31:47 -0500 Subject: [PATCH 086/219] Add several comments for exported constants. --- protocol.go | 21 ++++++++++++++++----- shahash.go | 4 ++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/protocol.go b/protocol.go index 2d4d9e2b..1e5c8ede 100644 --- a/protocol.go +++ b/protocol.go @@ -10,11 +10,21 @@ import ( ) const ( - MainPort = "8333" - TestNetPort = "18333" - RegressionTestPort = "18444" - ProtocolVersion uint32 = 70001 - TxVersion = 1 + // MainPort is the port used by default on the main network. + MainPort = "8333" + + // TestNetPort is the port used by default on the test network (version + // 3). + TestNetPort = "18333" + + // RegressionTestPort is the port used by default on the regression test + // network. + RegressionTestPort = "18444" + + // ProtocolVersion is the latest protocol version this package supports. + ProtocolVersion uint32 = 70001 + + TxVersion = 1 // MultipleAddressVersion is the protocol version which added multiple // addresses per message (pver >= MultipleAddressVersion). @@ -42,6 +52,7 @@ const ( type ServiceFlag uint64 const ( + // SFNodeNetwork is a flag used to indicate a peer is a full node. SFNodeNetwork ServiceFlag = 1 << iota ) diff --git a/shahash.go b/shahash.go index 090b2e41..a3966bbf 100644 --- a/shahash.go +++ b/shahash.go @@ -12,8 +12,12 @@ import ( // Size of array used to store sha hashes. See ShaHash. const HashSize = 32 + +// MaxHashStringSize is the maximum length of a ShaHash hash string. const MaxHashStringSize = HashSize * 2 +// ErrHashStrSize describes an error that indicates the caller specified a hash +// string that has too many characters. var ErrHashStrSize = fmt.Errorf("Max hash length is %v chars", MaxHashStringSize) // ShaHash is used in several of the bitcoin messages and common structures. It From 69446009b2b7c420d150bfff88d4c6de77db66ab Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 27 Jul 2013 16:34:47 -0500 Subject: [PATCH 087/219] Move TxVersion constant definition to msgtx.go. This moves the definition closer to the associated type and mirrors the rest of the package. --- msgtx.go | 3 +++ protocol.go | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/msgtx.go b/msgtx.go index a8181e74..48f00678 100644 --- a/msgtx.go +++ b/msgtx.go @@ -9,6 +9,9 @@ import ( "io" ) +// TxVersion is the current latest supported transaction version. +const TxVersion = 1 + // MaxTxInSequenceNum is the maximum sequence number the sequence field // of a transaction input can be. const MaxTxInSequenceNum uint32 = 0xffffffff diff --git a/protocol.go b/protocol.go index 1e5c8ede..ebf166fb 100644 --- a/protocol.go +++ b/protocol.go @@ -24,8 +24,6 @@ const ( // ProtocolVersion is the latest protocol version this package supports. ProtocolVersion uint32 = 70001 - TxVersion = 1 - // MultipleAddressVersion is the protocol version which added multiple // addresses per message (pver >= MultipleAddressVersion). MultipleAddressVersion uint32 = 209 From 81120958f03e07904fd9af614407a65a4dc82b42 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 27 Jul 2013 16:41:57 -0500 Subject: [PATCH 088/219] Comment inventory vector constants. --- invvect.go | 1 + 1 file changed, 1 insertion(+) diff --git a/invvect.go b/invvect.go index 1784a094..c74a9b50 100644 --- a/invvect.go +++ b/invvect.go @@ -21,6 +21,7 @@ const ( // InvType represents the allowed types of inventory vectors. See InvVect. type InvType uint32 +// These constants define the various supported inventory vector types. const ( InvVect_Error InvType = 0 InvVect_Tx InvType = 1 From 088f3c923dc33e98cfa788cdc578999462c9b3bd Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 5 Aug 2013 10:53:27 -0500 Subject: [PATCH 089/219] Add Serialize/Deserialize for MsgBlock and MsgTx. This commit introduces two new functions for MsgBlock and MsgTx named Serialize and Deserialize. The functions provide a stable mechanism for serializing and deserializing blocks and transactions to and from disk without having to worry about the protocol version. Instead these functions use the Version fields in the blocks and transactions. These new functions differ from BtcEncode and BtcDecode in that the latter functions are intended to encode/decode blocks and transaction from the wire which technically can differ depending on the protocol version and don't even really need to use the same format as the stored data. Currently, there is no difference between the two, and due to how intertwined they are in the reference implementaiton, they may not ever diverge, but there is a difference and the goal for btcwire is to provide a stable API that is flexible enough to deal with encoding changes. --- msgblock.go | 81 ++++++++++++++++++++++++++++++++++++++++++++++++----- msgtx.go | 39 ++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 7 deletions(-) diff --git a/msgblock.go b/msgblock.go index 5e57bf73..1b288703 100644 --- a/msgblock.go +++ b/msgblock.go @@ -57,6 +57,8 @@ func (msg *MsgBlock) ClearTransactions() { // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. // This is part of the Message interface implementation. +// See Deserialize for decoding blocks stored to disk, such as in a database, as +// opposed to decoding blocks from the wire. func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32) error { err := readBlockHeader(r, pver, &msg.Header) if err != nil { @@ -79,18 +81,17 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32) error { // receiver and returns a slice containing the start and length of each // transaction within the raw data. func (msg *MsgBlock) BtcDecodeTxLoc(r *bytes.Buffer, pver uint32) ([]TxLoc, error) { - var fullLen int - fullLen = r.Len() - + fullLen := r.Len() err := readBlockHeader(r, pver, &msg.Header) if err != nil { return nil, err } - var txLocs []TxLoc - txLocs = make([]TxLoc, msg.Header.TxnCount) - - for i := uint64(0); i < msg.Header.TxnCount; i++ { + // Decode each transaction while keeping track of its location within + // the byte stream. + txCount := msg.Header.TxnCount + txLocs := make([]TxLoc, txCount) + for i := uint64(0); i < txCount; i++ { txLocs[i].TxStart = fullLen - r.Len() tx := MsgTx{} err := tx.BtcDecode(r, pver) @@ -104,8 +105,58 @@ func (msg *MsgBlock) BtcDecodeTxLoc(r *bytes.Buffer, pver uint32) ([]TxLoc, erro return txLocs, nil } +// Deserialize decodes a block from r into the receiver using a format that is +// suitable for long-term storage such as a database while respecting the +// Version field in the block. This function differs from BtcDecode in that +// BtcDecode decodes from the bitcoin wire protocol as it was 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 block at +// all. As of the time this comment was written, the encoded block 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 *MsgBlock) Deserialize(r io.Reader) 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 BtcDecode. + return msg.BtcDecode(r, 0) +} + +// DeserializeTxLoc decodes r in the same manner Deserialize does, but it takes +// a byte buffer instead of a generic reader and returns a slice containing the start and length of +// each transaction within the raw data that is being deserialized. +func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) { + fullLen := r.Len() + + // 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 existing wire protocol functions. + err := readBlockHeader(r, 0, &msg.Header) + if err != nil { + return nil, err + } + + // Deserialize each transaction while keeping track of its location + // within the byte stream. + txCount := msg.Header.TxnCount + txLocs := make([]TxLoc, txCount) + for i := uint64(0); i < txCount; i++ { + txLocs[i].TxStart = fullLen - r.Len() + tx := MsgTx{} + err := tx.Deserialize(r) + if err != nil { + return nil, err + } + msg.Transactions = append(msg.Transactions, &tx) + txLocs[i].TxLen = (fullLen - r.Len()) - txLocs[i].TxStart + } + + return txLocs, nil +} + // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. // This is part of the Message interface implementation. +// See Serialize for encoding blocks to be stored to disk, such as in a +// database, as opposed to encoding blocks for the wire. func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32) error { msg.Header.TxnCount = uint64(len(msg.Transactions)) @@ -124,6 +175,22 @@ func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32) error { return nil } +// Serialize encodes the block to w using a format that suitable for long-term +// storage such as a database while respecting the Version field in the block. +// This function differs from BtcEncode in that BtcEncode encodes the block 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 block at all. As of the +// time this comment was written, the encoded block 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 *MsgBlock) 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, 0) +} + // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgBlock) Command() string { diff --git a/msgtx.go b/msgtx.go index 48f00678..0983c81c 100644 --- a/msgtx.go +++ b/msgtx.go @@ -168,6 +168,8 @@ func (tx *MsgTx) Copy() *MsgTx { // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. // This is part of the Message interface implementation. +// See Deserialize for decoding transactions stored to disk, such as in a +// database, as opposed to decoding transactions from the wire. func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { err := readElement(r, &msg.Version) if err != nil { @@ -210,8 +212,27 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { return nil } +// Deserialize decodes a transaction from r into the receiver using a format +// that is suitable for long-term storage such as a database while respecting +// the Version field in the transaction. This function differs from BtcDecode +// in that BtcDecode decodes from the bitcoin wire protocol as it was 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 *MsgTx) Deserialize(r io.Reader) 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 BtcDecode. + return msg.BtcDecode(r, 0) +} + // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. // This is part of the Message interface implementation. +// See Serialize for encoding transactions to be stored to disk, such as in a +// database, as opposed to encoding transactions for the wire. func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32) error { err := writeElement(w, msg.Version) if err != nil { @@ -252,6 +273,24 @@ func (msg *MsgTx) 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 *MsgTx) 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, 0) + +} + // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgTx) Command() string { From 29eb4d4250096ecdde3adf421760ed47ef00b65a Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 5 Aug 2013 11:38:41 -0500 Subject: [PATCH 090/219] Add tests for new Serialize/Deserialize functions. --- msgblock_test.go | 67 ++++++++++++++++++ msgtx_test.go | 63 +++++++++++++++++ test_coverage.txt | 169 ++++++++++++++++++++++++---------------------- 3 files changed, 217 insertions(+), 82 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index 6a16ed7d..ed18cfcf 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -291,6 +291,73 @@ func TestBlockWireErrors(t *testing.T) { } } +// TestBlockSerialize tests MsgBlock serialize and deserialize. +func TestBlockSerialize(t *testing.T) { + tests := []struct { + in *btcwire.MsgBlock // Message to encode + out *btcwire.MsgBlock // Expected decoded message + buf []byte // Serialized data + txLocs []btcwire.TxLoc // Expected transaction locations + }{ + { + &blockOne, + &blockOne, + blockOneBytes, + blockOneTxLocs, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Serialize the block. + var buf bytes.Buffer + err := test.in.Serialize(&buf) + if err != nil { + t.Errorf("Serialize #%d error %v", i, err) + continue + } + if !bytes.Equal(buf.Bytes(), test.buf) { + t.Errorf("Serialize #%d\n got: %s want: %s", i, + spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) + continue + } + + // Deserialize the block. + var block btcwire.MsgBlock + rbuf := bytes.NewBuffer(test.buf) + err = block.Deserialize(rbuf) + if err != nil { + t.Errorf("Deserialize #%d error %v", i, err) + continue + } + if !reflect.DeepEqual(&block, test.out) { + t.Errorf("Deserialize #%d\n got: %s want: %s", i, + spew.Sdump(&block), spew.Sdump(test.out)) + continue + } + + // Deserialize the block while gathering transaction location + // information. + var txLocBlock btcwire.MsgBlock + rbuf = bytes.NewBuffer(test.buf) + txLocs, err := txLocBlock.DeserializeTxLoc(rbuf) + if err != nil { + t.Errorf("DeserializeTxLoc #%d error %v", i, err) + continue + } + if !reflect.DeepEqual(&txLocBlock, test.out) { + t.Errorf("DeserializeTxLoc #%d\n got: %s want: %s", i, + spew.Sdump(&txLocBlock), spew.Sdump(test.out)) + continue + } + if !reflect.DeepEqual(txLocs, test.txLocs) { + t.Errorf("DeserializeTxLoc #%d\n got: %s want: %s", i, + spew.Sdump(txLocs), spew.Sdump(test.txLocs)) + continue + } + } +} + var blockOne = btcwire.MsgBlock{ Header: btcwire.BlockHeader{ Version: 1, diff --git a/msgtx_test.go b/msgtx_test.go index d7149e08..9939fc7c 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -119,6 +119,7 @@ func TestTx(t *testing.T) { return } +// TestTxSha tests the ability to generate the hash of a transaction accurately. func TestTxSha(t *testing.T) { pver := btcwire.ProtocolVersion @@ -369,6 +370,68 @@ func TestTxWireErrors(t *testing.T) { } } +// TestTxSerialize tests MsgTx serialize and deserialize. +func TestTxSerialize(t *testing.T) { + noTx := btcwire.NewMsgTx() + noTx.Version = 1 + noTxEncoded := []byte{ + 0x01, 0x00, 0x00, 0x00, // Version + 0x00, // Varint for number of input transactions + 0x00, // Varint for number of output transactions + 0x00, 0x00, 0x00, 0x00, // Lock time + } + + tests := []struct { + in *btcwire.MsgTx // Message to encode + out *btcwire.MsgTx // Expected decoded message + buf []byte // Serialized data + }{ + // No transactions. + { + noTx, + noTx, + noTxEncoded, + }, + + // Multiple transactions. + { + multiTx, + multiTx, + multiTxEncoded, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Serialize the transaction. + var buf bytes.Buffer + err := test.in.Serialize(&buf) + if err != nil { + t.Errorf("Serialize #%d error %v", i, err) + continue + } + if !bytes.Equal(buf.Bytes(), test.buf) { + t.Errorf("Serialize #%d\n got: %s want: %s", i, + spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) + continue + } + + // Deserialize the transaction. + var tx btcwire.MsgTx + rbuf := bytes.NewBuffer(test.buf) + err = tx.Deserialize(rbuf) + if err != nil { + t.Errorf("Deserialize #%d error %v", i, err) + continue + } + if !reflect.DeepEqual(&tx, test.out) { + t.Errorf("Deserialize #%d\n got: %s want: %s", i, + spew.Sdump(&tx), spew.Sdump(test.out)) + continue + } + } +} + // multiTx is a MsgTx with an input and output and used in various tests. var multiTx = &btcwire.MsgTx{ Version: 1, diff --git a/test_coverage.txt b/test_coverage.txt index fce68621..54735189 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -3,151 +3,156 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) -github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) +github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (23/23) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) -github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) +github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (17/17) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 100.00% (16/16) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 100.00% (15/15) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (12/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) -github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) +github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) +github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) -github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) -github.com/conformal/btcwire/common.go readElement 100.00% (1/1) -github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) -github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) -github.com/conformal/btcwire/error.go messageError 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) -github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) +github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) github.com/conformal/btcwire/msgping.go NewMsgPing 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msgpong.go MsgPong.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgpong.go NewMsgPong 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewOutPoint 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewTxIn 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewTxOut 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxIn 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxOut 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) +github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go MsgTx.Deserialize 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go MsgTx.Serialize 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewMsgTx 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) +github.com/conformal/btcwire/common.go readElement 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcDecode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.AddService 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) -github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) +github.com/conformal/btcwire/error.go messageError 100.00% (1/1) +github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (927/927) +github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 86.67% (13/15) +github.com/conformal/btcwire --------------------------------- 99.79% (943/945) From dea1bac359feb878badffe57bdc48added624e73 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 5 Aug 2013 11:50:41 -0500 Subject: [PATCH 091/219] Add negative tests for Serialize/Deserialize funcs. This commit adds tests for the error paths when serializing and deserializing MsgBlock and MsgTx. --- msgblock_test.go | 60 +++++++++++++++++++++++++++++ msgtx_test.go | 61 ++++++++++++++++++++++++++++++ test_coverage.txt | 96 +++++++++++++++++++++++------------------------ 3 files changed, 169 insertions(+), 48 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index ed18cfcf..30aa03b8 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -358,6 +358,66 @@ func TestBlockSerialize(t *testing.T) { } } +// TestBlockSerializeErrors performs negative tests against wire encode and +// decode of MsgBlock to confirm error paths work correctly. +func TestBlockSerializeErrors(t *testing.T) { + tests := []struct { + in *btcwire.MsgBlock // Value to encode + buf []byte // Serialized data + max int // Max size of fixed buffer to induce errors + writeErr error // Expected write error + readErr error // Expected read error + }{ + // Force error in version. + {&blockOne, blockOneBytes, 0, io.ErrShortWrite, io.EOF}, + // Force error in prev block hash. + {&blockOne, blockOneBytes, 4, io.ErrShortWrite, io.EOF}, + // Force error in merkle root. + {&blockOne, blockOneBytes, 36, io.ErrShortWrite, io.EOF}, + // Force error in timestamp. + {&blockOne, blockOneBytes, 68, io.ErrShortWrite, io.EOF}, + // Force error in difficulty bits. + {&blockOne, blockOneBytes, 72, io.ErrShortWrite, io.EOF}, + // Force error in header nonce. + {&blockOne, blockOneBytes, 76, io.ErrShortWrite, io.EOF}, + // Force error in transaction count. + {&blockOne, blockOneBytes, 80, io.ErrShortWrite, io.EOF}, + // Force error in transactions. + {&blockOne, blockOneBytes, 81, io.ErrShortWrite, io.EOF}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Serialize the block. + w := newFixedWriter(test.max) + err := test.in.Serialize(w) + if err != test.writeErr { + t.Errorf("Serialize #%d wrong error got: %v, want: %v", + i, err, test.writeErr) + continue + } + + // Deserialize the block. + var block btcwire.MsgBlock + r := newFixedReader(test.max, test.buf) + err = block.Deserialize(r) + if err != test.readErr { + t.Errorf("Deserialize #%d wrong error got: %v, want: %v", + i, err, test.readErr) + continue + } + + var txLocBlock btcwire.MsgBlock + rbuf := bytes.NewBuffer(test.buf[0:test.max]) + _, err = txLocBlock.DeserializeTxLoc(rbuf) + if err != test.readErr { + t.Errorf("DeserializeTxLoc #%d wrong error got: %v, want: %v", + i, err, test.readErr) + continue + } + } +} + var blockOne = btcwire.MsgBlock{ Header: btcwire.BlockHeader{ Version: 1, diff --git a/msgtx_test.go b/msgtx_test.go index 9939fc7c..99e93610 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -432,6 +432,67 @@ func TestTxSerialize(t *testing.T) { } } +// TestTxSerializeErrors performs negative tests against wire encode and decode +// of MsgTx to confirm error paths work correctly. +func TestTxSerializeErrors(t *testing.T) { + tests := []struct { + in *btcwire.MsgTx // Value to encode + buf []byte // Serialized data + max int // Max size of fixed buffer to induce errors + writeErr error // Expected write error + readErr error // Expected read error + }{ + // Force error in version. + {multiTx, multiTxEncoded, 0, io.ErrShortWrite, io.EOF}, + // Force error in number of transaction inputs. + {multiTx, multiTxEncoded, 4, io.ErrShortWrite, io.EOF}, + // Force error in transaction input previous block hash. + {multiTx, multiTxEncoded, 5, io.ErrShortWrite, io.EOF}, + // Force error in transaction input previous block hash. + {multiTx, multiTxEncoded, 5, io.ErrShortWrite, io.EOF}, + // Force error in transaction input previous block output index. + {multiTx, multiTxEncoded, 37, io.ErrShortWrite, io.EOF}, + // Force error in transaction input signature script length. + {multiTx, multiTxEncoded, 41, io.ErrShortWrite, io.EOF}, + // Force error in transaction input signature script. + {multiTx, multiTxEncoded, 42, io.ErrShortWrite, io.EOF}, + // Force error in transaction input sequence. + {multiTx, multiTxEncoded, 49, io.ErrShortWrite, io.EOF}, + // Force error in number of transaction outputs. + {multiTx, multiTxEncoded, 53, io.ErrShortWrite, io.EOF}, + // Force error in transaction output value. + {multiTx, multiTxEncoded, 54, io.ErrShortWrite, io.EOF}, + // Force error in transaction output pk script length. + {multiTx, multiTxEncoded, 62, io.ErrShortWrite, io.EOF}, + // Force error in transaction output pk script. + {multiTx, multiTxEncoded, 63, io.ErrShortWrite, io.EOF}, + // Force error in transaction output lock time. + {multiTx, multiTxEncoded, 130, io.ErrShortWrite, io.EOF}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Serialize the transaction. + w := newFixedWriter(test.max) + err := test.in.Serialize(w) + if err != test.writeErr { + t.Errorf("Serialize #%d wrong error got: %v, want: %v", + i, err, test.writeErr) + continue + } + + // Deserialize the transaction. + var tx btcwire.MsgTx + r := newFixedReader(test.max, test.buf) + err = tx.Deserialize(r) + if err != test.readErr { + t.Errorf("Deserialize #%d wrong error got: %v, want: %v", + i, err, test.readErr) + continue + } + } +} + // multiTx is a MsgTx with an input and output and used in various tests. var multiTx = &btcwire.MsgTx{ Version: 1, diff --git a/test_coverage.txt b/test_coverage.txt index 54735189..f91fd898 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -19,91 +19,91 @@ github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 100.00% (15/15) +github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (12/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (12/12) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) +github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) -github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (4/4) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) -github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) -github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) github.com/conformal/btcwire/msgping.go NewMsgPing 100.00% (1/1) +github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msgpong.go MsgPong.Command 100.00% (1/1) github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgpong.go NewMsgPong 100.00% (1/1) @@ -132,27 +132,27 @@ github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) +github.com/conformal/btcwire/error.go messageError 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.AddService 100.00% (1/1) github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) +github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) -github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/error.go messageError 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) -github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 86.67% (13/15) -github.com/conformal/btcwire --------------------------------- 99.79% (943/945) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire --------------------------------- 100.00% (945/945) From d90740728e2d6deec396bb2b3b2a91f31c8622ff Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 5 Aug 2013 16:24:50 -0500 Subject: [PATCH 092/219] Remove protocol version param from BlockSha/Txsha. Both of these depend on the serialized bytes which are dependent on the version field in the block/transaction. They must be independent of the protocol version so there is no need to require it. --- blockheader.go | 4 ++-- genesis_test.go | 18 ++++++------------ msgblock.go | 8 ++++---- msgblock_test.go | 19 ++++--------------- msgtx.go | 4 ++-- msgtx_test.go | 4 +--- 6 files changed, 19 insertions(+), 38 deletions(-) diff --git a/blockheader.go b/blockheader.go index 3294d566..2b74fcc9 100644 --- a/blockheader.go +++ b/blockheader.go @@ -50,7 +50,7 @@ type BlockHeader struct { const blockHashLen = 80 // BlockSha computes the block identifier hash for the given block header. -func (h *BlockHeader) BlockSha(pver uint32) (ShaHash, error) { +func (h *BlockHeader) BlockSha() (ShaHash, error) { // Encode the header and run double sha256 everything prior to the // number of transactions. Ignore the error returns since there is no // way the encode could fail except being out of memory which would @@ -59,7 +59,7 @@ func (h *BlockHeader) BlockSha(pver uint32) (ShaHash, error) { // regardless of input. var buf bytes.Buffer var sha ShaHash - _ = writeBlockHeader(&buf, pver, h) + _ = writeBlockHeader(&buf, 0, h) _ = sha.SetBytes(DoubleSha256(buf.Bytes()[0:blockHashLen])) // Even though this function can't currently fail, it still returns diff --git a/genesis_test.go b/genesis_test.go index 85771a0d..e886b824 100644 --- a/genesis_test.go +++ b/genesis_test.go @@ -14,11 +14,9 @@ import ( // TestGenesisBlock tests the genesis block of the main network for validity by // checking the encoded bytes and hashes. func TestGenesisBlock(t *testing.T) { - pver := uint32(60002) - // Encode the genesis block to raw bytes. var buf bytes.Buffer - err := btcwire.GenesisBlock.BtcEncode(&buf, pver) + err := btcwire.GenesisBlock.Serialize(&buf) if err != nil { t.Errorf("TestGenesisBlock: %v", err) return @@ -33,7 +31,7 @@ func TestGenesisBlock(t *testing.T) { } // Check hash of the block against expected hash. - hash, err := btcwire.GenesisBlock.Header.BlockSha(pver) + hash, err := btcwire.GenesisBlock.BlockSha() if err != nil { t.Errorf("BlockSha: %v", err) } @@ -48,11 +46,9 @@ func TestGenesisBlock(t *testing.T) { // TestTestNetGenesisBlock tests the genesis block of the regression test // network for validity by checking the encoded bytes and hashes. func TestTestNetGenesisBlock(t *testing.T) { - pver := uint32(60002) - // Encode the genesis block to raw bytes. var buf bytes.Buffer - err := btcwire.TestNetGenesisBlock.BtcEncode(&buf, pver) + err := btcwire.TestNetGenesisBlock.Serialize(&buf) if err != nil { t.Errorf("TestTestNetGenesisBlock: %v", err) return @@ -68,7 +64,7 @@ func TestTestNetGenesisBlock(t *testing.T) { } // Check hash of the block against expected hash. - hash, err := btcwire.TestNetGenesisBlock.Header.BlockSha(pver) + hash, err := btcwire.TestNetGenesisBlock.BlockSha() if err != nil { t.Errorf("BlockSha: %v", err) } @@ -83,11 +79,9 @@ func TestTestNetGenesisBlock(t *testing.T) { // TestTestNet3GenesisBlock tests the genesis block of the test network (version // 3) for validity by checking the encoded bytes and hashes. func TestTestNet3GenesisBlock(t *testing.T) { - pver := uint32(60002) - // Encode the genesis block to raw bytes. var buf bytes.Buffer - err := btcwire.TestNet3GenesisBlock.BtcEncode(&buf, pver) + err := btcwire.TestNet3GenesisBlock.Serialize(&buf) if err != nil { t.Errorf("TestTestNet3GenesisBlock: %v", err) return @@ -103,7 +97,7 @@ func TestTestNet3GenesisBlock(t *testing.T) { } // Check hash of the block against expected hash. - hash, err := btcwire.TestNet3GenesisBlock.Header.BlockSha(pver) + hash, err := btcwire.TestNet3GenesisBlock.BlockSha() if err != nil { t.Errorf("BlockSha: %v", err) } diff --git a/msgblock.go b/msgblock.go index 1b288703..209591a7 100644 --- a/msgblock.go +++ b/msgblock.go @@ -206,17 +206,17 @@ func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 { } // BlockSha computes the block identifier hash for this block. -func (msg *MsgBlock) BlockSha(pver uint32) (ShaHash, error) { - return msg.Header.BlockSha(pver) +func (msg *MsgBlock) BlockSha() (ShaHash, error) { + return msg.Header.BlockSha() } // TxShas returns a slice of hashes of all of transactions in this block. -func (msg *MsgBlock) TxShas(pver uint32) ([]ShaHash, error) { +func (msg *MsgBlock) TxShas() ([]ShaHash, error) { var shaList []ShaHash for _, tx := range msg.Transactions { // Ignore error here since TxSha can't fail in the current // implementation except due to run-time panics. - sha, _ := tx.TxSha(pver) + sha, _ := tx.TxSha() shaList = append(shaList, sha) } return shaList, nil diff --git a/msgblock_test.go b/msgblock_test.go index 30aa03b8..3273ee51 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -71,11 +71,6 @@ func TestBlock(t *testing.T) { // TestBlockTxShas tests the ability to generate a slice of all transaction // hashes from a block accurately. func TestBlockTxShas(t *testing.T) { - // Use protocol version 60002 specifically here instead of the latest - // because the test data is using bytes encoded with that protocol - // version. - pver := uint32(60002) - // Block 1, transaction 1 hash. hashStr := "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098" wantHash, err := btcwire.NewShaHashFromStr(hashStr) @@ -85,7 +80,7 @@ func TestBlockTxShas(t *testing.T) { } wantShas := []btcwire.ShaHash{*wantHash} - shas, err := blockOne.TxShas(pver) + shas, err := blockOne.TxShas() if err != nil { t.Errorf("TxShas: %v", err) } @@ -97,11 +92,6 @@ func TestBlockTxShas(t *testing.T) { // TestBlockSha tests the ability to generate the hash of a block accurately. func TestBlockSha(t *testing.T) { - // Use protocol version 60002 specifically here instead of the latest - // because the test data is using bytes encoded with that protocol - // version. - pver := uint32(60002) - // Block 1 hash. hashStr := "839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048" wantHash, err := btcwire.NewShaHashFromStr(hashStr) @@ -110,7 +100,7 @@ func TestBlockSha(t *testing.T) { } // Ensure the hash produced is expected. - blockHash, err := blockOne.BlockSha(pver) + blockHash, err := blockOne.BlockSha() if err != nil { t.Errorf("BlockSha: %v", err) } @@ -477,7 +467,7 @@ var blockOne = btcwire.MsgBlock{ }, } -// Block one bytes encoded with protocol version 60002. +// Block one serialized bytes. var blockOneBytes = []byte{ 0x01, 0x00, 0x00, 0x00, // Version 1 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, @@ -519,8 +509,7 @@ var blockOneBytes = []byte{ 0x00, 0x00, 0x00, 0x00, // Lock time } -// Transaction location information for block one trasnactions as encoded with -// protocol version 60002. +// Transaction location information for block one transactions. var blockOneTxLocs = []btcwire.TxLoc{ btcwire.TxLoc{TxStart: 81, TxLen: 134}, } diff --git a/msgtx.go b/msgtx.go index 0983c81c..91f4c127 100644 --- a/msgtx.go +++ b/msgtx.go @@ -89,7 +89,7 @@ func (msg *MsgTx) AddTxOut(to *TxOut) { } // TxSha generates the ShaHash name for the transaction. -func (tx *MsgTx) TxSha(pver uint32) (ShaHash, error) { +func (tx *MsgTx) TxSha() (ShaHash, error) { // Encode the transaction and calculate double sha256 on the result. // Ignore the error returns since the only way the encode could fail // is being out of memory or due to nil pointers, both of which would @@ -98,7 +98,7 @@ func (tx *MsgTx) TxSha(pver uint32) (ShaHash, error) { // regardless of input. var buf bytes.Buffer var sha ShaHash - _ = tx.BtcEncode(&buf, pver) + _ = tx.Serialize(&buf) _ = sha.SetBytes(DoubleSha256(buf.Bytes())) // Even though this function can't currently fail, it still returns diff --git a/msgtx_test.go b/msgtx_test.go index 99e93610..85a511ed 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -121,8 +121,6 @@ func TestTx(t *testing.T) { // TestTxSha tests the ability to generate the hash of a transaction accurately. func TestTxSha(t *testing.T) { - pver := btcwire.ProtocolVersion - // Hash of first transaction from block 113875. hashStr := "f051e59b5e2503ac626d03aaeac8ab7be2d72ba4b7e97119c5852d70d52dcb86" wantHash, err := btcwire.NewShaHashFromStr(hashStr) @@ -162,7 +160,7 @@ func TestTxSha(t *testing.T) { msgTx.LockTime = 0 // Ensure the hash produced is expected. - txHash, err := msgTx.TxSha(pver) + txHash, err := msgTx.TxSha() if err != nil { t.Errorf("TxSha: %v", err) } From b4b7204a9713a71b8eaff44aec5eddf55ccf0239 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 5 Aug 2013 19:18:45 -0500 Subject: [PATCH 093/219] Remove BtcDecodeTxLoc since it has been replaced. BtcDecodeTxLoc is no longer needed since it has been replaced by DeserializeTxLoc. --- msgblock.go | 28 --------- msgblock_test.go | 27 -------- test_coverage.txt | 155 +++++++++++++++++++++++----------------------- 3 files changed, 77 insertions(+), 133 deletions(-) diff --git a/msgblock.go b/msgblock.go index 209591a7..5f6d72b8 100644 --- a/msgblock.go +++ b/msgblock.go @@ -77,34 +77,6 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32) error { return nil } -// BtcDecodeTxLoc decodes r using the bitcoin protocol encoding into the -// receiver and returns a slice containing the start and length of each -// transaction within the raw data. -func (msg *MsgBlock) BtcDecodeTxLoc(r *bytes.Buffer, pver uint32) ([]TxLoc, error) { - fullLen := r.Len() - err := readBlockHeader(r, pver, &msg.Header) - if err != nil { - return nil, err - } - - // Decode each transaction while keeping track of its location within - // the byte stream. - txCount := msg.Header.TxnCount - txLocs := make([]TxLoc, txCount) - for i := uint64(0); i < txCount; i++ { - txLocs[i].TxStart = fullLen - r.Len() - tx := MsgTx{} - err := tx.BtcDecode(r, pver) - if err != nil { - return nil, err - } - msg.Transactions = append(msg.Transactions, &tx) - txLocs[i].TxLen = (fullLen - r.Len()) - txLocs[i].TxStart - } - - return txLocs, nil -} - // Deserialize decodes a block from r into the receiver using a format that is // suitable for long-term storage such as a database while respecting the // Version field in the block. This function differs from BtcDecode in that diff --git a/msgblock_test.go b/msgblock_test.go index 3273ee51..16184533 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -194,24 +194,6 @@ func TestBlockWire(t *testing.T) { spew.Sdump(&msg), spew.Sdump(test.out)) continue } - - var txLocMsg btcwire.MsgBlock - rbuf = bytes.NewBuffer(test.buf) - txLocs, err := txLocMsg.BtcDecodeTxLoc(rbuf, test.pver) - if err != nil { - t.Errorf("BtcDecodeTxLoc #%d error %v", i, err) - continue - } - if !reflect.DeepEqual(&txLocMsg, test.out) { - t.Errorf("BtcDecodeTxLoc #%d\n got: %s want: %s", i, - spew.Sdump(&txLocMsg), spew.Sdump(test.out)) - continue - } - if !reflect.DeepEqual(txLocs, test.txLocs) { - t.Errorf("BtcDecodeTxLoc #%d\n got: %s want: %s", i, - spew.Sdump(txLocs), spew.Sdump(test.txLocs)) - continue - } } } @@ -269,15 +251,6 @@ func TestBlockWireErrors(t *testing.T) { i, err, test.readErr) continue } - - var txLocMsg btcwire.MsgBlock - rbuf := bytes.NewBuffer(test.buf[0:test.max]) - _, err = txLocMsg.BtcDecodeTxLoc(rbuf, test.pver) - if err != test.readErr { - t.Errorf("BtcDecodeTxLoc #%d wrong error got: %v, want: %v", - i, err, test.readErr) - continue - } } } diff --git a/test_coverage.txt b/test_coverage.txt index f91fd898..0d93c31f 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -3,8 +3,8 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) -github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) +github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (23/23) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) @@ -14,145 +14,144 @@ github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (17/17) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) -github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecodeTxLoc 100.00% (15/15) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (15/15) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) +github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (12/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (4/4) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (4/4) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) +github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msgping.go NewMsgPing 100.00% (1/1) -github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) github.com/conformal/btcwire/msgpong.go MsgPong.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgpong.go NewMsgPong 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewOutPoint 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewTxIn 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewTxOut 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxIn 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxOut 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) -github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Deserialize 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Serialize 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewMsgTx 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) github.com/conformal/btcwire/common.go readElement 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) +github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcDecode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) -github.com/conformal/btcwire/error.go messageError 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.AddService 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) -github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) -github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) -github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) +github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) +github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) +github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) +github.com/conformal/btcwire/error.go messageError 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (945/945) +github.com/conformal/btcwire --------------------------------- 100.00% (930/930) From 335736e59f4d6b84794d5046af2b2c6da5e30c78 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 25 Jul 2013 15:30:18 -0500 Subject: [PATCH 094/219] Add new func NetAddressIPPort. This function is a convenience method to create a new NetAddress from a net.IP and uint16 port as opposed to a net.Addr which must be of type *net.TCPAddr. This allows callers to support connection types that don't provide access to a concrete *net.TCPAddr implementation. --- netaddress.go | 21 ++++++++++++++------- test_coverage.txt | 19 ++++++++++--------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/netaddress.go b/netaddress.go index b8db7468..446a9939 100644 --- a/netaddress.go +++ b/netaddress.go @@ -72,6 +72,18 @@ func (na *NetAddress) SetAddress(ip net.IP, port uint16) { na.Port = port } +// NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and +// supported services with defaults for the remaining fields. +func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress { + na := NetAddress{ + Timestamp: time.Now(), + Services: services, + IP: ip, + Port: port, + } + return &na +} + // NewNetAddress returns a new NetAddress using the provided TCP address and // supported services with defaults for the remaining fields. // @@ -83,13 +95,8 @@ func NewNetAddress(addr net.Addr, services ServiceFlag) (*NetAddress, error) { return nil, ErrInvalidNetAddr } - na := NetAddress{ - Timestamp: time.Now(), - Services: services, - IP: tcpAddr.IP, - Port: uint16(tcpAddr.Port), - } - return &na, nil + na := NewNetAddressIPPort(tcpAddr.IP, uint16(tcpAddr.Port), services) + return na, nil } // readNetAddress reads an encoded NetAddress from r depending on the protocol diff --git a/test_coverage.txt b/test_coverage.txt index 0d93c31f..7a6c0081 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,10 +1,10 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) -github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) +github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (23/23) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) @@ -32,12 +32,12 @@ github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) -github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) +github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) +github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) @@ -75,16 +75,16 @@ github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (4/4) github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) -github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) +github.com/conformal/btcwire/netaddress.go NewNetAddressIPPort 100.00% (2/2) github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) @@ -153,5 +153,6 @@ github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (930/930) +github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) +github.com/conformal/btcwire --------------------------------- 100.00% (932/932) From 8679275090e99c66e7026b0bb521e36058e6f90d Mon Sep 17 00:00:00 2001 From: Andrew Tian Date: Mon, 12 Aug 2013 22:53:50 -0500 Subject: [PATCH 095/219] Fix doc example typo --- doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc.go b/doc.go index 0a6ecd1b..dad217f6 100644 --- a/doc.go +++ b/doc.go @@ -96,7 +96,7 @@ switch or type assertion. An example of a type switch follows: // Assumes msg is already a valid concrete message such as one created // via NewMsgVersion or read via ReadMessage. - switch msg.(type) { + switch msg := msg.(type) { case *btcwire.MsgVersion: // The message is a pointer to a MsgVersion struct. fmt.Printf("Protocol version: %v", msg.ProtocolVersion) From e7f808378ec8893a8e5f0aa193c752e8abe6ed42 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 19 Sep 2013 16:46:14 -0500 Subject: [PATCH 096/219] Make max payload for a transaction max block size. The maximum payload for a transaction is limited to the size of a block rather than the maximum payload for a given message. --- msgtx.go | 2 +- msgtx_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/msgtx.go b/msgtx.go index 91f4c127..0e5b1d1b 100644 --- a/msgtx.go +++ b/msgtx.go @@ -300,7 +300,7 @@ func (msg *MsgTx) Command() string { // MaxPayloadLength returns the maximum length the payload can be for the // receiver. This is part of the Message interface implementation. func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 { - return maxMessagePayload + return MaxBlockPayload } // NewMsgTx returns a new bitcoin tx message that conforms to the Message diff --git a/msgtx_test.go b/msgtx_test.go index 85a511ed..9f003dc1 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -34,7 +34,7 @@ func TestTx(t *testing.T) { // Ensure max payload is expected value for latest protocol version. // Num addresses (varInt) + max allowed addresses. - wantPayload := uint32(1024 * 1024 * 32) + wantPayload := uint32(1000 * 1000) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { t.Errorf("MaxPayloadLength: wrong max payload length for "+ From 5f971e10e626cdb48d2ef0dd834d943408274280 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 25 Sep 2013 13:57:01 -0500 Subject: [PATCH 097/219] Pre-allocate space for slices. Several of the messages store the parts that have a variable number of elements as slices. This commit modifies the code to choose sane defaults for the backing arrays for the slices so when the entries are actually appended, a lot of the overhead of growing the backing arrays and copying the data multiple times is avoided. Along the same lines, when decoding messages, the actual size is known and now is pre-allocated instead of dynamically growing the backing array thereby avoiding some overhead. --- msgaddr.go | 5 ++++- msgblock.go | 16 +++++++++++++--- msggetblocks.go | 6 ++++-- msggetdata.go | 5 ++++- msggetheaders.go | 5 ++++- msgheaders.go | 5 ++++- msginv.go | 14 +++++++++++++- msgnotfound.go | 5 ++++- msgtx.go | 20 ++++++++++++++++++-- test_coverage.txt | 30 +++++++++++++++--------------- 10 files changed, 83 insertions(+), 28 deletions(-) diff --git a/msgaddr.go b/msgaddr.go index 13371c5c..b4dcfb12 100644 --- a/msgaddr.go +++ b/msgaddr.go @@ -70,6 +70,7 @@ func (msg *MsgAddr) BtcDecode(r io.Reader, pver uint32) error { return messageError("MsgAddr.BtcDecode", str) } + msg.AddrList = make([]*NetAddress, 0, count) for i := uint64(0); i < count; i++ { na := NetAddress{} err := readNetAddress(r, pver, &na, true) @@ -135,5 +136,7 @@ func (msg *MsgAddr) MaxPayloadLength(pver uint32) uint32 { // NewMsgAddr returns a new bitcoin addr message that conforms to the // Message interface. See MsgAddr for details. func NewMsgAddr() *MsgAddr { - return &MsgAddr{} + return &MsgAddr{ + AddrList: make([]*NetAddress, 0, MaxAddrPerMsg), + } } diff --git a/msgblock.go b/msgblock.go index 5f6d72b8..7ad79a3e 100644 --- a/msgblock.go +++ b/msgblock.go @@ -9,6 +9,13 @@ import ( "io" ) +// defaultTransactionAlloc is the default size used for the backing array +// for transactions. The transaction array will dynamically grow as needed, but +// this figure is intended to provide enough space for the number of +// transactions in the vast majority of blocks without needing to grow the +// backing array multiple times. +const defaultTransactionAlloc = 2048 + // MaxBlocksPerMsg is the maximum number of blocks allowed per message. const MaxBlocksPerMsg = 500 @@ -51,7 +58,7 @@ func (msg *MsgBlock) AddTransaction(tx *MsgTx) error { // ClearTransactions removes all transactions from the message and updates // Header.TxnCount accordingly. func (msg *MsgBlock) ClearTransactions() { - msg.Transactions = []*MsgTx{} + msg.Transactions = make([]*MsgTx, 0, defaultTransactionAlloc) msg.Header.TxnCount = 0 } @@ -65,6 +72,7 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32) error { return err } + msg.Transactions = make([]*MsgTx, 0, msg.Header.TxnCount) for i := uint64(0); i < msg.Header.TxnCount; i++ { tx := MsgTx{} err := tx.BtcDecode(r, pver) @@ -110,6 +118,7 @@ func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) { // Deserialize each transaction while keeping track of its location // within the byte stream. txCount := msg.Header.TxnCount + msg.Transactions = make([]*MsgTx, 0, txCount) txLocs := make([]TxLoc, txCount) for i := uint64(0); i < txCount; i++ { txLocs[i].TxStart = fullLen - r.Len() @@ -184,7 +193,7 @@ func (msg *MsgBlock) BlockSha() (ShaHash, error) { // TxShas returns a slice of hashes of all of transactions in this block. func (msg *MsgBlock) TxShas() ([]ShaHash, error) { - var shaList []ShaHash + shaList := make([]ShaHash, 0, len(msg.Transactions)) for _, tx := range msg.Transactions { // Ignore error here since TxSha can't fail in the current // implementation except due to run-time panics. @@ -198,6 +207,7 @@ func (msg *MsgBlock) TxShas() ([]ShaHash, error) { // Message interface. See MsgBlock for details. func NewMsgBlock(blockHeader *BlockHeader) *MsgBlock { return &MsgBlock{ - Header: *blockHeader, + Header: *blockHeader, + Transactions: make([]*MsgTx, 0, defaultTransactionAlloc), } } diff --git a/msggetblocks.go b/msggetblocks.go index b10eb7e6..9f083630 100644 --- a/msggetblocks.go +++ b/msggetblocks.go @@ -65,6 +65,7 @@ func (msg *MsgGetBlocks) BtcDecode(r io.Reader, pver uint32) error { return messageError("MsgGetBlocks.BtcDecode", str) } + msg.BlockLocatorHashes = make([]*ShaHash, 0, count) for i := uint64(0); i < count; i++ { sha := ShaHash{} err := readElement(r, &sha) @@ -136,7 +137,8 @@ func (msg *MsgGetBlocks) MaxPayloadLength(pver uint32) uint32 { // fields. func NewMsgGetBlocks(hashStop *ShaHash) *MsgGetBlocks { return &MsgGetBlocks{ - ProtocolVersion: ProtocolVersion, - HashStop: *hashStop, + ProtocolVersion: ProtocolVersion, + BlockLocatorHashes: make([]*ShaHash, 0, MaxBlockLocatorsPerMsg), + HashStop: *hashStop, } } diff --git a/msggetdata.go b/msggetdata.go index e4f546eb..c58d89cb 100644 --- a/msggetdata.go +++ b/msggetdata.go @@ -49,6 +49,7 @@ func (msg *MsgGetData) BtcDecode(r io.Reader, pver uint32) error { return messageError("MsgGetData.BtcDecode", str) } + msg.InvList = make([]*InvVect, 0, count) for i := uint64(0); i < count; i++ { iv := InvVect{} err := readInvVect(r, pver, &iv) @@ -102,5 +103,7 @@ func (msg *MsgGetData) MaxPayloadLength(pver uint32) uint32 { // NewMsgGetData returns a new bitcoin getdata message that conforms to the // Message interface. See MsgGetData for details. func NewMsgGetData() *MsgGetData { - return &MsgGetData{} + return &MsgGetData{ + InvList: make([]*InvVect, 0, defaultInvListAlloc), + } } diff --git a/msggetheaders.go b/msggetheaders.go index 50a6b023..b360203a 100644 --- a/msggetheaders.go +++ b/msggetheaders.go @@ -62,6 +62,7 @@ func (msg *MsgGetHeaders) BtcDecode(r io.Reader, pver uint32) error { return messageError("MsgGetHeaders.BtcDecode", str) } + msg.BlockLocatorHashes = make([]*ShaHash, 0, count) for i := uint64(0); i < count; i++ { sha := ShaHash{} err := readElement(r, &sha) @@ -132,5 +133,7 @@ func (msg *MsgGetHeaders) MaxPayloadLength(pver uint32) uint32 { // NewMsgGetHeaders returns a new bitcoin getheaders message that conforms to // the Message interface. See MsgGetHeaders for details. func NewMsgGetHeaders() *MsgGetHeaders { - return &MsgGetHeaders{} + return &MsgGetHeaders{ + BlockLocatorHashes: make([]*ShaHash, 0, MaxBlockLocatorsPerMsg), + } } diff --git a/msgheaders.go b/msgheaders.go index 3aa5d160..294955a1 100644 --- a/msgheaders.go +++ b/msgheaders.go @@ -49,6 +49,7 @@ func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32) error { return messageError("MsgHeaders.BtcDecode", str) } + msg.Headers = make([]*BlockHeader, 0, count) for i := uint64(0); i < count; i++ { bh := BlockHeader{} err := readBlockHeader(r, pver, &bh) @@ -117,5 +118,7 @@ func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 { // NewMsgHeaders returns a new bitcoin headers message that conforms to the // Message interface. See MsgHeaders for details. func NewMsgHeaders() *MsgHeaders { - return &MsgHeaders{} + return &MsgHeaders{ + Headers: make([]*BlockHeader, 0, MaxBlockHeadersPerMsg), + } } diff --git a/msginv.go b/msginv.go index 015f4a81..96538af8 100644 --- a/msginv.go +++ b/msginv.go @@ -9,6 +9,15 @@ import ( "io" ) +// defaultInvListAlloc is the default size used for the backing array for an +// inventory list. The array will dynamically grow as needed, but this +// figure is intended to provide enough space for the max number of inventory +// vectors in a *typical* inventory message without needing to grow the backing +// array multiple times. Technically, the list can grow to MaxInvPerMsg, but +// rather than using that large figure, this figure more accurately reflects the +// typical case. +const defaultInvListAlloc = 1000 + // MsgInv implements the Message interface and represents a bitcoin inv message. // It is used to advertise a peer's known data such as blocks and transactions // through inventory vectors. It may be sent unsolicited to inform other peers @@ -48,6 +57,7 @@ func (msg *MsgInv) BtcDecode(r io.Reader, pver uint32) error { return messageError("MsgInv.BtcDecode", str) } + msg.InvList = make([]*InvVect, 0, count) for i := uint64(0); i < count; i++ { iv := InvVect{} err := readInvVect(r, pver, &iv) @@ -101,5 +111,7 @@ func (msg *MsgInv) MaxPayloadLength(pver uint32) uint32 { // NewMsgInv returns a new bitcoin inv message that conforms to the Message // interface. See MsgInv for details. func NewMsgInv() *MsgInv { - return &MsgInv{} + return &MsgInv{ + InvList: make([]*InvVect, 0, defaultInvListAlloc), + } } diff --git a/msgnotfound.go b/msgnotfound.go index 1fbfd155..0370d104 100644 --- a/msgnotfound.go +++ b/msgnotfound.go @@ -46,6 +46,7 @@ func (msg *MsgNotFound) BtcDecode(r io.Reader, pver uint32) error { return messageError("MsgNotFound.BtcDecode", str) } + msg.InvList = make([]*InvVect, 0, count) for i := uint64(0); i < count; i++ { iv := InvVect{} err := readInvVect(r, pver, &iv) @@ -100,5 +101,7 @@ func (msg *MsgNotFound) MaxPayloadLength(pver uint32) uint32 { // NewMsgNotFound returns a new bitcoin notfound message that conforms to the // Message interface. See MsgNotFound for details. func NewMsgNotFound() *MsgNotFound { - return &MsgNotFound{} + return &MsgNotFound{ + InvList: make([]*InvVect, 0, defaultInvListAlloc), + } } diff --git a/msgtx.go b/msgtx.go index 0e5b1d1b..cdccbcc7 100644 --- a/msgtx.go +++ b/msgtx.go @@ -9,6 +9,13 @@ import ( "io" ) +// defaultTxInOutAlloc is the default size used for the backing array for +// transaction inputs and outputs. The array will dynamically grow as needed, +// but this figure is intended to provide enough space for the number of +// inputs and outputs in a typical transaction without needing to grow the +// backing array multiple times. +const defaultTxInOutAlloc = 15 + // TxVersion is the current latest supported transaction version. const TxVersion = 1 @@ -110,9 +117,12 @@ func (tx *MsgTx) TxSha() (ShaHash, error) { // Copy creates a deep copy of a transaction so that the original does not get // modified when the copy is manipulated. func (tx *MsgTx) Copy() *MsgTx { - // Create new tx and start by copying primitive values. + // Create new tx and start by copying primitive values and making space + // for the transaction inputs and outputs. newTx := MsgTx{ Version: tx.Version, + TxIn: make([]*TxIn, 0, len(tx.TxIn)), + TxOut: make([]*TxOut, 0, len(tx.TxOut)), LockTime: tx.LockTime, } @@ -181,6 +191,7 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { return err } + msg.TxIn = make([]*TxIn, 0, count) for i := uint64(0); i < count; i++ { ti := TxIn{} err = readTxIn(r, pver, msg.Version, &ti) @@ -195,6 +206,7 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { return err } + msg.TxOut = make([]*TxOut, 0, count) for i := uint64(0); i < count; i++ { to := TxOut{} err = readTxOut(r, pver, msg.Version, &to) @@ -309,7 +321,11 @@ func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 { // to indicate the transaction is valid immediately as opposed to some time in // future. func NewMsgTx() *MsgTx { - return &MsgTx{Version: TxVersion} + return &MsgTx{ + Version: TxVersion, + TxIn: make([]*TxIn, 0, defaultTxInOutAlloc), + TxOut: make([]*TxOut, 0, defaultTxInOutAlloc), + } } // readOutPoint reads the next sequence of bytes from r as an OutPoint. diff --git a/test_coverage.txt b/test_coverage.txt index 7a6c0081..2dd4557f 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,49 +1,49 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (27/27) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (23/23) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (19/19) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (19/19) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (17/17) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (16/16) -github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (15/15) +github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (16/16) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (13/13) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (13/13) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (12/12) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (10/10) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (11/11) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) +github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) @@ -154,5 +154,5 @@ github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1 github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (932/932) +github.com/conformal/btcwire --------------------------------- 100.00% (943/943) From 95ecbadb8e58cd2c0212d56b2456cc7a6587668d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 6 Oct 2013 22:06:34 -0500 Subject: [PATCH 098/219] Ensure readVarInt handles short buf on first byte. It is technically possible for the Read method on a reader to return zero bytes read with a nil error even though that behavior is "discouraged" by the interface documenation. This commit switches the read of the first byte to use io.ReadFull which will always error in this case. --- common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.go b/common.go index 649d142d..21666892 100644 --- a/common.go +++ b/common.go @@ -53,7 +53,7 @@ func writeElements(w io.Writer, elements ...interface{}) error { // readVarInt reads a variable length integer from r and returns it as a uint64. func readVarInt(r io.Reader, pver uint32) (uint64, error) { b := make([]byte, 1) - _, err := r.Read(b) + _, err := io.ReadFull(r, b) if err != nil { return 0, err } From 93d86305a2ef3da7b6d192258d6d41dffe36472d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 8 Oct 2013 15:36:20 -0500 Subject: [PATCH 099/219] Deprecate InvVect_* constants in favor of InvType*. This commit changes the InvVect_* constants, which are not standard Go style, to the InvType*. In order to preserve backwards compatibility, it also adds a legacy.go file which maps the old public constant names to the new ones. Closes #1. --- invvect.go | 12 ++++++------ invvect_test.go | 20 ++++++++++---------- legacy.go | 14 ++++++++++++++ msggetdata_test.go | 14 +++++++------- msginv_test.go | 14 +++++++------- msgnotfound_test.go | 14 +++++++------- 6 files changed, 51 insertions(+), 37 deletions(-) create mode 100644 legacy.go diff --git a/invvect.go b/invvect.go index c74a9b50..1cac91b5 100644 --- a/invvect.go +++ b/invvect.go @@ -23,16 +23,16 @@ type InvType uint32 // These constants define the various supported inventory vector types. const ( - InvVect_Error InvType = 0 - InvVect_Tx InvType = 1 - InvVect_Block InvType = 2 + InvTypeError InvType = 0 + InvTypeTx InvType = 1 + InvTypeBlock InvType = 2 ) // Map of service flags back to their constant names for pretty printing. var ivStrings = map[InvType]string{ - InvVect_Error: "ERROR", - InvVect_Tx: "MSG_TX", - InvVect_Block: "MSG_BLOCK", + InvTypeError: "ERROR", + InvTypeTx: "MSG_TX", + InvTypeBlock: "MSG_BLOCK", } // String returns the InvType in human-readable form. diff --git a/invvect_test.go b/invvect_test.go index d374c976..6a80531f 100644 --- a/invvect_test.go +++ b/invvect_test.go @@ -18,9 +18,9 @@ func TestInvTypeStringer(t *testing.T) { in btcwire.InvType want string }{ - {btcwire.InvVect_Error, "ERROR"}, - {btcwire.InvVect_Tx, "MSG_TX"}, - {btcwire.InvVect_Block, "MSG_BLOCK"}, + {btcwire.InvTypeError, "ERROR"}, + {btcwire.InvTypeTx, "MSG_TX"}, + {btcwire.InvTypeBlock, "MSG_BLOCK"}, {0xffffffff, "Unknown InvType (4294967295)"}, } @@ -38,7 +38,7 @@ func TestInvTypeStringer(t *testing.T) { // TestInvVect tests the InvVect API. func TestInvVect(t *testing.T) { - ivType := btcwire.InvVect_Block + ivType := btcwire.InvTypeBlock hash := btcwire.ShaHash{} // Ensure we get the same payload and signature back out. @@ -66,13 +66,13 @@ func TestInvVectWire(t *testing.T) { // errInvVect is an inventory vector with an error. errInvVect := btcwire.InvVect{ - Type: btcwire.InvVect_Error, + Type: btcwire.InvTypeError, Hash: btcwire.ShaHash{}, } // errInvVectEncoded is the wire encoded bytes of errInvVect. errInvVectEncoded := []byte{ - 0x00, 0x00, 0x00, 0x00, // InvVect_Error + 0x00, 0x00, 0x00, 0x00, // InvTypeError 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -81,13 +81,13 @@ func TestInvVectWire(t *testing.T) { // txInvVect is an inventory vector representing a transaction. txInvVect := btcwire.InvVect{ - Type: btcwire.InvVect_Tx, + Type: btcwire.InvTypeTx, Hash: *baseHash, } // txInvVectEncoded is the wire encoded bytes of txInvVect. txInvVectEncoded := []byte{ - 0x01, 0x00, 0x00, 0x00, // InvVect_Tx + 0x01, 0x00, 0x00, 0x00, // InvTypeTx 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, @@ -96,13 +96,13 @@ func TestInvVectWire(t *testing.T) { // blockInvVect is an inventory vector representing a block. blockInvVect := btcwire.InvVect{ - Type: btcwire.InvVect_Block, + Type: btcwire.InvTypeBlock, Hash: *baseHash, } // blockInvVectEncoded is the wire encoded bytes of blockInvVect. blockInvVectEncoded := []byte{ - 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0x02, 0x00, 0x00, 0x00, // InvTypeBlock 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, diff --git a/legacy.go b/legacy.go new file mode 100644 index 00000000..8c072d94 --- /dev/null +++ b/legacy.go @@ -0,0 +1,14 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +// These constants are deprecated as they do not follow the standard Go style +// guidelines and are only provided for backwards compatibility. Use the +// InvType* constants instead. +const ( + InvVect_Error InvType = InvTypeError + InvVect_Tx InvType = InvTypeTx + InvVect_Block InvType = InvTypeBlock +) diff --git a/msggetdata_test.go b/msggetdata_test.go index 47822e68..84461e87 100644 --- a/msggetdata_test.go +++ b/msggetdata_test.go @@ -37,7 +37,7 @@ func TestGetData(t *testing.T) { // Ensure inventory vectors are added properly. hash := btcwire.ShaHash{} - iv := btcwire.NewInvVect(btcwire.InvVect_Block, &hash) + iv := btcwire.NewInvVect(btcwire.InvTypeBlock, &hash) err := msg.AddInvVect(iv) if err != nil { t.Errorf("AddInvVect: %v", err) @@ -77,8 +77,8 @@ func TestGetDataWire(t *testing.T) { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) - iv2 := btcwire.NewInvVect(btcwire.InvVect_Tx, txHash) + iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) + iv2 := btcwire.NewInvVect(btcwire.InvTypeTx, txHash) // Empty MsgGetData message. NoInv := btcwire.NewMsgGetData() @@ -92,12 +92,12 @@ func TestGetDataWire(t *testing.T) { MultiInv.AddInvVect(iv2) MultiInvEncoded := []byte{ 0x02, // Varint for number of inv vectors - 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0x02, 0x00, 0x00, 0x00, // InvTypeBlock 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash - 0x01, 0x00, 0x00, 0x00, // InvVect_Tx + 0x01, 0x00, 0x00, 0x00, // InvTypeTx 0xf0, 0xfa, 0xcc, 0x7a, 0x48, 0x1b, 0xe7, 0xcf, 0x42, 0xbd, 0x7f, 0xe5, 0x4f, 0x2c, 0x2a, 0xf8, 0xef, 0x81, 0x9a, 0xdd, 0x93, 0xee, 0x55, 0x98, @@ -235,14 +235,14 @@ func TestGetDataWireErrors(t *testing.T) { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) + iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) // Base message used to induce errors. baseGetData := btcwire.NewMsgGetData() baseGetData.AddInvVect(iv) baseGetDataEncoded := []byte{ 0x02, // Varint for number of inv vectors - 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0x02, 0x00, 0x00, 0x00, // InvTypeBlock 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, diff --git a/msginv_test.go b/msginv_test.go index 6d0c9460..ca068121 100644 --- a/msginv_test.go +++ b/msginv_test.go @@ -37,7 +37,7 @@ func TestInv(t *testing.T) { // Ensure inventory vectors are added properly. hash := btcwire.ShaHash{} - iv := btcwire.NewInvVect(btcwire.InvVect_Block, &hash) + iv := btcwire.NewInvVect(btcwire.InvTypeBlock, &hash) err := msg.AddInvVect(iv) if err != nil { t.Errorf("AddInvVect: %v", err) @@ -77,8 +77,8 @@ func TestInvWire(t *testing.T) { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) - iv2 := btcwire.NewInvVect(btcwire.InvVect_Tx, txHash) + iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) + iv2 := btcwire.NewInvVect(btcwire.InvTypeTx, txHash) // Empty inv message. NoInv := btcwire.NewMsgInv() @@ -92,12 +92,12 @@ func TestInvWire(t *testing.T) { MultiInv.AddInvVect(iv2) MultiInvEncoded := []byte{ 0x02, // Varint for number of inv vectors - 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0x02, 0x00, 0x00, 0x00, // InvTypeBlock 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash - 0x01, 0x00, 0x00, 0x00, // InvVect_Tx + 0x01, 0x00, 0x00, 0x00, // InvTypeTx 0xf0, 0xfa, 0xcc, 0x7a, 0x48, 0x1b, 0xe7, 0xcf, 0x42, 0xbd, 0x7f, 0xe5, 0x4f, 0x2c, 0x2a, 0xf8, 0xef, 0x81, 0x9a, 0xdd, 0x93, 0xee, 0x55, 0x98, @@ -235,14 +235,14 @@ func TestInvWireErrors(t *testing.T) { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) + iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) // Base inv message used to induce errors. baseInv := btcwire.NewMsgInv() baseInv.AddInvVect(iv) baseInvEncoded := []byte{ 0x02, // Varint for number of inv vectors - 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0x02, 0x00, 0x00, 0x00, // InvTypeBlock 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, diff --git a/msgnotfound_test.go b/msgnotfound_test.go index 9dc50866..26a43e99 100644 --- a/msgnotfound_test.go +++ b/msgnotfound_test.go @@ -37,7 +37,7 @@ func TestNotFound(t *testing.T) { // Ensure inventory vectors are added properly. hash := btcwire.ShaHash{} - iv := btcwire.NewInvVect(btcwire.InvVect_Block, &hash) + iv := btcwire.NewInvVect(btcwire.InvTypeBlock, &hash) err := msg.AddInvVect(iv) if err != nil { t.Errorf("AddInvVect: %v", err) @@ -77,8 +77,8 @@ func TestNotFoundWire(t *testing.T) { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) - iv2 := btcwire.NewInvVect(btcwire.InvVect_Tx, txHash) + iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) + iv2 := btcwire.NewInvVect(btcwire.InvTypeTx, txHash) // Empty notfound message. NoInv := btcwire.NewMsgNotFound() @@ -92,12 +92,12 @@ func TestNotFoundWire(t *testing.T) { MultiInv.AddInvVect(iv2) MultiInvEncoded := []byte{ 0x02, // Varint for number of inv vectors - 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0x02, 0x00, 0x00, 0x00, // InvTypeBlock 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash - 0x01, 0x00, 0x00, 0x00, // InvVect_Tx + 0x01, 0x00, 0x00, 0x00, // InvTypeTx 0xf0, 0xfa, 0xcc, 0x7a, 0x48, 0x1b, 0xe7, 0xcf, 0x42, 0xbd, 0x7f, 0xe5, 0x4f, 0x2c, 0x2a, 0xf8, 0xef, 0x81, 0x9a, 0xdd, 0x93, 0xee, 0x55, 0x98, @@ -235,14 +235,14 @@ func TestNotFoundWireErrors(t *testing.T) { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvVect_Block, blockHash) + iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) // Base message used to induce errors. baseNotFound := btcwire.NewMsgNotFound() baseNotFound.AddInvVect(iv) baseNotFoundEncoded := []byte{ 0x02, // Varint for number of inv vectors - 0x02, 0x00, 0x00, 0x00, // InvVect_Block + 0x02, 0x00, 0x00, 0x00, // InvTypeBlock 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, From 5c8fddf4b4c04e47e13f56c2b28e0a97c2b6238e Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 8 Oct 2013 15:51:34 -0500 Subject: [PATCH 100/219] Add deprecated comments to legacy InvVect_* consts. This makes it a little more obvious in the documentation that they are deprecated. --- legacy.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/legacy.go b/legacy.go index 8c072d94..9234feaf 100644 --- a/legacy.go +++ b/legacy.go @@ -8,7 +8,7 @@ package btcwire // guidelines and are only provided for backwards compatibility. Use the // InvType* constants instead. const ( - InvVect_Error InvType = InvTypeError - InvVect_Tx InvType = InvTypeTx - InvVect_Block InvType = InvTypeBlock + InvVect_Error InvType = InvTypeError // DEPRECATED + InvVect_Tx InvType = InvTypeTx // DEPRECATED + InvVect_Block InvType = InvTypeBlock // DEPRECATED ) From fa1d343430ecff479bee0652a7a000aed61f3f6f Mon Sep 17 00:00:00 2001 From: Jonathan Gillham Date: Mon, 14 Oct 2013 23:55:18 +0100 Subject: [PATCH 101/219] Removed extra local variable assignment from DoubleSha256. --- common.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common.go b/common.go index 21666892..1d2b37ac 100644 --- a/common.go +++ b/common.go @@ -176,6 +176,5 @@ func DoubleSha256(b []byte) []byte { sum := hasher.Sum(nil) hasher.Reset() hasher.Write(sum) - sum = hasher.Sum(nil) - return sum + return hasher.Sum(nil) } From 70aa92bf0d822d2ad5265924ed474af6328510df Mon Sep 17 00:00:00 2001 From: Dale Rahn Date: Thu, 24 Oct 2013 14:39:40 -0400 Subject: [PATCH 102/219] Test some boundary conditions that exercise 'flaws' in the current btcwire protocol. --- common_test.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/common_test.go b/common_test.go index 8a191c34..a3d09209 100644 --- a/common_test.go +++ b/common_test.go @@ -193,6 +193,29 @@ func TestVarStringWire(t *testing.T) { continue } } + + invtests := []struct { + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + {append([]byte{0x02}, []byte("")...), pver}, + //{append([]byte{0xfe, 0x00, 0x00, 0x00, 0x80}, []byte("")...), pver}, + {append([]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, []byte("")...), pver}, + //{append([]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, []byte("")...), pver}, + } + t.Logf("Running %d invalid tests", len(invtests)) + for i, test := range invtests { + // Decode from wire format. + rbuf := bytes.NewBuffer(test.buf) + val, err := btcwire.TstReadVarString(rbuf, test.pver) + if err != nil { + t.Logf("readVarString #%d error %v (error expected)", i, err) + continue + } + t.Errorf("readVarString #%d\n got: %d want error != nil: %d", i, + val) + continue + } } // TestVarStringWireErrors performs negative tests against wire encode and From 5cc32bbfc7dff4a672161d4b16a2fcb82cd031fc Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 24 Oct 2013 23:13:51 -0500 Subject: [PATCH 103/219] Add bounds checking to all variable length allocs. Several of the bitcoin data structures contain variable length entries, many of which have well-defined maximum limits. However, there are still a few cases, such as variable length strings and number of transactions which don't have clearly defined maximum limits. Instead they are only limited by the maximum size of a message. In order to efficiently decode messages, space is pre-allocated for the slices which hold these variable length pieces as to avoid needing to dynamically grow the backing arrays. Due to this however, it was previously possible to claim extremely high slice lengths which exceed available memory (or maximum allowed slice lengths). This commit imposes limits to all of these cases based on calculating the maximum possible number of elements that could fit into a message and using those as sane upper limits. The variable length string case was found (and tests added to hit it) by drahn@ which prompted an audit to find all cases. --- common.go | 21 ++++++++++++-- msgblock.go | 30 +++++++++++++++++-- msgtx.go | 83 ++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 121 insertions(+), 13 deletions(-) diff --git a/common.go b/common.go index 1d2b37ac..27923cfe 100644 --- a/common.go +++ b/common.go @@ -8,6 +8,7 @@ import ( "crypto/rand" "crypto/sha256" "encoding/binary" + "fmt" "io" "math" ) @@ -121,13 +122,27 @@ func writeVarInt(w io.Writer, pver uint32, val uint64) error { // readVarString reads a variable length string from r and returns it as a Go // string. A varString is encoded as a varInt containing the length of the -// string, and the bytes that represent the string itself. +// string, and the bytes that represent the string itself. An error is returned +// if the length is greater than the maximum block payload size, since it would +// not be possible to put a varString of that size into a block anyways and it +// also helps protect against memory exhuastion attacks and forced panics +// through malformed messages. func readVarString(r io.Reader, pver uint32) (string, error) { - slen, err := readVarInt(r, pver) + count, err := readVarInt(r, pver) if err != nil { return "", err } - buf := make([]byte, slen) + + // Prevent variable length strings that are larger than the maximum + // message size. It would be possible to cause memory exhaustion and + // panics without a sane upper bound on this count. + if count > maxMessagePayload { + str := fmt.Sprintf("variable length string is too long "+ + "[count %d, max %d]", count, maxMessagePayload) + return "", messageError("readVarString", str) + } + + buf := make([]byte, count) err = readElement(r, buf) if err != nil { return "", err diff --git a/msgblock.go b/msgblock.go index 7ad79a3e..35693211 100644 --- a/msgblock.go +++ b/msgblock.go @@ -6,6 +6,7 @@ package btcwire import ( "bytes" + "fmt" "io" ) @@ -22,6 +23,10 @@ const MaxBlocksPerMsg = 500 // MaxBlockPayload is the maximum bytes a block message can be in bytes. const MaxBlockPayload = 1000000 // Not actually 1MB which would be 1024 * 1024 +// maxTxPerBlock is the maximum number of transactions that could +// possibly fit into a block. +const maxTxPerBlock = (MaxBlockPayload / minTxPayload) + 1 + // TxLoc holds locator data for the offset and length of where a transaction is // located within a MsgBlock data buffer. type TxLoc struct { @@ -72,8 +77,18 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32) error { return err } - msg.Transactions = make([]*MsgTx, 0, msg.Header.TxnCount) - for i := uint64(0); i < msg.Header.TxnCount; i++ { + // Prevent more transactions than could possibly fit into a block. + // It would be possible to cause memory exhaustion and panics without + // a sane upper bound on this count. + txCount := msg.Header.TxnCount + if txCount > maxTxPerBlock { + str := fmt.Sprintf("too many transactions to fit into a block "+ + "[count %d, max %d]", txCount, maxTxPerBlock) + return messageError("MsgBlock.BtcDecode", str) + } + + msg.Transactions = make([]*MsgTx, 0, txCount) + for i := uint64(0); i < txCount; i++ { tx := MsgTx{} err := tx.BtcDecode(r, pver) if err != nil { @@ -115,9 +130,18 @@ func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) { return nil, err } + // Prevent more transactions than could possibly fit into a block. + // It would be possible to cause memory exhaustion and panics without + // a sane upper bound on this count. + txCount := msg.Header.TxnCount + if txCount > maxTxPerBlock { + str := fmt.Sprintf("too many transactions to fit into a block "+ + "[count %d, max %d]", txCount, maxTxPerBlock) + return nil, messageError("MsgBlock.DeserializeTxLoc", str) + } + // Deserialize each transaction while keeping track of its location // within the byte stream. - txCount := msg.Header.TxnCount msg.Transactions = make([]*MsgTx, 0, txCount) txLocs := make([]TxLoc, txCount) for i := uint64(0); i < txCount; i++ { diff --git a/msgtx.go b/msgtx.go index cdccbcc7..673faf1f 100644 --- a/msgtx.go +++ b/msgtx.go @@ -6,9 +6,17 @@ package btcwire import ( "bytes" + "fmt" "io" ) +// TxVersion is the current latest supported transaction version. +const TxVersion = 1 + +// MaxTxInSequenceNum is the maximum sequence number the sequence field +// of a transaction input can be. +const MaxTxInSequenceNum uint32 = 0xffffffff + // defaultTxInOutAlloc is the default size used for the backing array for // transaction inputs and outputs. The array will dynamically grow as needed, // but this figure is intended to provide enough space for the number of @@ -16,12 +24,33 @@ import ( // backing array multiple times. const defaultTxInOutAlloc = 15 -// TxVersion is the current latest supported transaction version. -const TxVersion = 1 +const ( + // minTxInPayload is the minimum payload size for a transaction input. + // PreviousOutpoint.Hash + PreviousOutpoint.Index 4 bytes + Varint for + // SignatureScript length 1 byte + Sequence 4 bytes. + minTxInPayload = 9 + HashSize -// MaxTxInSequenceNum is the maximum sequence number the sequence field -// of a transaction input can be. -const MaxTxInSequenceNum uint32 = 0xffffffff + // maxTxInPerMessage is the maximum number of transactions inputs that + // a transaction which fits into a message could possibly have. + maxTxInPerMessage = (maxMessagePayload / minTxInPayload) + 1 + + // minTxOutPayload is the minimum payload size for a transaction output. + // Value 8 bytes + Varint for PkScript length 1 byte. + minTxOutPayload = 9 + + // maxTxOutPerMessage is the maximum number of transactions outputs that + // a transaction which fits into a message could possibly have. + maxTxOutPerMessage = (maxMessagePayload / minTxOutPayload) + 1 + + // minTxPayload is the minimum payload size for a transaction. Note + // that any realistically usable transaction must have at least one + // input or output, but that is a rule enforced at a higher layer, so + // it is intentionally not included here. + // Version 4 bytes + Varint number of transaction inputs 1 byte + Varint + // number of transaction outputs 1 byte + LockTime 4 bytes + min input + // payload + min output payload. + minTxPayload = 10 +) // OutPoint defines a bitcoin data type that is used to track previous // transaction outputs. @@ -191,6 +220,16 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { return err } + // Prevent more input transactions than could possibly fit into a + // message. It would be possible to cause memory exhaustion and panics + // without a sane upper bound on this count. + if count > uint64(maxTxInPerMessage) { + str := fmt.Sprintf("too many input transactions to fit into "+ + "max message size [count %d, max %d]", count, + maxTxInPerMessage) + return messageError("MsgTx.BtcDecode", str) + } + msg.TxIn = make([]*TxIn, 0, count) for i := uint64(0); i < count; i++ { ti := TxIn{} @@ -206,6 +245,16 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { return err } + // Prevent more output transactions than could possibly fit into a + // message. It would be possible to cause memory exhaustion and panics + // without a sane upper bound on this count. + if count > uint64(maxTxOutPerMessage) { + str := fmt.Sprintf("too many output transactions to fit into "+ + "max message size [count %d, max %d]", count, + maxTxOutPerMessage) + return messageError("MsgTx.BtcDecode", str) + } + msg.TxOut = make([]*TxOut, 0, count) for i := uint64(0); i < count; i++ { to := TxOut{} @@ -362,6 +411,16 @@ func readTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { return err } + // Prevent signature script larger than the max message size. It would + // be possible to cause memory exhaustion and panics without a sane + // upper bound on this count. + if count > uint64(maxMessagePayload) { + str := fmt.Sprintf("transaction input signature script is "+ + "larger than max message size [count %d, max %d]", + count, maxMessagePayload) + return messageError("MsgTx.BtcDecode", str) + } + b := make([]byte, count) err = readElement(r, b) if err != nil { @@ -413,12 +472,22 @@ func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { return err } - slen, err := readVarInt(r, pver) + count, err := readVarInt(r, pver) if err != nil { return err } - b := make([]byte, slen) + // Prevent public key script larger than the max message size. It would + // be possible to cause memory exhaustion and panics without a sane + // upper bound on this count. + if count > uint64(maxMessagePayload) { + str := fmt.Sprintf("transaction output public key script is "+ + "larger than max message size [count %d, max %d]", + count, maxMessagePayload) + return messageError("MsgTx.BtcDecode", str) + } + + b := make([]byte, count) err = readElement(r, b) if err != nil { return err From d1edbf1f0b86075d41fecc52c750addd70376665 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 24 Oct 2013 23:36:15 -0500 Subject: [PATCH 104/219] Add tests to exercise intential malicious overflow. This commit adds several tests which intentionally attempt to feed malicious data to the various deserialize functions. --- msgblock_test.go | 68 +++++++++++++++++++++++++++++++++ msgtx_test.go | 96 +++++++++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 66 ++++++++++++++++---------------- 3 files changed, 197 insertions(+), 33 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index 16184533..3104de8d 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -381,6 +381,74 @@ func TestBlockSerializeErrors(t *testing.T) { } } +// TestBlockOverflowErrors performs tests to ensure deserializing blocks which +// are intentionally crafted to use large values for the number of transactions +// are handled properly. This could otherwise potentially be used as an attack +// vector. +func TestBlockOverflowErrors(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) + + tests := []struct { + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + err error // Expected error + }{ + // Block that claims to have ~uint64(0) transactions. + { + []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 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // TxnCount + }, pver, &btcwire.MessageError{}, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Decode from wire format. + var msg btcwire.MsgBlock + r := bytes.NewBuffer(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 + } + + // Deserialize from wire format. + r = bytes.NewBuffer(test.buf) + err = msg.Deserialize(r) + if reflect.TypeOf(err) != reflect.TypeOf(test.err) { + t.Errorf("Deserialize #%d wrong error got: %v, want: %v", + i, err, reflect.TypeOf(test.err)) + continue + } + + // Deserialize with transaction location info from wire format. + r = bytes.NewBuffer(test.buf) + _, err = msg.DeserializeTxLoc(r) + if reflect.TypeOf(err) != reflect.TypeOf(test.err) { + t.Errorf("DeserializeTxLoc #%d wrong error got: %v, "+ + "want: %v", i, err, reflect.TypeOf(test.err)) + continue + } + } +} + var blockOne = btcwire.MsgBlock{ Header: btcwire.BlockHeader{ Version: 1, diff --git a/msgtx_test.go b/msgtx_test.go index 9f003dc1..64535a81 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -491,6 +491,102 @@ func TestTxSerializeErrors(t *testing.T) { } } +// TestTxOverflowErrors performs tests to ensure deserializing transactions +// which are intentionally crafted to use large values for the variable number +// of inputs and outputs are handled properly. This could otherwise potentially +// be used as an attack vector. +func TestTxOverflowErrors(t *testing.T) { + // Use protocol version 70001 and transaction version 1 specifically + // here instead of the latest values because the test data is using + // bytes encoded with those versions. + pver := uint32(70001) + txVer := uint32(1) + + tests := []struct { + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + version uint32 // Transaction version + err error // Expected error + }{ + // Transaction that claims to have ~uint64(0) inputs. + { + []byte{ + 0x00, 0x00, 0x00, 0x01, // Version + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // Varint for number of input transactions + }, pver, txVer, &btcwire.MessageError{}, + }, + + // Transaction that claims to have ~uint64(0) outputs. + { + []byte{ + 0x00, 0x00, 0x00, 0x01, // Version + 0x00, // Varint for number of input transactions + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // Varint for number of output transactions + }, pver, txVer, &btcwire.MessageError{}, + }, + + // Transaction that has an input with a signature script that + // claims to have ~uint64(0) length. + { + []byte{ + 0x00, 0x00, 0x00, 0x01, // Version + 0x01, // Varint for number of input transactions + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash + 0xff, 0xff, 0xff, 0xff, // Prevous output index + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // Varint for length of signature script + }, pver, txVer, &btcwire.MessageError{}, + }, + + // Transaction that has an output with a public key script + // that claims to have ~uint64(0) length. + { + []byte{ + 0x00, 0x00, 0x00, 0x01, // Version + 0x01, // Varint for number of input transactions + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash + 0xff, 0xff, 0xff, 0xff, // Prevous output index + 0x00, // Varint for length of signature script + 0xff, 0xff, 0xff, 0xff, // Sequence + 0x01, // Varint for number of output transactions + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Transaction amount + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // Varint for length of public key script + }, pver, txVer, &btcwire.MessageError{}, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Decode from wire format. + var msg btcwire.MsgTx + r := bytes.NewBuffer(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 + } + + // Decode from wire format. + r = bytes.NewBuffer(test.buf) + err = msg.Deserialize(r) + if reflect.TypeOf(err) != reflect.TypeOf(test.err) { + t.Errorf("Deserialize #%d wrong error got: %v, want: %v", + i, err, reflect.TypeOf(test.err)) + continue + } + } +} + // multiTx is a MsgTx with an input and output and used in various tests. var multiTx = &btcwire.MsgTx{ Version: 1, diff --git a/test_coverage.txt b/test_coverage.txt index 2dd4557f..9f5dcf31 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,7 +1,7 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (33/33) github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (27/27) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) @@ -9,62 +9,62 @@ github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (23/23) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) -github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) +github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) +github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) +github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (19/19) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) -github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (17/17) github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) -github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (16/16) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) +github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) +github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (15/15) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (12/12) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (11/11) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) +github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) -github.com/conformal/btcwire/common.go readVarString 100.00% (8/8) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (7/7) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) @@ -154,5 +154,5 @@ github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1 github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (943/943) +github.com/conformal/btcwire --------------------------------- 100.00% (964/964) From a4c5c620c60d9e85626187a245b71c8bc21f2124 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 24 Oct 2013 23:39:49 -0500 Subject: [PATCH 105/219] Finish a TODO in the message headers tests. --- msgheaders_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/msgheaders_test.go b/msgheaders_test.go index e3142f98..689d21b9 100644 --- a/msgheaders_test.go +++ b/msgheaders_test.go @@ -50,8 +50,7 @@ func TestHeaders(t *testing.T) { for i := 0; i < btcwire.MaxBlockHeadersPerMsg+1; i++ { err = msg.AddBlockHeader(bh) } - // TODO(davec): Check for actual error. - if err == nil { + if reflect.TypeOf(err) != reflect.TypeOf(&btcwire.MessageError{}) { t.Errorf("AddBlockHeader: expected error on too many headers " + "not received") } From bd297491b9ccc5611057abf9c3f43199dedeb7f0 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 25 Oct 2013 09:55:00 -0500 Subject: [PATCH 106/219] Make var length string overflow tests consistent. This commit modifies the variable length string overflow tests slight to make them consistent with the other overflow tests. --- common_test.go | 56 +++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/common_test.go b/common_test.go index a3d09209..e424044e 100644 --- a/common_test.go +++ b/common_test.go @@ -10,6 +10,7 @@ import ( "github.com/conformal/btcwire" "github.com/davecgh/go-spew/spew" "io" + "reflect" "strings" "testing" ) @@ -193,29 +194,6 @@ func TestVarStringWire(t *testing.T) { continue } } - - invtests := []struct { - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding - }{ - {append([]byte{0x02}, []byte("")...), pver}, - //{append([]byte{0xfe, 0x00, 0x00, 0x00, 0x80}, []byte("")...), pver}, - {append([]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, []byte("")...), pver}, - //{append([]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, []byte("")...), pver}, - } - t.Logf("Running %d invalid tests", len(invtests)) - for i, test := range invtests { - // Decode from wire format. - rbuf := bytes.NewBuffer(test.buf) - val, err := btcwire.TstReadVarString(rbuf, test.pver) - if err != nil { - t.Logf("readVarString #%d error %v (error expected)", i, err) - continue - } - t.Errorf("readVarString #%d\n got: %d want error != nil: %d", i, - val) - continue - } } // TestVarStringWireErrors performs negative tests against wire encode and @@ -265,6 +243,38 @@ func TestVarStringWireErrors(t *testing.T) { } } +// 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 := btcwire.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, &btcwire.MessageError{}}, + {[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + pver, &btcwire.MessageError{}}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Decode from wire format. + rbuf := bytes.NewBuffer(test.buf) + _, err := btcwire.TstReadVarString(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 + } + } + +} + // 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 From cbf648a02f20ecf1a366e335e15c209371b9fa39 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 30 Oct 2013 21:03:57 -0500 Subject: [PATCH 107/219] Slightly optimize writeVarInt for the normal case. Most variable length integers are smaller numbers, so this commit reverses the order of the if checks in the writeVarInt to assume smaller numbers are more common. This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27 --- common.go | 29 ++++++++++------------------- test_coverage.txt | 32 ++++++++++++++++---------------- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/common.go b/common.go index 27923cfe..75f5f9ec 100644 --- a/common.go +++ b/common.go @@ -96,28 +96,19 @@ func readVarInt(r io.Reader, pver uint32) (uint64, error) { // writeVarInt serializes val to w using a variable number of bytes depending // on its value. func writeVarInt(w io.Writer, pver uint32, val uint64) error { - if val > math.MaxUint32 { - err := writeElements(w, []byte{0xff}, uint64(val)) - if err != nil { - return err - } - return nil + if val < 0xfd { + return writeElement(w, uint8(val)) } - if val > math.MaxUint16 { - err := writeElements(w, []byte{0xfe}, uint32(val)) - if err != nil { - return err - } - return nil + + if val <= math.MaxUint16 { + return writeElements(w, []byte{0xfd}, uint16(val)) } - if val >= 0xfd { - err := writeElements(w, []byte{0xfd}, uint16(val)) - if err != nil { - return err - } - return nil + + if val <= math.MaxUint32 { + return writeElements(w, []byte{0xfe}, uint32(val)) } - return writeElement(w, uint8(val)) + + return writeElements(w, []byte{0xff}, uint64(val)) } // readVarString reads a variable length string from r and returns it as a Go diff --git a/test_coverage.txt b/test_coverage.txt index 9f5dcf31..3d90c5bd 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -16,15 +16,14 @@ github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (1 github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) -github.com/conformal/btcwire/common.go writeVarInt 100.00% (16/16) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) +github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) -github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (15/15) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) @@ -32,39 +31,40 @@ github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) -github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) -github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) +github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarInt 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) @@ -154,5 +154,5 @@ github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1 github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (964/964) +github.com/conformal/btcwire --------------------------------- 100.00% (955/955) From 26cb71d805c1d80ba0b3eba35fea967c9c282282 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 31 Oct 2013 00:09:52 -0500 Subject: [PATCH 108/219] Expose new SerializeSize API for transactions. This commit adds a new function named SerializeSize to the public API for MsgTx, TxOut, and TxIn which can be used to determine how many bytes the serialized data would take without having to actually serialize it. The following benchmark shows the difference between using the new function to get the serialize size for a typical transaction and serializing into a temporary buffer and taking the length of it: Bufffer: BenchmarkTxSerializeSizeBuffer 200000 7050 ns/op New: BenchmarkTxSerializeSizeNew 100000000 18 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- common.go | 23 +++++++++++++++++++++++ msgtx.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/common.go b/common.go index 75f5f9ec..8eabcbc8 100644 --- a/common.go +++ b/common.go @@ -111,6 +111,29 @@ func writeVarInt(w io.Writer, pver uint32, val uint64) error { return writeElements(w, []byte{0xff}, uint64(val)) } +// varIntSerializeSize returns the number of bytes it would take to serialize +// val as a variable length integer. +func varIntSerializeSize(val uint64) int { + // The value is small enough to be represented by itself, so it's + // just 1 byte. + if val < 0xfd { + return 1 + } + + // Discriminant 1 byte plus 2 bytes for the uint16. + if val <= math.MaxUint16 { + return 3 + } + + // Discriminant 1 byte plus 4 bytes for the uint32. + if val <= math.MaxUint32 { + return 5 + } + + // Discriminant 1 byte plus 8 bytes for the uint64. + return 9 +} + // readVarString reads a variable length string from r and returns it as a Go // string. A varString is encoded as a varInt containing the length of the // string, and the bytes that represent the string itself. An error is returned diff --git a/msgtx.go b/msgtx.go index 673faf1f..8151fe0a 100644 --- a/msgtx.go +++ b/msgtx.go @@ -75,6 +75,16 @@ type TxIn struct { Sequence uint32 } +// SerializeSize returns the number of bytes it would take to serialize the +// the transaction input. +func (t *TxIn) SerializeSize() int { + // Outpoint Hash 32 bytes + Outpoint Index 4 bytes + Sequence 4 bytes + + // serialized varint size for the length of SignatureScript + + // SignatureScript bytes. + return 40 + varIntSerializeSize(uint64(len(t.SignatureScript))) + + len(t.SignatureScript) +} + // NewTxIn returns a new bitcoin transaction input with the provided // previous outpoint point and signature script with a default sequence of // MaxTxInSequenceNum. @@ -92,6 +102,14 @@ type TxOut struct { PkScript []byte } +// SerializeSize returns the number of bytes it would take to serialize the +// the transaction output. +func (t *TxOut) SerializeSize() int { + // Value 8 bytes + serialized varint size for the length of PkScript + + // PkScript bytes. + return 8 + varIntSerializeSize(uint64(len(t.PkScript))) + len(t.PkScript) +} + // NewTxOut returns a new bitcoin transaction output with the provided // transaction value and public key script. func NewTxOut(value int64, pkScript []byte) *TxOut { @@ -352,6 +370,25 @@ func (msg *MsgTx) Serialize(w io.Writer) error { } +// SerializeSize returns the number of bytes it would take to serialize the +// the transaction. +func (msg *MsgTx) SerializeSize() int { + // Version 4 bytes + LockTime 4 bytes + Serialized varint size for the + // number of transaction inputs and outputs. + n := 8 + varIntSerializeSize(uint64(len(msg.TxIn))) + + varIntSerializeSize(uint64(len(msg.TxOut))) + + for _, txIn := range msg.TxIn { + n += txIn.SerializeSize() + } + + for _, txOut := range msg.TxOut { + n += txOut.SerializeSize() + } + + return n +} + // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgTx) Command() string { From b7b700fd5aebb86addc93efecaa367a2f4976058 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 31 Oct 2013 00:18:34 -0500 Subject: [PATCH 109/219] Add tests for the new SerializeSize functions. This commit adds tests for the new SerializeSize functions for variable length integers and transactions (and indirectly transaction inputs and outputs). --- common_test.go | 35 +++++++++++ internal_test.go | 6 ++ msgtx_test.go | 29 +++++++++ test_coverage.txt | 150 ++++++++++++++++++++++++---------------------- 4 files changed, 147 insertions(+), 73 deletions(-) diff --git a/common_test.go b/common_test.go index e424044e..29a65d41 100644 --- a/common_test.go +++ b/common_test.go @@ -144,6 +144,41 @@ func TestVarIntWireErrors(t *testing.T) { } } +// 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 := btcwire.TstVarIntSerializeSize(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 := btcwire.ProtocolVersion diff --git a/internal_test.go b/internal_test.go index a9619b50..fddc6b27 100644 --- a/internal_test.go +++ b/internal_test.go @@ -37,6 +37,12 @@ func TstWriteVarInt(w io.Writer, pver uint32, val uint64) error { return writeVarInt(w, pver, val) } +// TstVarIntSerializeSize makes the internal varIntSerializeSize function +// available to the test package. +func TstVarIntSerializeSize(val uint64) int { + return varIntSerializeSize(val) +} + // TstReadVarString makes the internal readVarString function available to the // test package. func TstReadVarString(r io.Reader, pver uint32) (string, error) { diff --git a/msgtx_test.go b/msgtx_test.go index 64535a81..520b90b3 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -587,6 +587,35 @@ func TestTxOverflowErrors(t *testing.T) { } } +// TestTxSerializeSize performs tests to ensure the serialize size for various +// transactions is accurate. +func TestTxSerializeSize(t *testing.T) { + // Empty tx message. + noTx := btcwire.NewMsgTx() + noTx.Version = 1 + + tests := []struct { + in *btcwire.MsgTx // Tx to encode + size int // Expected serialized size + }{ + // No inputs or outpus. + {noTx, 10}, + + // Transcaction with an input and an output. + {multiTx, 134}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + serializedSize := test.in.SerializeSize() + if serializedSize != test.size { + t.Errorf("MsgTx.SerializeSize: #%d got: %d, want: %d", i, + serializedSize, test.size) + continue + } + } +} + // multiTx is a MsgTx with an input and output and used in various tests. var multiTx = &btcwire.MsgTx{ Version: 1, diff --git a/test_coverage.txt b/test_coverage.txt index 3d90c5bd..cc07fa26 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -3,156 +3,160 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (33/33) github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) -github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) +github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (23/23) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (20/20) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (19/19) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) -github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (15/15) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) +github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (15/15) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) -github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) +github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) github.com/conformal/btcwire/common.go writeVarInt 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (4/4) github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NewNetAddressIPPort 100.00% (2/2) -github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) +github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) +github.com/conformal/btcwire/common.go readElement 100.00% (1/1) github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) +github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) +github.com/conformal/btcwire/error.go messageError 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msgping.go NewMsgPing 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) github.com/conformal/btcwire/msgpong.go MsgPong.Command 100.00% (1/1) github.com/conformal/btcwire/msgpong.go NewMsgPong 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewOutPoint 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go TxIn.SerializeSize 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewTxIn 100.00% (1/1) +github.com/conformal/btcwire/msgtx.go TxOut.SerializeSize 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewTxOut 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxIn 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxOut 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Deserialize 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Serialize 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewMsgTx 100.00% (1/1) -github.com/conformal/btcwire/common.go readElement 100.00% (1/1) -github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcDecode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.AddService 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) -github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) -github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) -github.com/conformal/btcwire/error.go messageError 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) -github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) -github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (955/955) +github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) +github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) +github.com/conformal/btcwire --------------------------------- 100.00% (970/970) From 900db0b44471965de9597af2998e99a089454885 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 5 Nov 2013 19:56:12 -0600 Subject: [PATCH 110/219] Add benchmarks for writeVarInt. This commit adds a few benchmarks for the writeVarInt function. --- bench_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 bench_test.go diff --git a/bench_test.go b/bench_test.go new file mode 100644 index 00000000..158f7a56 --- /dev/null +++ b/bench_test.go @@ -0,0 +1,43 @@ +// Copyright (c) 2013 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "github.com/conformal/btcwire" + "io/ioutil" + "testing" +) + +// BenchmarkWriteVarInt1 performs a benchmark on how long it takes to write +// a single byte variable length integer. +func BenchmarkWriteVarInt1(b *testing.B) { + for i := 0; i < b.N; i++ { + btcwire.TstWriteVarInt(ioutil.Discard, 0, 1) + } +} + +// BenchmarkWriteVarInt3 performs a benchmark on how long it takes to write +// a three byte variable length integer. +func BenchmarkWriteVarInt3(b *testing.B) { + for i := 0; i < b.N; i++ { + btcwire.TstWriteVarInt(ioutil.Discard, 0, 65535) + } +} + +// BenchmarkWriteVarInt5 performs a benchmark on how long it takes to write +// a five byte variable length integer. +func BenchmarkWriteVarInt5(b *testing.B) { + for i := 0; i < b.N; i++ { + btcwire.TstWriteVarInt(ioutil.Discard, 0, 4294967295) + } +} + +// BenchmarkWriteVarInt9 performs a benchmark on how long it takes to write +// a nine byte variable length integer. +func BenchmarkWriteVarInt9(b *testing.B) { + for i := 0; i < b.N; i++ { + btcwire.TstWriteVarInt(ioutil.Discard, 0, 18446744073709551615) + } +} From 50c10faf4e679d96b25a633a7c33e5f80e894628 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 5 Nov 2013 20:32:36 -0600 Subject: [PATCH 111/219] Optimize writeVarInt. Before: BenchmarkWriteVarInt1 10000000 173 ns/op BenchmarkWriteVarInt3 2000000 965 ns/op BenchmarkWriteVarInt5 2000000 966 ns/op BenchmarkWriteVarInt9 2000000 968 ns/op After: BenchmarkWriteVarInt1 20000000 101 ns/op BenchmarkWriteVarInt3 20000000 136 ns/op BenchmarkWriteVarInt5 10000000 142 ns/op BenchmarkWriteVarInt9 10000000 156 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- common.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/common.go b/common.go index 8eabcbc8..3c1bfeff 100644 --- a/common.go +++ b/common.go @@ -97,18 +97,31 @@ func readVarInt(r io.Reader, pver uint32) (uint64, error) { // on its value. func writeVarInt(w io.Writer, pver uint32, val uint64) error { if val < 0xfd { - return writeElement(w, uint8(val)) + _, err := w.Write([]byte{uint8(val)}) + return err } if val <= math.MaxUint16 { - return writeElements(w, []byte{0xfd}, uint16(val)) + buf := make([]byte, 3) + buf[0] = 0xfd + binary.LittleEndian.PutUint16(buf[1:], uint16(val)) + _, err := w.Write(buf) + return err } if val <= math.MaxUint32 { - return writeElements(w, []byte{0xfe}, uint32(val)) + buf := make([]byte, 5) + buf[0] = 0xfe + binary.LittleEndian.PutUint32(buf[1:], uint32(val)) + _, err := w.Write(buf) + return err } - return writeElements(w, []byte{0xff}, uint64(val)) + buf := make([]byte, 9) + buf[0] = 0xff + binary.LittleEndian.PutUint64(buf[1:], val) + _, err := w.Write(buf) + return err } // varIntSerializeSize returns the number of bytes it would take to serialize From 87ce23d6791917c41533c85f9113c13512c7f555 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 5 Nov 2013 21:35:28 -0600 Subject: [PATCH 112/219] Add benchmarks for readVarInt. This commit adds a few benchmarks for the readVarInt function. --- bench_test.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/bench_test.go b/bench_test.go index 158f7a56..0150c658 100644 --- a/bench_test.go +++ b/bench_test.go @@ -5,6 +5,7 @@ package btcwire_test import ( + "bytes" "github.com/conformal/btcwire" "io/ioutil" "testing" @@ -41,3 +42,39 @@ func BenchmarkWriteVarInt9(b *testing.B) { btcwire.TstWriteVarInt(ioutil.Discard, 0, 18446744073709551615) } } + +// BenchmarkReadVarInt1 performs a benchmark on how long it takes to write +// a single byte variable length integer. +func BenchmarkReadVarInt1(b *testing.B) { + buf := []byte{0x01} + for i := 0; i < b.N; i++ { + btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0) + } +} + +// BenchmarkReadVarInt3 performs a benchmark on how long it takes to write +// a three byte variable length integer. +func BenchmarkReadVarInt3(b *testing.B) { + buf := []byte{0x0fd, 0xff, 0xff} + for i := 0; i < b.N; i++ { + btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0) + } +} + +// BenchmarkReadVarInt5 performs a benchmark on how long it takes to write +// a five byte variable length integer. +func BenchmarkReadVarInt5(b *testing.B) { + buf := []byte{0xfe, 0xff, 0xff, 0xff, 0xff} + for i := 0; i < b.N; i++ { + btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0) + } +} + +// BenchmarkReadVarInt9 performs a benchmark on how long it takes to write +// a nine byte variable length integer. +func BenchmarkReadVarInt9(b *testing.B) { + buf := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + for i := 0; i < b.N; i++ { + btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0) + } +} From 6263efcc716b6827158afaa7eb6bad62bd79effa Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 5 Nov 2013 21:53:16 -0600 Subject: [PATCH 113/219] Slightly optimize readVarInt. This commit slightly optimizes the readVarInt function in the case of multiple-byte variable length integers. It also reduces the amount of memory garbage it generates. Before: BenchmarkReadVarInt1 5000000 386 ns/op BenchmarkReadVarInt3 5000000 693 ns/op BenchmarkReadVarInt5 2000000 793 ns/op BenchmarkReadVarInt9 5000000 709 ns/op After: BenchmarkReadVarInt1 5000000 387 ns/op BenchmarkReadVarInt3 5000000 471 ns/op BenchmarkReadVarInt5 5000000 575 ns/op BenchmarkReadVarInt9 5000000 473 ns/op This is part ef the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- common.go | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/common.go b/common.go index 3c1bfeff..b1853471 100644 --- a/common.go +++ b/common.go @@ -53,8 +53,8 @@ func writeElements(w io.Writer, elements ...interface{}) error { // readVarInt reads a variable length integer from r and returns it as a uint64. func readVarInt(r io.Reader, pver uint32) (uint64, error) { - b := make([]byte, 1) - _, err := io.ReadFull(r, b) + b := make([]byte, 8) + _, err := io.ReadFull(r, b[0:1]) if err != nil { return 0, err } @@ -63,28 +63,25 @@ func readVarInt(r io.Reader, pver uint32) (uint64, error) { discriminant := uint8(b[0]) switch discriminant { case 0xff: - var u uint64 - err = binary.Read(r, binary.LittleEndian, &u) + _, err := io.ReadFull(r, b) if err != nil { return 0, err } - rv = u + rv = binary.LittleEndian.Uint64(b) case 0xfe: - var u uint32 - err = binary.Read(r, binary.LittleEndian, &u) + _, err := io.ReadFull(r, b[0:4]) if err != nil { return 0, err } - rv = uint64(u) + rv = uint64(binary.LittleEndian.Uint32(b)) case 0xfd: - var u uint16 - err = binary.Read(r, binary.LittleEndian, &u) + _, err := io.ReadFull(r, b[0:2]) if err != nil { return 0, err } - rv = uint64(u) + rv = uint64(binary.LittleEndian.Uint16(b)) default: rv = uint64(discriminant) From 052c2ca8d3688fc5d9f8549627968d3ca27b1967 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 5 Nov 2013 23:03:54 -0600 Subject: [PATCH 114/219] Correct benchmark comments. --- bench_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bench_test.go b/bench_test.go index 0150c658..2927f4ee 100644 --- a/bench_test.go +++ b/bench_test.go @@ -43,7 +43,7 @@ func BenchmarkWriteVarInt9(b *testing.B) { } } -// BenchmarkReadVarInt1 performs a benchmark on how long it takes to write +// BenchmarkReadVarInt1 performs a benchmark on how long it takes to read // a single byte variable length integer. func BenchmarkReadVarInt1(b *testing.B) { buf := []byte{0x01} @@ -52,7 +52,7 @@ func BenchmarkReadVarInt1(b *testing.B) { } } -// BenchmarkReadVarInt3 performs a benchmark on how long it takes to write +// BenchmarkReadVarInt3 performs a benchmark on how long it takes to read // a three byte variable length integer. func BenchmarkReadVarInt3(b *testing.B) { buf := []byte{0x0fd, 0xff, 0xff} @@ -61,7 +61,7 @@ func BenchmarkReadVarInt3(b *testing.B) { } } -// BenchmarkReadVarInt5 performs a benchmark on how long it takes to write +// BenchmarkReadVarInt5 performs a benchmark on how long it takes to read // a five byte variable length integer. func BenchmarkReadVarInt5(b *testing.B) { buf := []byte{0xfe, 0xff, 0xff, 0xff, 0xff} @@ -70,7 +70,7 @@ func BenchmarkReadVarInt5(b *testing.B) { } } -// BenchmarkReadVarInt9 performs a benchmark on how long it takes to write +// BenchmarkReadVarInt9 performs a benchmark on how long it takes to read // a nine byte variable length integer. func BenchmarkReadVarInt9(b *testing.B) { buf := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} From b830e2ddf3ed719889d1c11da8d73ef09d82a68b Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 5 Nov 2013 23:08:55 -0600 Subject: [PATCH 115/219] Add benchmarks for readVarString. This commit adds a few benchmarks for the readVarString function. --- bench_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bench_test.go b/bench_test.go index 2927f4ee..d5c84343 100644 --- a/bench_test.go +++ b/bench_test.go @@ -78,3 +78,21 @@ func BenchmarkReadVarInt9(b *testing.B) { btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0) } } + +// BenchmarkReadVarStr4 performs a benchmark on how long it takes to read a +// four byte variable length string. +func BenchmarkReadVarStr4(b *testing.B) { + buf := []byte{0x04, 't', 'e', 's', 't'} + for i := 0; i < b.N; i++ { + btcwire.TstReadVarString(bytes.NewBuffer(buf), 0) + } +} + +// BenchmarkReadVarStr10 performs a benchmark on how long it takes to read a +// ten byte variable length string. +func BenchmarkReadVarStr10(b *testing.B) { + buf := []byte{0x0a, 't', 'e', 's', 't', '0', '1', '2', '3', '4', '5'} + for i := 0; i < b.N; i++ { + btcwire.TstReadVarString(bytes.NewBuffer(buf), 0) + } +} From 4002051a22d914db76fef4cbaff00253665564b9 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 5 Nov 2013 23:33:21 -0600 Subject: [PATCH 116/219] Optimize readVarString. Before: BenchmarkReadVarStr4 1000000 1698 ns/op BenchmarkReadVarStr10 1000000 1812 ns/op After: BenchmarkReadVarStr4 2000000 853 ns/op BenchmarkReadVarStr10 5000000 712 ns/op This is part ef the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.go b/common.go index b1853471..42a389d4 100644 --- a/common.go +++ b/common.go @@ -167,7 +167,7 @@ func readVarString(r io.Reader, pver uint32) (string, error) { } buf := make([]byte, count) - err = readElement(r, buf) + _, err = io.ReadFull(r, buf) if err != nil { return "", err } From fa8f666e8ca2ef9aca035952faab38cfdd5a1fb6 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 5 Nov 2013 23:49:34 -0600 Subject: [PATCH 117/219] Add benchmarks for writeVarString. This commit adds a couple of benchmarks for the writeVarString function. --- bench_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/bench_test.go b/bench_test.go index d5c84343..a62f0d68 100644 --- a/bench_test.go +++ b/bench_test.go @@ -96,3 +96,19 @@ func BenchmarkReadVarStr10(b *testing.B) { btcwire.TstReadVarString(bytes.NewBuffer(buf), 0) } } + +// BenchmarkWriteVarStr4 performs a benchmark on how long it takes to write a +// four byte variable length string. +func BenchmarkWriteVarStr4(b *testing.B) { + for i := 0; i < b.N; i++ { + btcwire.TstWriteVarString(ioutil.Discard, 0, "test") + } +} + +// BenchmarkWriteVarStr10 performs a benchmark on how long it takes to write a +// four byte variable length string. +func BenchmarkWriteVarStr10(b *testing.B) { + for i := 0; i < b.N; i++ { + btcwire.TstWriteVarString(ioutil.Discard, 0, "test012345") + } +} From 8a1828a2d66cef3d49e034c591d9ed9a140e1f83 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 5 Nov 2013 23:59:40 -0600 Subject: [PATCH 118/219] Optimize writeVarString. Before: BenchmarkWriteVarStr4 1000000 1114 ns/op BenchmarkWriteVarStr10 1000000 1352 ns/op After: BenchmarkWriteVarStr4 5000000 291 ns/op BenchmarkWriteVarStr10 10000000 248 ns/op This is part ef the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.go b/common.go index 42a389d4..bb5b08d3 100644 --- a/common.go +++ b/common.go @@ -181,7 +181,7 @@ func writeVarString(w io.Writer, pver uint32, str string) error { if err != nil { return err } - err = writeElement(w, []byte(str)) + _, err = w.Write([]byte(str)) if err != nil { return err } From 547b6487023e6591b27187f819fdbbbf7388a013 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 00:43:52 -0600 Subject: [PATCH 119/219] Add benchmarks for writeOutPoint. This commit adds a benchmark for the writeOutPoint function. --- bench_test.go | 12 ++++++++++++ internal_test.go | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/bench_test.go b/bench_test.go index a62f0d68..f0e178ac 100644 --- a/bench_test.go +++ b/bench_test.go @@ -112,3 +112,15 @@ func BenchmarkWriteVarStr10(b *testing.B) { btcwire.TstWriteVarString(ioutil.Discard, 0, "test012345") } } + +// BenchmarkWriteOutPoint performs a benchmark on how long it takes to write a +// transaction output point. +func BenchmarkWriteOutPoint(b *testing.B) { + op := &btcwire.OutPoint{ + Hash: btcwire.ShaHash{}, + Index: 0, + } + for i := 0; i < b.N; i++ { + btcwire.TstWriteOutPoint(ioutil.Discard, 0, 0, op) + } +} diff --git a/internal_test.go b/internal_test.go index fddc6b27..a49e376f 100644 --- a/internal_test.go +++ b/internal_test.go @@ -102,3 +102,9 @@ func TstWriteBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { func TstReadMessageHeader(r io.Reader) (*messageHeader, error) { return readMessageHeader(r) } + +// TstWriteOutPoint makes the internal writeOutPoint function available to the +// test package. +func TstWriteOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error { + return writeOutPoint(w, pver, version, op) +} From f54b010e4b106737aaade12066246e72cc7aa5a2 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 00:47:57 -0600 Subject: [PATCH 120/219] Optimize writeOutPoint. Before: BenchmarkWriteOutPoint 500000 2664 ns/op After: BenchmarkWriteOutPoint 10000000 151 ns/op This is part ef the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- msgtx.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/msgtx.go b/msgtx.go index 8151fe0a..7c941455 100644 --- a/msgtx.go +++ b/msgtx.go @@ -6,6 +6,7 @@ package btcwire import ( "bytes" + "encoding/binary" "fmt" "io" ) @@ -426,7 +427,14 @@ func readOutPoint(r io.Reader, pver uint32, version uint32, op *OutPoint) error // writeOutPoint encodes op to the bitcoin protocol encoding for an OutPoint // to w. func writeOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error { - err := writeElements(w, op.Hash, op.Index) + _, err := w.Write(op.Hash[:]) + if err != nil { + return err + } + + buf := make([]byte, 4) + binary.LittleEndian.PutUint32(buf, op.Index) + _, err = w.Write(buf) if err != nil { return err } From d63e0dd455f0551cd2d57f116282a88dae20533c Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 07:33:37 -0600 Subject: [PATCH 121/219] Add benchmarks for readOutPoint. This commit adds a benchmark for the readOutPoint function. --- bench_test.go | 18 +++++++++++++++++- internal_test.go | 6 ++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/bench_test.go b/bench_test.go index f0e178ac..f17ac565 100644 --- a/bench_test.go +++ b/bench_test.go @@ -106,13 +106,29 @@ func BenchmarkWriteVarStr4(b *testing.B) { } // BenchmarkWriteVarStr10 performs a benchmark on how long it takes to write a -// four byte variable length string. +// ten byte variable length string. func BenchmarkWriteVarStr10(b *testing.B) { for i := 0; i < b.N; i++ { btcwire.TstWriteVarString(ioutil.Discard, 0, "test012345") } } +// BenchmarkReadOutPoint performs a benchmark on how long it takes to read a +// transaction output point. +func BenchmarkReadOutPoint(b *testing.B) { + buf := []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash + 0xff, 0xff, 0xff, 0xff, // Previous output index + } + var op btcwire.OutPoint + for i := 0; i < b.N; i++ { + btcwire.TstReadOutPoint(bytes.NewBuffer(buf), 0, 0, &op) + } +} + // BenchmarkWriteOutPoint performs a benchmark on how long it takes to write a // transaction output point. func BenchmarkWriteOutPoint(b *testing.B) { diff --git a/internal_test.go b/internal_test.go index a49e376f..bae8181e 100644 --- a/internal_test.go +++ b/internal_test.go @@ -103,6 +103,12 @@ func TstReadMessageHeader(r io.Reader) (*messageHeader, error) { return readMessageHeader(r) } +// TstReadOutPoint makes the internal readOutPoint function available to the +// test package. +func TstReadOutPoint(r io.Reader, pver uint32, version uint32, op *OutPoint) error { + return readOutPoint(r, pver, version, op) +} + // TstWriteOutPoint makes the internal writeOutPoint function available to the // test package. func TstWriteOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error { From 73f4ee623b335b363b3d155870c6e9aa0a00ddef Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 07:37:34 -0600 Subject: [PATCH 122/219] Optimize readOutPoint. Before: BenchmarkReadOutPoint 500000 2946 ns/op After: BenchmarkReadOutPoint 5000000 582 ns/op This is part ef the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- msgtx.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/msgtx.go b/msgtx.go index 7c941455..891bb5da 100644 --- a/msgtx.go +++ b/msgtx.go @@ -417,10 +417,17 @@ func NewMsgTx() *MsgTx { // readOutPoint reads the next sequence of bytes from r as an OutPoint. func readOutPoint(r io.Reader, pver uint32, version uint32, op *OutPoint) error { - err := readElements(r, &op.Hash, &op.Index) + _, err := io.ReadFull(r, op.Hash[:]) if err != nil { return err } + + buf := make([]byte, 4) + _, err = io.ReadFull(r, buf) + if err != nil { + return err + } + op.Index = binary.LittleEndian.Uint32(buf) return nil } From 48c350f379ba663549fa71319e9d6d40ac75181f Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 07:44:51 -0600 Subject: [PATCH 123/219] Update test coverage report. --- test_coverage.txt | 60 +++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/test_coverage.txt b/test_coverage.txt index cc07fa26..e2d163a3 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -4,76 +4,76 @@ github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (33/33) github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) -github.com/conformal/btcwire/common.go readVarInt 100.00% (24/24) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (23/23) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) +github.com/conformal/btcwire/common.go readVarInt 100.00% (21/21) +github.com/conformal/btcwire/common.go writeVarInt 100.00% (20/20) github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (20/20) +github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) -github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (19/19) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) -github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) +github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (15/15) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) +github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) +github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (9/9) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) +github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (9/9) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) -github.com/conformal/btcwire/common.go writeVarInt 100.00% (7/7) -github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (4/4) -github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) @@ -158,5 +158,5 @@ github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (970/970) +github.com/conformal/btcwire --------------------------------- 100.00% (990/990) From ab8c8e2d39986d127dff8ec85f46fcea498ead1a Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 15:21:37 -0600 Subject: [PATCH 124/219] Add benchmarks for writeTxOut. This commit adds a benchmark for the writeTxOut function. --- bench_test.go | 9 +++++++++ internal_test.go | 6 ++++++ msgtx.go | 4 ++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/bench_test.go b/bench_test.go index f17ac565..a144b932 100644 --- a/bench_test.go +++ b/bench_test.go @@ -140,3 +140,12 @@ func BenchmarkWriteOutPoint(b *testing.B) { btcwire.TstWriteOutPoint(ioutil.Discard, 0, 0, op) } } + +// BenchmarkWriteTxOut performs a benchmark on how long it takes to write +// a transaction output. +func BenchmarkWriteTxOut(b *testing.B) { + txOut := blockOne.Transactions[0].TxOut[0] + for i := 0; i < b.N; i++ { + btcwire.TstWriteTxOut(ioutil.Discard, 0, 0, txOut) + } +} diff --git a/internal_test.go b/internal_test.go index bae8181e..8e07775b 100644 --- a/internal_test.go +++ b/internal_test.go @@ -114,3 +114,9 @@ func TstReadOutPoint(r io.Reader, pver uint32, version uint32, op *OutPoint) err func TstWriteOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error { return writeOutPoint(w, pver, version, op) } + +// TstWriteTxOut makes the internal writeTxOut function available to the test +// package. +func TstWriteTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { + return writeTxOut(w, pver, version, to) +} diff --git a/msgtx.go b/msgtx.go index 891bb5da..cf75bead 100644 --- a/msgtx.go +++ b/msgtx.go @@ -339,7 +339,7 @@ func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32) error { } for _, to := range msg.TxOut { - err = writeTxOut(w, pver, to) + err = writeTxOut(w, pver, msg.Version, to) if err != nil { return err } @@ -551,7 +551,7 @@ func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { // writeTxOut encodes to into the bitcoin protocol encoding for a transaction // output (TxOut) to w. -func writeTxOut(w io.Writer, pver uint32, to *TxOut) error { +func writeTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { err := writeElement(w, to.Value) if err != nil { return err From a7e3ee6aebc928fb5baa6595fb2f7ab797552a15 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 15:29:39 -0600 Subject: [PATCH 125/219] Optimize writeTxOut. Before: BenchmarkWriteTxOut 500000 4050 ns/op After: BenchmarkWriteTxOut 10000000 248 ns/op This is part ef the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- msgtx.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/msgtx.go b/msgtx.go index cf75bead..31bcc03c 100644 --- a/msgtx.go +++ b/msgtx.go @@ -552,7 +552,9 @@ func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { // writeTxOut encodes to into the bitcoin protocol encoding for a transaction // output (TxOut) to w. func writeTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { - err := writeElement(w, to.Value) + buf := make([]byte, 8) + binary.LittleEndian.PutUint64(buf, uint64(to.Value)) + _, err := w.Write(buf) if err != nil { return err } @@ -563,7 +565,7 @@ func writeTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { return err } - err = writeElement(w, to.PkScript) + _, err = w.Write(to.PkScript) if err != nil { return err } From 0228508172bb6aaa8fc54ff492ffcbde14642f9c Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 15:40:46 -0600 Subject: [PATCH 126/219] Add benchmarks for readTxOut. This commit adds a benchmark for the readTxOut function. --- bench_test.go | 27 +++++++++++++++++++++++++++ internal_test.go | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/bench_test.go b/bench_test.go index a144b932..691a6e39 100644 --- a/bench_test.go +++ b/bench_test.go @@ -141,6 +141,33 @@ func BenchmarkWriteOutPoint(b *testing.B) { } } +// BenchmarkReadTxOut performs a benchmark on how long it takes to read a +// transaction output. +func BenchmarkReadTxOut(b *testing.B) { + buf := []byte{ + 0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount + 0x43, // Varint for length of pk script + 0x41, // OP_DATA_65 + 0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c, + 0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16, + 0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c, + 0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c, + 0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4, + 0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6, + 0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e, + 0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58, + 0xee, // 65-byte signature + 0xac, // OP_CHECKSIG + } + var txOut btcwire.TxOut + for i := 0; i < b.N; i++ { + err := btcwire.TstReadTxOut(bytes.NewBuffer(buf), 0, 0, &txOut) + if err != nil { + b.Log(err) + } + } +} + // BenchmarkWriteTxOut performs a benchmark on how long it takes to write // a transaction output. func BenchmarkWriteTxOut(b *testing.B) { diff --git a/internal_test.go b/internal_test.go index 8e07775b..311e9cf5 100644 --- a/internal_test.go +++ b/internal_test.go @@ -115,6 +115,12 @@ func TstWriteOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) er return writeOutPoint(w, pver, version, op) } +// TstReadTxOut makes the internal readTxOut function available to the test +// package. +func TstReadTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { + return readTxOut(r, pver, version, to) +} + // TstWriteTxOut makes the internal writeTxOut function available to the test // package. func TstWriteTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { From cece305f7824208a2ba16d07f7ce8f517e9c015d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 15:49:26 -0600 Subject: [PATCH 127/219] Optimize readTxOut. Before: BenchmarkReadTxOut 500000 4576 ns/op After: BenchmarkReadTxOut 2000000 871 ns/op This is part ef the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- msgtx.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/msgtx.go b/msgtx.go index 31bcc03c..b56bac24 100644 --- a/msgtx.go +++ b/msgtx.go @@ -519,7 +519,9 @@ func writeTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { // readTxOut reads the next sequence of bytes from r as a transaction output // (TxOut). func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { - err := readElement(r, &to.Value) + buf := make([]byte, 8) + _, err := io.ReadFull(r, buf) + to.Value = int64(binary.LittleEndian.Uint64(buf)) if err != nil { return err } @@ -540,7 +542,7 @@ func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { } b := make([]byte, count) - err = readElement(r, b) + _, err = io.ReadFull(r, b) if err != nil { return err } From 1fe9f9e165ae31f5df6c418dd70568e72b798379 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 16:06:53 -0600 Subject: [PATCH 128/219] Add benchmarks for readTxIn. This commit adds a benchmark for the readTxIn function. --- bench_test.go | 24 ++++++++++++++++++++---- internal_test.go | 6 ++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/bench_test.go b/bench_test.go index 691a6e39..82f895b7 100644 --- a/bench_test.go +++ b/bench_test.go @@ -161,10 +161,7 @@ func BenchmarkReadTxOut(b *testing.B) { } var txOut btcwire.TxOut for i := 0; i < b.N; i++ { - err := btcwire.TstReadTxOut(bytes.NewBuffer(buf), 0, 0, &txOut) - if err != nil { - b.Log(err) - } + btcwire.TstReadTxOut(bytes.NewBuffer(buf), 0, 0, &txOut) } } @@ -176,3 +173,22 @@ func BenchmarkWriteTxOut(b *testing.B) { btcwire.TstWriteTxOut(ioutil.Discard, 0, 0, txOut) } } + +// BenchmarkReadTxIn performs a benchmark on how long it takes to read a +// transaction input. +func BenchmarkReadTxIn(b *testing.B) { + buf := []byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash + 0xff, 0xff, 0xff, 0xff, // Previous output index + 0x07, // Varint for length of signature script + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script + 0xff, 0xff, 0xff, 0xff, // Sequence + } + var txIn btcwire.TxIn + for i := 0; i < b.N; i++ { + btcwire.TstReadTxIn(bytes.NewBuffer(buf), 0, 0, &txIn) + } +} diff --git a/internal_test.go b/internal_test.go index 311e9cf5..0696c200 100644 --- a/internal_test.go +++ b/internal_test.go @@ -126,3 +126,9 @@ func TstReadTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { func TstWriteTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { return writeTxOut(w, pver, version, to) } + +// TstReadTxIn makes the internal readTxIn function available to the test +// package. +func TstReadTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { + return readTxIn(r, pver, version, ti) +} From 59da6921317b6d0cb23d4157c181d915c53badeb Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 16:18:15 -0600 Subject: [PATCH 129/219] Optimize readTxIn. Before: BenchmarkReadTxIn 1000000 2435 ns/op After: BenchmarkReadTxIn 1000000 1427 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- msgtx.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/msgtx.go b/msgtx.go index b56bac24..2e989fb2 100644 --- a/msgtx.go +++ b/msgtx.go @@ -451,7 +451,7 @@ func writeOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error // readTxIn reads the next sequence of bytes from r as a transaction input // (TxIn). func readTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { - op := OutPoint{} + var op OutPoint err := readOutPoint(r, pver, version, &op) if err != nil { return err @@ -474,16 +474,18 @@ func readTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { } b := make([]byte, count) - err = readElement(r, b) + _, err = io.ReadFull(r, b) if err != nil { return err } ti.SignatureScript = b - err = readElement(r, &ti.Sequence) + b = make([]byte, 4) + _, err = io.ReadFull(r, b) if err != nil { return err } + ti.Sequence = binary.LittleEndian.Uint32(b) return nil } @@ -521,10 +523,10 @@ func writeTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { buf := make([]byte, 8) _, err := io.ReadFull(r, buf) - to.Value = int64(binary.LittleEndian.Uint64(buf)) if err != nil { return err } + to.Value = int64(binary.LittleEndian.Uint64(buf)) count, err := readVarInt(r, pver) if err != nil { From 63cc0851e5bee7fe6152ace2c46fd796b1b08ca6 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 16:21:49 -0600 Subject: [PATCH 130/219] Add benchmarks for writeTxIn. This commit adds a benchmark for the writeTxIn function. --- bench_test.go | 9 +++++++++ internal_test.go | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/bench_test.go b/bench_test.go index 82f895b7..377ab0aa 100644 --- a/bench_test.go +++ b/bench_test.go @@ -192,3 +192,12 @@ func BenchmarkReadTxIn(b *testing.B) { btcwire.TstReadTxIn(bytes.NewBuffer(buf), 0, 0, &txIn) } } + +// BenchmarkWriteTxIn performs a benchmark on how long it takes to write +// a transaction input. +func BenchmarkWriteTxIn(b *testing.B) { + txIn := blockOne.Transactions[0].TxIn[0] + for i := 0; i < b.N; i++ { + btcwire.TstWriteTxIn(ioutil.Discard, 0, 0, txIn) + } +} diff --git a/internal_test.go b/internal_test.go index 0696c200..e8ec3535 100644 --- a/internal_test.go +++ b/internal_test.go @@ -132,3 +132,9 @@ func TstWriteTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { func TstReadTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { return readTxIn(r, pver, version, ti) } + +// TstWriteTxIn makes the internal writeTxIn function available to the test +// package. +func TstWriteTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { + return writeTxIn(w, pver, version, ti) +} From 1a1f93865f7bda02f26811fdf18a94ec889cfb31 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 16:38:51 -0600 Subject: [PATCH 131/219] Optimize writeTxIn. Before: BenchmarkWriteTxIn 5000000 422 ns/op After: BenchmarkWriteTxIn 5000000 389 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- msgtx.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/msgtx.go b/msgtx.go index 2e989fb2..182fb7eb 100644 --- a/msgtx.go +++ b/msgtx.go @@ -504,13 +504,14 @@ func writeTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { return err } - b := []byte(ti.SignatureScript) - _, err = w.Write(b) + _, err = w.Write(ti.SignatureScript) if err != nil { return err } - err = writeElement(w, &ti.Sequence) + buf := make([]byte, 4) + binary.LittleEndian.PutUint32(buf, ti.Sequence) + _, err = w.Write(buf) if err != nil { return err } From fe713b8013d355b335d7422a5b6244484332c0bb Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 16:56:42 -0600 Subject: [PATCH 132/219] Add benchmarks for transaction Serialize. This commit adds a benchmark for the MsgTx.BtcEncode/Serialize functions. --- bench_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bench_test.go b/bench_test.go index 377ab0aa..6bbd6154 100644 --- a/bench_test.go +++ b/bench_test.go @@ -201,3 +201,13 @@ func BenchmarkWriteTxIn(b *testing.B) { btcwire.TstWriteTxIn(ioutil.Discard, 0, 0, txIn) } } + +// BenchmarkSerializeTx performs a benchmark on how long it takes to serialize +// a transaction. +func BenchmarkSerializeTx(b *testing.B) { + tx := blockOne.Transactions[0] + for i := 0; i < b.N; i++ { + tx.BtcEncode(ioutil.Discard, 0) + + } +} From a81e081cc48935edf08ca060e9bbbd2c08502854 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 17:43:44 -0600 Subject: [PATCH 133/219] Optimize transaction Serialize. The benchmark results for the current commit: Before: BenchmarkSerializeTx 1000000 1233 ns/op After: BenchmarkSerializeTx 1000000 1083 ns/op The cumulative benchmark results since commit b7b700fd5aebb86addc93efecaa367a2f4976058: Before: BenchmarkSerializeTx 1000000 5437 ns/op After: BenchmarkSerializeTx 1000000 1083 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- msgtx.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/msgtx.go b/msgtx.go index 182fb7eb..1c73b833 100644 --- a/msgtx.go +++ b/msgtx.go @@ -314,7 +314,9 @@ func (msg *MsgTx) Deserialize(r io.Reader) error { // See Serialize for encoding transactions to be stored to disk, such as in a // database, as opposed to encoding transactions for the wire. func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32) error { - err := writeElement(w, msg.Version) + buf := make([]byte, 4) + binary.LittleEndian.PutUint32(buf, msg.Version) + _, err := w.Write(buf) if err != nil { return err } @@ -345,7 +347,8 @@ func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32) error { } } - err = writeElement(w, msg.LockTime) + binary.LittleEndian.PutUint32(buf, msg.LockTime) + _, err = w.Write(buf) if err != nil { return err } From 92b2f9e6b34dda683ed7ab18b7c5dab3af27a432 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 18:01:29 -0600 Subject: [PATCH 134/219] Add benchmarks for transaction Deserialize. This commit adds a benchmark for the MsgTx.BtcDecode/Deserialize functions. --- bench_test.go | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/bench_test.go b/bench_test.go index 6bbd6154..c2b097c3 100644 --- a/bench_test.go +++ b/bench_test.go @@ -202,12 +202,49 @@ func BenchmarkWriteTxIn(b *testing.B) { } } +// BenchmarkDeserializeTx performs a benchmark on how long it takes to +// deserialize a transaction. +func BenchmarkDeserializeTx(b *testing.B) { + buf := []byte{ + 0x01, 0x00, 0x00, 0x00, // Version + 0x01, // Varint for number of input transactions + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // // Previous output hash + 0xff, 0xff, 0xff, 0xff, // Prevous output index + 0x07, // Varint for length of signature script + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script + 0xff, 0xff, 0xff, 0xff, // Sequence + 0x01, // Varint for number of output transactions + 0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount + 0x43, // Varint for length of pk script + 0x41, // OP_DATA_65 + 0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c, + 0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16, + 0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c, + 0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c, + 0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4, + 0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6, + 0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e, + 0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58, + 0xee, // 65-byte signature + 0xac, // OP_CHECKSIG + 0x00, 0x00, 0x00, 0x00, // Lock time + } + var tx btcwire.MsgTx + for i := 0; i < b.N; i++ { + tx.Deserialize(bytes.NewBuffer(buf)) + + } +} + // BenchmarkSerializeTx performs a benchmark on how long it takes to serialize // a transaction. func BenchmarkSerializeTx(b *testing.B) { tx := blockOne.Transactions[0] for i := 0; i < b.N; i++ { - tx.BtcEncode(ioutil.Discard, 0) + tx.Serialize(ioutil.Discard) } } From 9b7e3527b0a87c6b0d353ff45642cb560d2440d1 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 18:41:41 -0600 Subject: [PATCH 135/219] Optimize transaction Deserialize. The benchmark results for the current commit: Before: BenchmarkDeserializeTx 500000 4018 ns/op After: BenchmarkDeserializeTx 500000 3780 ns/op The cumulative benchmark results since commit b7b700fd5aebb86addc93efecaa367a2f4976058: Before: BenchmarkDeserializeTx 200000 10665 ns/op After: BenchmarkDeserializeTx 500000 3780 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- msgtx.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/msgtx.go b/msgtx.go index 1c73b833..7e0ac38b 100644 --- a/msgtx.go +++ b/msgtx.go @@ -229,10 +229,12 @@ func (tx *MsgTx) Copy() *MsgTx { // See Deserialize for decoding transactions stored to disk, such as in a // database, as opposed to decoding transactions from the wire. func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { - err := readElement(r, &msg.Version) + buf := make([]byte, 4) + _, err := io.ReadFull(r, buf) if err != nil { return err } + msg.Version = binary.LittleEndian.Uint32(buf) count, err := readVarInt(r, pver) if err != nil { @@ -249,14 +251,14 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { return messageError("MsgTx.BtcDecode", str) } - msg.TxIn = make([]*TxIn, 0, count) + msg.TxIn = make([]*TxIn, count) for i := uint64(0); i < count; i++ { ti := TxIn{} err = readTxIn(r, pver, msg.Version, &ti) if err != nil { return err } - msg.TxIn = append(msg.TxIn, &ti) + msg.TxIn[i] = &ti } count, err = readVarInt(r, pver) @@ -274,20 +276,21 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { return messageError("MsgTx.BtcDecode", str) } - msg.TxOut = make([]*TxOut, 0, count) + msg.TxOut = make([]*TxOut, count) for i := uint64(0); i < count; i++ { to := TxOut{} err = readTxOut(r, pver, msg.Version, &to) if err != nil { return err } - msg.TxOut = append(msg.TxOut, &to) + msg.TxOut[i] = &to } - err = readElement(r, &msg.LockTime) + _, err = io.ReadFull(r, buf) if err != nil { return err } + msg.LockTime = binary.LittleEndian.Uint32(buf) return nil } From d21050a8aa1d9f578e8a736dde00dd946b2542ca Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 20:35:17 -0600 Subject: [PATCH 136/219] Add benchmark for readBlockHeader. This commit adds a benchmark for the readBlockHeader function. --- bench_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/bench_test.go b/bench_test.go index c2b097c3..244a47e5 100644 --- a/bench_test.go +++ b/bench_test.go @@ -248,3 +248,27 @@ func BenchmarkSerializeTx(b *testing.B) { } } + +// BenchmarkReadBlockHeader performs a benchmark on how long it takes to +// deserialize a block header. +func BenchmarkReadBlockHeader(b *testing.B) { + buf := []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 + 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, // MerkleRoot + 0x29, 0xab, 0x5f, 0x49, // Timestamp + 0xff, 0xff, 0x00, 0x1d, // Bits + 0xf3, 0xe0, 0x01, 0x00, // Nonce + 0x00, // TxnCount Varint + } + var header btcwire.BlockHeader + for i := 0; i < b.N; i++ { + btcwire.TstReadBlockHeader(bytes.NewBuffer(buf), 0, &header) + } +} From bc85a3101699e5e4f33dd9abd90fead9d6c11727 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 6 Nov 2013 23:00:17 -0600 Subject: [PATCH 137/219] Optimize readElement. The following benchmark results show the results for deserializing a block header: Before: BenchmarkReadBlockHeader 500000 5916 ns/op After: BenchmarkReadBlockHeader 1000000 2078 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- common.go | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/common.go b/common.go index bb5b08d3..4822db07 100644 --- a/common.go +++ b/common.go @@ -17,8 +17,112 @@ import ( const maxVarIntPayload = 9 // readElement reads the next sequence of bytes from r using little endian -// depending on the concrete type of element pointed to. +// depending on the concrete type of element pointed to. It also accepts a +// scratch buffer that is used for the primitive values rather than creating +// a new buffer on every call. func readElement(r io.Reader, element interface{}) error { + var scratch [8]byte + + // Attempt to read the element based on the concrete type via fast + // type assertions first. + switch e := element.(type) { + case *int32: + b := scratch[0:4] + _, err := io.ReadFull(r, b) + if err != nil { + return err + } + *e = int32(binary.LittleEndian.Uint32(b)) + return nil + + case *uint32: + b := scratch[0:4] + _, err := io.ReadFull(r, b) + if err != nil { + return err + } + *e = binary.LittleEndian.Uint32(b) + return nil + + case *int64: + b := scratch[0:8] + _, err := io.ReadFull(r, b) + if err != nil { + return err + } + *e = int64(binary.LittleEndian.Uint64(b)) + return nil + + case *uint64: + b := scratch[0:8] + _, err := io.ReadFull(r, b) + if err != nil { + return err + } + *e = binary.LittleEndian.Uint64(b) + return nil + + // Message header checksum. + case *[4]byte: + _, err := io.ReadFull(r, e[:]) + if err != nil { + return err + } + return nil + + // Message header command. + case *[commandSize]uint8: + _, err := io.ReadFull(r, e[:]) + if err != nil { + return err + } + return nil + + // IP address. + case *[16]byte: + _, err := io.ReadFull(r, e[:]) + if err != nil { + return err + } + return nil + + case *ShaHash: + _, err := io.ReadFull(r, e[:]) + if err != nil { + return err + } + return nil + + case *ServiceFlag: + b := scratch[0:8] + _, err := io.ReadFull(r, b) + if err != nil { + return err + } + *e = ServiceFlag(binary.LittleEndian.Uint64(b)) + return nil + + case *InvType: + b := scratch[0:4] + _, err := io.ReadFull(r, b) + if err != nil { + return err + } + *e = InvType(binary.LittleEndian.Uint32(b)) + return nil + + case *BitcoinNet: + b := scratch[0:4] + _, err := io.ReadFull(r, b) + if err != nil { + return err + } + *e = BitcoinNet(binary.LittleEndian.Uint32(b)) + return nil + } + + // Fall back to the slower binary.Read if a fast path was not available + // above. return binary.Read(r, binary.LittleEndian, element) } From 7de20add63e82fda5b8adda82fc77b93f72985b9 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 7 Nov 2013 00:30:20 -0600 Subject: [PATCH 138/219] Add benchmark for writeBlockHeader. This commit adds a benchmark for the writeBlockHeader function. --- bench_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bench_test.go b/bench_test.go index 244a47e5..0a15e6ff 100644 --- a/bench_test.go +++ b/bench_test.go @@ -272,3 +272,12 @@ func BenchmarkReadBlockHeader(b *testing.B) { btcwire.TstReadBlockHeader(bytes.NewBuffer(buf), 0, &header) } } + +// BenchmarkWriteBlockHeader performs a benchmark on how long it takes to +// serialize a block header. +func BenchmarkWriteBlockHeader(b *testing.B) { + header := blockOne.Header + for i := 0; i < b.N; i++ { + btcwire.TstWriteBlockHeader(ioutil.Discard, 0, &header) + } +} From 9ee6a8aeb666d50684137e49b1dcc41b895690ff Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 7 Nov 2013 00:56:20 -0600 Subject: [PATCH 139/219] Optimize writeElement. This commit modifies the writeElement function to have a "fast path" which uses type assertions for all of the types which btcwire write so the more expensive reflection-based binary.Write can be avoided. Also, this changes all cases that were writing raw ShaHash (32-byte) arrays (which requires a stack copy) instead simply passing the pointer. The following benchmark results show the results for serializing a block header after these changes: Before: BenchmarkWriteBlockHeader 500000 5566 ns/op After: BenchmarkWriteBlockHeader 1000000 991 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27. --- blockheader.go | 2 +- common.go | 104 +++++++++++++++++++++++++++++++++++++++++++++-- invvect.go | 2 +- msggetblocks.go | 2 +- msggetheaders.go | 2 +- 5 files changed, 105 insertions(+), 7 deletions(-) diff --git a/blockheader.go b/blockheader.go index 2b74fcc9..12b53013 100644 --- a/blockheader.go +++ b/blockheader.go @@ -107,7 +107,7 @@ func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error { // writeBlockHeader writes a bitcoin block header to w. func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { sec := uint32(bh.Timestamp.Unix()) - err := writeElements(w, bh.Version, bh.PrevBlock, bh.MerkleRoot, + err := writeElements(w, bh.Version, &bh.PrevBlock, &bh.MerkleRoot, sec, bh.Bits, bh.Nonce) if err != nil { return err diff --git a/common.go b/common.go index 4822db07..299b9f6f 100644 --- a/common.go +++ b/common.go @@ -17,9 +17,7 @@ import ( const maxVarIntPayload = 9 // readElement reads the next sequence of bytes from r using little endian -// depending on the concrete type of element pointed to. It also accepts a -// scratch buffer that is used for the primitive values rather than creating -// a new buffer on every call. +// depending on the concrete type of element pointed to. func readElement(r io.Reader, element interface{}) error { var scratch [8]byte @@ -140,6 +138,106 @@ func readElements(r io.Reader, elements ...interface{}) error { // writeElement writes the little endian representation of element to w. func writeElement(w io.Writer, element interface{}) error { + var scratch [8]byte + + // Attempt to read the element based on the concrete type via fast + // type assertions first. + switch e := element.(type) { + case int32: + b := scratch[0:4] + binary.LittleEndian.PutUint32(b, uint32(e)) + _, err := w.Write(b) + if err != nil { + return err + } + return nil + + case uint32: + b := scratch[0:4] + binary.LittleEndian.PutUint32(b, e) + _, err := w.Write(b) + if err != nil { + return err + } + return nil + + case int64: + b := scratch[0:8] + binary.LittleEndian.PutUint64(b, uint64(e)) + _, err := w.Write(b) + if err != nil { + return err + } + return nil + + case uint64: + b := scratch[0:8] + binary.LittleEndian.PutUint64(b, e) + _, err := w.Write(b) + if err != nil { + return err + } + return nil + + // Message header checksum. + case [4]byte: + _, err := w.Write(e[:]) + if err != nil { + return err + } + return nil + + // Message header command. + case [commandSize]uint8: + _, err := w.Write(e[:]) + if err != nil { + return err + } + return nil + + // IP address. + case [16]byte: + _, err := w.Write(e[:]) + if err != nil { + return err + } + return nil + + case *ShaHash: + _, err := w.Write(e[:]) + if err != nil { + return err + } + return nil + + case ServiceFlag: + b := scratch[0:8] + binary.LittleEndian.PutUint64(b, uint64(e)) + _, err := w.Write(b) + if err != nil { + return err + } + return nil + + case InvType: + b := scratch[0:4] + binary.LittleEndian.PutUint32(b, uint32(e)) + _, err := w.Write(b) + if err != nil { + return err + } + return nil + + case BitcoinNet: + b := scratch[0:4] + binary.LittleEndian.PutUint32(b, uint32(e)) + _, err := w.Write(b) + if err != nil { + return err + } + return nil + } + return binary.Write(w, binary.LittleEndian, element) } diff --git a/invvect.go b/invvect.go index 1cac91b5..a45cfbde 100644 --- a/invvect.go +++ b/invvect.go @@ -72,7 +72,7 @@ func readInvVect(r io.Reader, pver uint32, iv *InvVect) error { // writeInvVect serializes an InvVect to w depending on the protocol version. func writeInvVect(w io.Writer, pver uint32, iv *InvVect) error { - err := writeElements(w, iv.Type, iv.Hash) + err := writeElements(w, iv.Type, &iv.Hash) if err != nil { return err } diff --git a/msggetblocks.go b/msggetblocks.go index 9f083630..848fe159 100644 --- a/msggetblocks.go +++ b/msggetblocks.go @@ -110,7 +110,7 @@ func (msg *MsgGetBlocks) BtcEncode(w io.Writer, pver uint32) error { } } - err = writeElement(w, msg.HashStop) + err = writeElement(w, &msg.HashStop) if err != nil { return err } diff --git a/msggetheaders.go b/msggetheaders.go index b360203a..e0c91146 100644 --- a/msggetheaders.go +++ b/msggetheaders.go @@ -108,7 +108,7 @@ func (msg *MsgGetHeaders) BtcEncode(w io.Writer, pver uint32) error { } } - err = writeElement(w, msg.HashStop) + err = writeElement(w, &msg.HashStop) if err != nil { return err } From 119a2ddc75b3d06c14962caf5ddb6794e061e37d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 7 Nov 2013 05:17:17 -0600 Subject: [PATCH 140/219] Add tests for updated readElement/writeElement. This commit adds tests to ensure the new "fast" paths in readElement and writeElement work properly including proper fallback to the slower reflection based read/write of the binary package. --- common_test.go | 115 ++++++++++++++++++++++++++++++++++++++++++++++ internal_test.go | 16 +++++++ test_coverage.txt | 92 ++++++++++++++++++------------------- 3 files changed, 177 insertions(+), 46 deletions(-) diff --git a/common_test.go b/common_test.go index 29a65d41..20ffbdcd 100644 --- a/common_test.go +++ b/common_test.go @@ -32,6 +32,121 @@ func (r *fakeRandReader) Read(p []byte) (int, error) { 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}, + }, + { + [4]byte{0x01, 0x02, 0x03, 0x04}, + []byte{0x01, 0x02, 0x03, 0x04}, + }, + { + [btcwire.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, + }, + }, + { + (*btcwire.ShaHash)(&[btcwire.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, + }, + }, + { + btcwire.ServiceFlag(btcwire.SFNodeNetwork), + []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + }, + { + btcwire.InvType(btcwire.InvTypeTx), + []byte{0x01, 0x00, 0x00, 0x00}, + }, + { + btcwire.BitcoinNet(btcwire.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 := btcwire.TstWriteElement(&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.NewBuffer(test.buf) + val := test.in + if reflect.ValueOf(test.in).Kind() != reflect.Ptr { + val = reflect.New(reflect.TypeOf(test.in)).Interface() + } + err = btcwire.TstReadElement(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 + } + } +} + // TestVarIntWire tests wire encode and decode for variable length integers. func TestVarIntWire(t *testing.T) { pver := btcwire.ProtocolVersion diff --git a/internal_test.go b/internal_test.go index e8ec3535..e18e147d 100644 --- a/internal_test.go +++ b/internal_test.go @@ -19,12 +19,28 @@ import ( // the test package. const MaxMessagePayload uint32 = maxMessagePayload +// CommandSize makes the internal commandSize constant available to the test +// package. +const CommandSize = commandSize + // TstRandomUint64 makes the internal randomUint64 function available to the // test package. func TstRandomUint64(r io.Reader) (uint64, error) { return randomUint64(r) } +// TstReadElement makes the internal readElement function available to the +// test package. +func TstReadElement(r io.Reader, element interface{}) error { + return readElement(r, element) +} + +// TstWriteElement makes the internal writeElement function available to the +// test package. +func TstWriteElement(w io.Writer, element interface{}) error { + return writeElement(w, element) +} + // TstReadVarInt makes the internal readVarInt function available to the // test package. func TstReadVarInt(r io.Reader, pver uint32) (uint64, error) { diff --git a/test_coverage.txt b/test_coverage.txt index e2d163a3..b4ef5880 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,96 +1,94 @@ github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (33/33) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (36/36) github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) +github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (26/26) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (23/23) +github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (22/22) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) github.com/conformal/btcwire/common.go readVarInt 100.00% (21/21) +github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/common.go writeVarInt 100.00% (20/20) -github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (20/20) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) -github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (19/19) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) +github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (17/17) +github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (16/16) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (15/15) -github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (13/13) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) -github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (11/11) -github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) -github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (9/9) +github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (9/9) +github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (9/9) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) +github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NewNetAddressIPPort 100.00% (2/2) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) -github.com/conformal/btcwire/common.go readElement 100.00% (1/1) -github.com/conformal/btcwire/common.go writeElement 100.00% (1/1) github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) github.com/conformal/btcwire/error.go messageError 100.00% (1/1) github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) @@ -158,5 +156,7 @@ github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (990/990) +github.com/conformal/btcwire/common.go writeElement 96.77% (60/62) +github.com/conformal/btcwire/common.go readElement 96.72% (59/61) +github.com/conformal/btcwire --------------------------------- 99.64% (1120/1124) From 6f61e0acc2531e77c077ea6bf267ec74e20cfdd9 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 7 Nov 2013 05:37:48 -0600 Subject: [PATCH 141/219] Add negative tests for updated read/writeElement. This commit adds tests for the error paths in the updated readElement and writeElement functions. This brings the test coverage back up to 100%. --- common_test.go | 67 +++++++++++++++++++++++++++++++++++++++++ test_coverage.txt | 76 +++++++++++++++++++++++------------------------ 2 files changed, 105 insertions(+), 38 deletions(-) diff --git a/common_test.go b/common_test.go index 20ffbdcd..ca7aa30e 100644 --- a/common_test.go +++ b/common_test.go @@ -147,6 +147,73 @@ func TestElementWire(t *testing.T) { } } +// 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}, + {[4]byte{0x01, 0x02, 0x03, 0x04}, 0, io.ErrShortWrite, io.EOF}, + { + [btcwire.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, + }, + { + (*btcwire.ShaHash)(&[btcwire.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, + }, + {btcwire.ServiceFlag(btcwire.SFNodeNetwork), 0, io.ErrShortWrite, io.EOF}, + {btcwire.InvType(btcwire.InvTypeTx), 0, io.ErrShortWrite, io.EOF}, + {btcwire.BitcoinNet(btcwire.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 := btcwire.TstWriteElement(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 = btcwire.TstReadElement(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 := btcwire.ProtocolVersion diff --git a/test_coverage.txt b/test_coverage.txt index b4ef5880..495dedbf 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,28 +1,30 @@ +github.com/conformal/btcwire/common.go writeElement 100.00% (61/61) +github.com/conformal/btcwire/common.go readElement 100.00% (61/61) github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (36/36) github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (26/26) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) -github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (22/22) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) +github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (22/22) github.com/conformal/btcwire/common.go readVarInt 100.00% (21/21) -github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) -github.com/conformal/btcwire/common.go writeVarInt 100.00% (20/20) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) +github.com/conformal/btcwire/common.go writeVarInt 100.00% (20/20) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) +github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (19/19) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (17/17) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (16/16) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) +github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) @@ -31,62 +33,62 @@ github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) +github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (9/9) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (9/9) -github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (9/9) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) -github.com/conformal/btcwire/netaddress.go NewNetAddressIPPort 100.00% (2/2) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/netaddress.go NewNetAddressIPPort 100.00% (2/2) +github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) @@ -156,7 +158,5 @@ github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) -github.com/conformal/btcwire/common.go writeElement 96.77% (60/62) -github.com/conformal/btcwire/common.go readElement 96.72% (59/61) -github.com/conformal/btcwire --------------------------------- 99.64% (1120/1124) +github.com/conformal/btcwire --------------------------------- 100.00% (1123/1123) From dd41f7e91a682b7c1ceed633e12ece6ba7b6bc72 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 7 Nov 2013 06:21:44 -0600 Subject: [PATCH 142/219] Minor cleanup. This commit fixes a couple of comments and cleans up a couple of things golint complained about. --- common.go | 4 +++- msgtx.go | 18 +++++++++--------- shahash.go | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/common.go b/common.go index 299b9f6f..db4da0ac 100644 --- a/common.go +++ b/common.go @@ -140,7 +140,7 @@ func readElements(r io.Reader, elements ...interface{}) error { func writeElement(w io.Writer, element interface{}) error { var scratch [8]byte - // Attempt to read the element based on the concrete type via fast + // Attempt to write the element based on the concrete type via fast // type assertions first. switch e := element.(type) { case int32: @@ -238,6 +238,8 @@ func writeElement(w io.Writer, element interface{}) error { return nil } + // Fall back to the slower binary.Write if a fast path was not available + // above. return binary.Write(w, binary.LittleEndian, element) } diff --git a/msgtx.go b/msgtx.go index 7e0ac38b..f4ae9af7 100644 --- a/msgtx.go +++ b/msgtx.go @@ -144,7 +144,7 @@ func (msg *MsgTx) AddTxOut(to *TxOut) { } // TxSha generates the ShaHash name for the transaction. -func (tx *MsgTx) TxSha() (ShaHash, error) { +func (msg *MsgTx) TxSha() (ShaHash, error) { // Encode the transaction and calculate double sha256 on the result. // Ignore the error returns since the only way the encode could fail // is being out of memory or due to nil pointers, both of which would @@ -153,7 +153,7 @@ func (tx *MsgTx) TxSha() (ShaHash, error) { // regardless of input. var buf bytes.Buffer var sha ShaHash - _ = tx.Serialize(&buf) + _ = msg.Serialize(&buf) _ = sha.SetBytes(DoubleSha256(buf.Bytes())) // Even though this function can't currently fail, it still returns @@ -164,18 +164,18 @@ func (tx *MsgTx) TxSha() (ShaHash, error) { // Copy creates a deep copy of a transaction so that the original does not get // modified when the copy is manipulated. -func (tx *MsgTx) Copy() *MsgTx { +func (msg *MsgTx) Copy() *MsgTx { // Create new tx and start by copying primitive values and making space // for the transaction inputs and outputs. newTx := MsgTx{ - Version: tx.Version, - TxIn: make([]*TxIn, 0, len(tx.TxIn)), - TxOut: make([]*TxOut, 0, len(tx.TxOut)), - LockTime: tx.LockTime, + Version: msg.Version, + TxIn: make([]*TxIn, 0, len(msg.TxIn)), + TxOut: make([]*TxOut, 0, len(msg.TxOut)), + LockTime: msg.LockTime, } // Deep copy the old TxIn data. - for _, oldTxIn := range tx.TxIn { + for _, oldTxIn := range msg.TxIn { // Deep copy the old previous outpoint. oldOutPoint := oldTxIn.PreviousOutpoint newOutPoint := OutPoint{} @@ -202,7 +202,7 @@ func (tx *MsgTx) Copy() *MsgTx { } // Deep copy the old TxOut data. - for _, oldTxOut := range tx.TxOut { + for _, oldTxOut := range msg.TxOut { // Deep copy the old PkScript var newScript []byte oldScript := oldTxOut.PkScript diff --git a/shahash.go b/shahash.go index a3966bbf..57ea2f74 100644 --- a/shahash.go +++ b/shahash.go @@ -18,7 +18,7 @@ const MaxHashStringSize = HashSize * 2 // ErrHashStrSize describes an error that indicates the caller specified a hash // string that has too many characters. -var ErrHashStrSize = fmt.Errorf("Max hash length is %v chars", MaxHashStringSize) +var ErrHashStrSize = fmt.Errorf("max hash length is %v chars", MaxHashStringSize) // ShaHash is used in several of the bitcoin messages and common structures. It // typically represents the double sha256 of data. From 6ad853019a1c2474236ba5abe0bbb12da91c1627 Mon Sep 17 00:00:00 2001 From: Marco Peereboom Date: Wed, 6 Nov 2013 17:47:31 -0600 Subject: [PATCH 143/219] use fastsha256 --- common.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common.go b/common.go index db4da0ac..46c00406 100644 --- a/common.go +++ b/common.go @@ -6,9 +6,9 @@ package btcwire import ( "crypto/rand" - "crypto/sha256" "encoding/binary" "fmt" + "github.com/conformal/fastsha256" "io" "math" ) @@ -414,7 +414,7 @@ func RandomUint64() (uint64, error) { // DoubleSha256 calculates sha256(sha256(b)) and returns the resulting bytes. func DoubleSha256(b []byte) []byte { - hasher := sha256.New() + hasher := fastsha256.New() hasher.Write(b) sum := hasher.Sum(nil) hasher.Reset() From 977d47641f887c575edee118f3598c0dd13a0363 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 9 Dec 2013 05:41:54 -0600 Subject: [PATCH 144/219] Add support for TravisCI. Also add TravisCI build status badge to README.md. --- .travis.yml | 4 ++++ README.md | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..a189282b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: go +go: + - release + - tip diff --git a/README.md b/README.md index 2902a612..5834bd01 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ btcwire ======= +[![Build Status](https://travis-ci.org/conformal/btcwire.png?branch=master)] +(https://travis-ci.org/conformal/btcwire) + Package btcwire implements the bitcoin wire protocol. A comprehensive suite of tests with 100% test coverage is provided to ensure proper functionality. See `test_coverage.txt` for the gocov coverage report. Alternatively, if you are From e5a09bdfaa139999d8195c10cea07312dbeb1065 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 10 Dec 2013 16:13:08 -0600 Subject: [PATCH 145/219] Configure TravisCI to pull pkgs needed for tests. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a189282b..59c603be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,3 +2,4 @@ language: go go: - release - tip +install: go get -d -t -v ./... From 626662fb5fe042ad574fb817f0f1cce357fc6446 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 3 Jan 2014 08:32:43 -0600 Subject: [PATCH 146/219] Add Stringer to BitcoinNet. --- protocol.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/protocol.go b/protocol.go index ebf166fb..fb10997d 100644 --- a/protocol.go +++ b/protocol.go @@ -5,6 +5,7 @@ package btcwire import ( + "fmt" "strconv" "strings" ) @@ -101,3 +102,20 @@ const ( // TestNet3 represents the test network (version 3). TestNet3 BitcoinNet = 0x0709110b ) + +// bnStrings is a map of bitcoin networks back to their constant names for +// pretty printing. +var bnStrings = map[BitcoinNet]string{ + MainNet: "MainNet", + TestNet: "TestNet", + TestNet3: "TestNet3", +} + +// String returns the BitcoinNet in human-readable form. +func (n BitcoinNet) String() string { + if s, ok := bnStrings[n]; ok { + return s + } + + return fmt.Sprintf("Unknown BitcoinNet (%d)", uint32(n)) +} From e64e6f07576535fc30283f0ed2bed0d236497092 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 3 Jan 2014 08:36:11 -0600 Subject: [PATCH 147/219] Add tests for new BitcoinNet Stringer. --- protocol_test.go | 23 +++++++ test_coverage.txt | 155 +++++++++++++++++++++++----------------------- 2 files changed, 101 insertions(+), 77 deletions(-) diff --git a/protocol_test.go b/protocol_test.go index b95515c2..c20fc1b5 100644 --- a/protocol_test.go +++ b/protocol_test.go @@ -30,3 +30,26 @@ func TestServiceFlagStringer(t *testing.T) { } } } + +// TestBitcoinNetStringer tests the stringized output for bitcoin net types. +func TestBitcoinNetStringer(t *testing.T) { + tests := []struct { + in btcwire.BitcoinNet + want string + }{ + {btcwire.MainNet, "MainNet"}, + {btcwire.TestNet, "TestNet"}, + {btcwire.TestNet3, "TestNet3"}, + {0xffffffff, "Unknown BitcoinNet (4294967295)"}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + result := test.in.String() + if result != test.want { + t.Errorf("String #%d\n got: %s want: %s", i, result, + test.want) + continue + } + } +} diff --git a/test_coverage.txt b/test_coverage.txt index 495dedbf..0d895c4a 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,6 +1,6 @@ -github.com/conformal/btcwire/common.go writeElement 100.00% (61/61) github.com/conformal/btcwire/common.go readElement 100.00% (61/61) +github.com/conformal/btcwire/common.go writeElement 100.00% (61/61) github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (36/36) github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) @@ -10,129 +10,101 @@ github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (22/22) github.com/conformal/btcwire/common.go readVarInt 100.00% (21/21) -github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) -github.com/conformal/btcwire/common.go writeVarInt 100.00% (20/20) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) +github.com/conformal/btcwire/common.go writeVarInt 100.00% (20/20) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) +github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (19/19) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) -github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (17/17) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) +github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (17/17) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (16/16) -github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (13/13) github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) -github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (9/9) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (9/9) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) +github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (9/9) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) +github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) +github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) +github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/protocol.go BitcoinNet.String 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NewNetAddressIPPort 100.00% (2/2) +github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) -github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) -github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) -github.com/conformal/btcwire/error.go messageError 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) -github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) -github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) +github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) github.com/conformal/btcwire/msgping.go NewMsgPing 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) github.com/conformal/btcwire/msgpong.go MsgPong.Command 100.00% (1/1) +github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/msgpong.go NewMsgPong 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewOutPoint 100.00% (1/1) github.com/conformal/btcwire/msgtx.go TxIn.SerializeSize 100.00% (1/1) @@ -141,22 +113,51 @@ github.com/conformal/btcwire/msgtx.go TxOut.SerializeSize 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewTxOut 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxIn 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxOut 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Deserialize 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Serialize 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewMsgTx 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcDecode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.AddService 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) +github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) -github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (1123/1123) +github.com/conformal/btcwire/error.go messageError 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) +github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) +github.com/conformal/btcwire --------------------------------- 100.00% (1126/1126) From 497aac6d4accaabd0df9a2706b7399a5afe819ea Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 8 Jan 2014 17:21:51 -0600 Subject: [PATCH 148/219] Add new funcs to allow size hints on getdata/inv. This commit adds two new functions named NewMsgGetDataSizeHint and NewMsgInvSizeHint. These are intended to allow callers which know in advance how large the inventory lists will grow the ability to provides that information when creating the message. This in turn provides a mechanism to avoid the need to perform several grow operations of the backing array when adding large number of inventory vectors. --- msggetdata.go | 21 +++++++++++++++++++++ msginv.go | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/msggetdata.go b/msggetdata.go index c58d89cb..c64deab6 100644 --- a/msggetdata.go +++ b/msggetdata.go @@ -107,3 +107,24 @@ func NewMsgGetData() *MsgGetData { InvList: make([]*InvVect, 0, defaultInvListAlloc), } } + +// NewMsgGetDataSizeHint returns a new bitcoin getdata message that conforms to +// the Message interface. See MsgGetData for details. This function differs +// from NewMsgGetData in that it allows a default allocation size for the +// backing array which houses the inventory vector list. This allows callers +// who know in advance how large the inventory list will grow to avoid the +// overhead of growing the internal backing array several times when appending +// large amounts of inventory vectors with AddInvVect. Note that the specified +// hint is just that - a hint that is used for the default allocation size. +// Adding more (or less) inventory vectors will still work properly. The size +// hint is limited to MaxInvPerMsg. +func NewMsgGetDataSizeHint(sizeHint uint) *MsgGetData { + // Limit the specified hint to the maximum allow per message. + if sizeHint > MaxInvPerMsg { + sizeHint = MaxInvPerMsg + } + + return &MsgGetData{ + InvList: make([]*InvVect, 0, sizeHint), + } +} diff --git a/msginv.go b/msginv.go index 96538af8..7f7f08c4 100644 --- a/msginv.go +++ b/msginv.go @@ -115,3 +115,24 @@ func NewMsgInv() *MsgInv { InvList: make([]*InvVect, 0, defaultInvListAlloc), } } + +// NewMsgInvSizeHint returns a new bitcoin inv message that conforms to the +// Message interface. See MsgInv for details. This function differs from +// NewMsgInv in that it allows a default allocation size for the backing array +// which houses the inventory vector list. This allows callers who know in +// advance how large the inventory list will grow to avoid the overhead of +// growing the internal backing array several times when appending large amounts +// of inventory vectors with AddInvVect. Note that the specified hint is just +// that - a hint that is used for the default allocation size. Adding more +// (or less) inventory vectors will still work properly. The size hint is +// limited to MaxInvPerMsg. +func NewMsgInvSizeHint(sizeHint uint) *MsgInv { + // Limit the specified hint to the maximum allow per message. + if sizeHint > MaxInvPerMsg { + sizeHint = MaxInvPerMsg + } + + return &MsgInv{ + InvList: make([]*InvVect, 0, sizeHint), + } +} From 2458841855ed7783f5fc2bfce519dcee4fe9b10a Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 8 Jan 2014 17:42:57 -0600 Subject: [PATCH 149/219] Add tests for new size hint functions. This brings the test coverage back up to 100%. --- msggetdata_test.go | 9 ++++++++ msginv_test.go | 9 ++++++++ test_coverage.txt | 54 ++++++++++++++++++++++++---------------------- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/msggetdata_test.go b/msggetdata_test.go index 84461e87..e2c9a2ba 100644 --- a/msggetdata_test.go +++ b/msggetdata_test.go @@ -57,6 +57,15 @@ func TestGetData(t *testing.T) { "vectors not received") } + // Ensure creating the message with a size hint larger than the max + // works as expected. + msg = btcwire.NewMsgGetDataSizeHint(btcwire.MaxInvPerMsg + 1) + wantCap := btcwire.MaxInvPerMsg + if cap(msg.InvList) != wantCap { + t.Errorf("NewMsgGetDataSizeHint: wrong cap for size hint - "+ + "got %v, want %v", cap(msg.InvList), wantCap) + } + return } diff --git a/msginv_test.go b/msginv_test.go index ca068121..7ea4510c 100644 --- a/msginv_test.go +++ b/msginv_test.go @@ -57,6 +57,15 @@ func TestInv(t *testing.T) { "vectors not received") } + // Ensure creating the message with a size hint larger than the max + // works as expected. + msg = btcwire.NewMsgInvSizeHint(btcwire.MaxInvPerMsg + 1) + wantCap := btcwire.MaxInvPerMsg + if cap(msg.InvList) != wantCap { + t.Errorf("NewMsgInvSizeHint: wrong cap for size hint - "+ + "got %v, want %v", cap(msg.InvList), wantCap) + } + return } diff --git a/test_coverage.txt b/test_coverage.txt index 0d895c4a..0df2bc76 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -16,8 +16,8 @@ github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (19/19) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (17/17) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (16/16) @@ -31,9 +31,9 @@ github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (13/13) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) @@ -41,8 +41,8 @@ github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (9/9) github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (9/9) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) @@ -51,26 +51,26 @@ github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) +github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) github.com/conformal/btcwire/common.go readElements 100.00% (5/5) github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) @@ -79,25 +79,26 @@ github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/ github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/protocol.go BitcoinNet.String 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/msggetdata.go NewMsgGetDataSizeHint 100.00% (3/3) github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) +github.com/conformal/btcwire/msginv.go NewMsgInvSizeHint 100.00% (3/3) +github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) +github.com/conformal/btcwire/protocol.go BitcoinNet.String 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NewNetAddressIPPort 100.00% (2/2) github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) -github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) github.com/conformal/btcwire/msgping.go NewMsgPing 100.00% (1/1) @@ -142,8 +143,8 @@ github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) github.com/conformal/btcwire/error.go messageError 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) @@ -151,13 +152,14 @@ github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00 github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (1126/1126) +github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) +github.com/conformal/btcwire --------------------------------- 100.00% (1132/1132) From 6c7f45fdb74e92e8de38775a691545ef888d8998 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 8 Jan 2014 23:44:08 -0600 Subject: [PATCH 150/219] Add 2014 to copyright dates. --- LICENSE | 2 +- bench_test.go | 2 +- blockheader.go | 2 +- blockheader_test.go | 2 +- common.go | 2 +- common_test.go | 2 +- doc.go | 2 +- error.go | 2 +- fakeconn_test.go | 2 +- fakemessage_test.go | 2 +- fixedIO_test.go | 2 +- genesis.go | 2 +- genesis_test.go | 2 +- internal_test.go | 2 +- invvect.go | 2 +- invvect_test.go | 2 +- legacy.go | 2 +- message.go | 2 +- message_test.go | 2 +- msgaddr.go | 2 +- msgaddr_test.go | 2 +- msgalert.go | 2 +- msgalert_test.go | 2 +- msgblock.go | 2 +- msgblock_test.go | 2 +- msggetaddr.go | 2 +- msggetaddr_test.go | 2 +- msggetblocks.go | 2 +- msggetblocks_test.go | 2 +- msggetdata.go | 2 +- msggetdata_test.go | 2 +- msggetheaders.go | 2 +- msggetheaders_test.go | 2 +- msgheaders.go | 2 +- msgheaders_test.go | 2 +- msginv.go | 2 +- msginv_test.go | 2 +- msgmempool.go | 2 +- msgmempool_test.go | 2 +- msgnotfound.go | 2 +- msgnotfound_test.go | 2 +- msgping.go | 2 +- msgping_test.go | 2 +- msgpong.go | 2 +- msgpong_test.go | 2 +- msgtx.go | 2 +- msgtx_test.go | 2 +- msgverack.go | 2 +- msgverack_test.go | 2 +- msgversion.go | 2 +- msgversion_test.go | 2 +- netaddress.go | 2 +- netaddress_test.go | 2 +- protocol.go | 2 +- protocol_test.go | 2 +- shahash.go | 2 +- shahash_test.go | 2 +- 57 files changed, 57 insertions(+), 57 deletions(-) diff --git a/LICENSE b/LICENSE index 0d760cbb..992dd50d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013 Conformal Systems LLC. +Copyright (c) 2013-2014 Conformal Systems LLC. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/bench_test.go b/bench_test.go index 0a15e6ff..d127c328 100644 --- a/bench_test.go +++ b/bench_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/blockheader.go b/blockheader.go index 12b53013..f01bcb86 100644 --- a/blockheader.go +++ b/blockheader.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/blockheader_test.go b/blockheader_test.go index ca352883..a6a9c3b7 100644 --- a/blockheader_test.go +++ b/blockheader_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/common.go b/common.go index 46c00406..ef47f7ac 100644 --- a/common.go +++ b/common.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/common_test.go b/common_test.go index ca7aa30e..c5ca0291 100644 --- a/common_test.go +++ b/common_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/doc.go b/doc.go index dad217f6..a04d077f 100644 --- a/doc.go +++ b/doc.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/error.go b/error.go index da617138..43282a47 100644 --- a/error.go +++ b/error.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/fakeconn_test.go b/fakeconn_test.go index 3c6f6bc6..51b7d03d 100644 --- a/fakeconn_test.go +++ b/fakeconn_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/fakemessage_test.go b/fakemessage_test.go index c1676ee9..d08b4a5b 100644 --- a/fakemessage_test.go +++ b/fakemessage_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/fixedIO_test.go b/fixedIO_test.go index 7ea0377d..139b248a 100644 --- a/fixedIO_test.go +++ b/fixedIO_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/genesis.go b/genesis.go index 1703f5ee..3d1824fe 100644 --- a/genesis.go +++ b/genesis.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/genesis_test.go b/genesis_test.go index e886b824..5e0529e0 100644 --- a/genesis_test.go +++ b/genesis_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/internal_test.go b/internal_test.go index e18e147d..686bdb7e 100644 --- a/internal_test.go +++ b/internal_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/invvect.go b/invvect.go index a45cfbde..b0dbb697 100644 --- a/invvect.go +++ b/invvect.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/invvect_test.go b/invvect_test.go index 6a80531f..015fafbb 100644 --- a/invvect_test.go +++ b/invvect_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/legacy.go b/legacy.go index 9234feaf..ee18b357 100644 --- a/legacy.go +++ b/legacy.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/message.go b/message.go index 06c65f1a..32e813b8 100644 --- a/message.go +++ b/message.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/message_test.go b/message_test.go index 9186bdbd..be29e7ef 100644 --- a/message_test.go +++ b/message_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgaddr.go b/msgaddr.go index b4dcfb12..800e65fa 100644 --- a/msgaddr.go +++ b/msgaddr.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgaddr_test.go b/msgaddr_test.go index 32790211..21126e99 100644 --- a/msgaddr_test.go +++ b/msgaddr_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgalert.go b/msgalert.go index 78879c12..fdb1d66d 100644 --- a/msgalert.go +++ b/msgalert.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgalert_test.go b/msgalert_test.go index 99e602a1..3e9e3ce5 100644 --- a/msgalert_test.go +++ b/msgalert_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgblock.go b/msgblock.go index 35693211..47661e10 100644 --- a/msgblock.go +++ b/msgblock.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgblock_test.go b/msgblock_test.go index 3104de8d..8e659e73 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msggetaddr.go b/msggetaddr.go index 385a3e44..78716806 100644 --- a/msggetaddr.go +++ b/msggetaddr.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msggetaddr_test.go b/msggetaddr_test.go index fdbc2d33..296a6fbb 100644 --- a/msggetaddr_test.go +++ b/msggetaddr_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msggetblocks.go b/msggetblocks.go index 848fe159..1996ae44 100644 --- a/msggetblocks.go +++ b/msggetblocks.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msggetblocks_test.go b/msggetblocks_test.go index 8420f15b..2b8482d8 100644 --- a/msggetblocks_test.go +++ b/msggetblocks_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msggetdata.go b/msggetdata.go index c64deab6..a7494f70 100644 --- a/msggetdata.go +++ b/msggetdata.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msggetdata_test.go b/msggetdata_test.go index e2c9a2ba..ca7e1edf 100644 --- a/msggetdata_test.go +++ b/msggetdata_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msggetheaders.go b/msggetheaders.go index e0c91146..bbd6cc17 100644 --- a/msggetheaders.go +++ b/msggetheaders.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msggetheaders_test.go b/msggetheaders_test.go index 3afd7619..ca8a2ebc 100644 --- a/msggetheaders_test.go +++ b/msggetheaders_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgheaders.go b/msgheaders.go index 294955a1..aace3c0f 100644 --- a/msgheaders.go +++ b/msgheaders.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgheaders_test.go b/msgheaders_test.go index 689d21b9..67eaa76a 100644 --- a/msgheaders_test.go +++ b/msgheaders_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msginv.go b/msginv.go index 7f7f08c4..594bda0d 100644 --- a/msginv.go +++ b/msginv.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msginv_test.go b/msginv_test.go index 7ea4510c..1ba6e31c 100644 --- a/msginv_test.go +++ b/msginv_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgmempool.go b/msgmempool.go index 9a75f839..cb4f5b75 100644 --- a/msgmempool.go +++ b/msgmempool.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgmempool_test.go b/msgmempool_test.go index 4cab821e..af22dbae 100644 --- a/msgmempool_test.go +++ b/msgmempool_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgnotfound.go b/msgnotfound.go index 0370d104..47188299 100644 --- a/msgnotfound.go +++ b/msgnotfound.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgnotfound_test.go b/msgnotfound_test.go index 26a43e99..da6bf57d 100644 --- a/msgnotfound_test.go +++ b/msgnotfound_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgping.go b/msgping.go index 25a7f521..7a7937aa 100644 --- a/msgping.go +++ b/msgping.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgping_test.go b/msgping_test.go index 4a6b6819..f84bae4e 100644 --- a/msgping_test.go +++ b/msgping_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgpong.go b/msgpong.go index 70127726..d8958031 100644 --- a/msgpong.go +++ b/msgpong.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgpong_test.go b/msgpong_test.go index fb10d51e..d588c6fb 100644 --- a/msgpong_test.go +++ b/msgpong_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgtx.go b/msgtx.go index f4ae9af7..c5cc93d2 100644 --- a/msgtx.go +++ b/msgtx.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgtx_test.go b/msgtx_test.go index 520b90b3..47b1f1d9 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgverack.go b/msgverack.go index 65ba8afc..94a27249 100644 --- a/msgverack.go +++ b/msgverack.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgverack_test.go b/msgverack_test.go index a32acd19..e1c09366 100644 --- a/msgverack_test.go +++ b/msgverack_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgversion.go b/msgversion.go index 5330ca66..c8ac391b 100644 --- a/msgversion.go +++ b/msgversion.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/msgversion_test.go b/msgversion_test.go index 5f524e73..d12e7044 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/netaddress.go b/netaddress.go index 446a9939..8d060f8e 100644 --- a/netaddress.go +++ b/netaddress.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/netaddress_test.go b/netaddress_test.go index aed67503..27a6825b 100644 --- a/netaddress_test.go +++ b/netaddress_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/protocol.go b/protocol.go index fb10997d..7436c0b8 100644 --- a/protocol.go +++ b/protocol.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/protocol_test.go b/protocol_test.go index c20fc1b5..3eb79939 100644 --- a/protocol_test.go +++ b/protocol_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/shahash.go b/shahash.go index 57ea2f74..466aef58 100644 --- a/shahash.go +++ b/shahash.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. diff --git a/shahash_test.go b/shahash_test.go index a1f5774c..e13c5849 100644 --- a/shahash_test.go +++ b/shahash_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Conformal Systems LLC. +// Copyright (c) 2013-2014 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. From 144822d4bfce9cf302d7d5ade8b9604964c79f94 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 18 Jan 2014 19:37:33 -0600 Subject: [PATCH 151/219] Remove BlockHeader.TxnCount field. This commit removes the TxnCount field from the BlockHeader type and updates the tests accordingly. Note that this change does not affect the actual wire protocol encoding in any way. The reason the field has been removed is it really doesn't belong there even though the wire protocol wiki entry on the official bitcoin wiki implies it does. The implication is an artifact from the way the reference implementation serializes headers (MsgHeaders) messages. It includes the transaction count, which is naturally always 0 for headers, along with every header. However, in reality, a block header does not include the transaction count. This can be evidenced by looking at how a block hash is calculated. It is only up to and including the Nonce field (a total of 80 bytes). From an API standpoint, having the field as part of the BlockHeader type results in several odd cases. For example, the transaction count for MsgBlocks (the only place that actually has a real transaction count since MsgHeaders does not) is available by taking the len of the Transactions slice. As such, having the extra field in the BlockHeader is really a useless field that could potentially get out of sync and cause the encode to fail. Another example is related to deserializing a block header from the database in order to serve it in response to a getheaders (MsgGetheaders) request. If a block header is assumed to have the transaction count as a part of it, then derserializing a block header not only consumes more than the 80 bytes that actually comprise the header as stated above, but you then need to change the transaction count to 0 before sending the headers (MsgHeaders) message. So, not only are you reading and deserializing more bytes than needed, but worse, you generally have to make a copy of it so you can change the transaction count without busting cached headers. This is part 1 of #13. --- blockheader.go | 21 ++------------------- blockheader_test.go | 2 -- genesis.go | 3 --- msgblock.go | 32 ++++++++++++++++++++------------ msgblock_test.go | 1 - msgheaders.go | 32 +++++++++++++++++++++----------- msgheaders_test.go | 10 ++++++---- 7 files changed, 49 insertions(+), 52 deletions(-) diff --git a/blockheader.go b/blockheader.go index f01bcb86..28f75cba 100644 --- a/blockheader.go +++ b/blockheader.go @@ -14,8 +14,8 @@ import ( const BlockVersion uint32 = 2 // Version 4 bytes + Timestamp 4 bytes + Bits 4 bytes + Nonce 4 bytes + -// TxnCount (varInt) + PrevBlock and MerkleRoot hashes. -const maxBlockHeaderPayload = 16 + maxVarIntPayload + (HashSize * 2) +// PrevBlock and MerkleRoot hashes. +const maxBlockHeaderPayload = 16 + (HashSize * 2) // BlockHeader defines information about a block and is used in the bitcoin // block (MsgBlock) and headers (MsgHeaders) messages. @@ -38,11 +38,6 @@ type BlockHeader struct { // Nonce used to generate the block. Nonce uint32 - - // Number of transactions in the block. For the bitcoin headers - // (MsgHeaders) message, this must be 0. This is encoded as a variable - // length integer on the wire. - TxnCount uint64 } // blockHashLen is a constant that represents how much of the block header is @@ -81,7 +76,6 @@ func NewBlockHeader(prevHash *ShaHash, merkleRootHash *ShaHash, bits uint32, Timestamp: time.Now(), Bits: bits, Nonce: nonce, - TxnCount: 0, } } @@ -95,12 +89,6 @@ func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error { } bh.Timestamp = time.Unix(int64(sec), 0) - count, err := readVarInt(r, pver) - if err != nil { - return err - } - bh.TxnCount = count - return nil } @@ -113,10 +101,5 @@ func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { return err } - err = writeVarInt(w, pver, bh.TxnCount) - if err != nil { - return err - } - return nil } diff --git a/blockheader_test.go b/blockheader_test.go index a6a9c3b7..d8195544 100644 --- a/blockheader_test.go +++ b/blockheader_test.go @@ -61,7 +61,6 @@ func TestBlockHeaderWire(t *testing.T) { Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST Bits: bits, Nonce: nonce, - TxnCount: 0, } // baseBlockHdrEncoded is the wire encoded bytes of baseBlockHdr. @@ -78,7 +77,6 @@ func TestBlockHeaderWire(t *testing.T) { 0x29, 0xab, 0x5f, 0x49, // Timestamp 0xff, 0xff, 0x00, 0x1d, // Bits 0xf3, 0xe0, 0x01, 0x00, // Nonce - 0x00, // TxnCount Varint } tests := []struct { diff --git a/genesis.go b/genesis.go index 3d1824fe..3ec7b63f 100644 --- a/genesis.go +++ b/genesis.go @@ -80,7 +80,6 @@ var GenesisBlock = MsgBlock{ Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 18:15:05 +0000 UTC Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] Nonce: 0x7c2bac1d, // 2083236893 - TxnCount: 1, }, Transactions: []*MsgTx{&genesisCoinbaseTx}, } @@ -109,7 +108,6 @@ var TestNetGenesisBlock = MsgBlock{ Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000] Nonce: 2, - TxnCount: 1, }, Transactions: []*MsgTx{&genesisCoinbaseTx}, } @@ -138,7 +136,6 @@ var TestNet3GenesisBlock = MsgBlock{ Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] Nonce: 0x18aea41a, // 414098458 - TxnCount: 1, }, Transactions: []*MsgTx{&genesisCoinbaseTx}, } diff --git a/msgblock.go b/msgblock.go index 47661e10..9b2fe373 100644 --- a/msgblock.go +++ b/msgblock.go @@ -49,22 +49,18 @@ type MsgBlock struct { Transactions []*MsgTx } -// AddTransaction adds a transaction to the message and updates Header.TxnCount -// accordingly. +// 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) - msg.Header.TxnCount = uint64(len(msg.Transactions)) return nil } -// ClearTransactions removes all transactions from the message and updates -// Header.TxnCount accordingly. +// ClearTransactions removes all transactions from the message. func (msg *MsgBlock) ClearTransactions() { msg.Transactions = make([]*MsgTx, 0, defaultTransactionAlloc) - msg.Header.TxnCount = 0 } // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. @@ -77,10 +73,14 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32) error { return err } + txCount, err := readVarInt(r, pver) + if err != nil { + return err + } + // Prevent more transactions than could possibly fit into a block. // It would be possible to cause memory exhaustion and panics without // a sane upper bound on this count. - txCount := msg.Header.TxnCount if txCount > maxTxPerBlock { str := fmt.Sprintf("too many transactions to fit into a block "+ "[count %d, max %d]", txCount, maxTxPerBlock) @@ -130,10 +130,14 @@ func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) { return nil, err } + txCount, err := readVarInt(r, 0) + if err != nil { + return nil, err + } + // Prevent more transactions than could possibly fit into a block. // It would be possible to cause memory exhaustion and panics without // a sane upper bound on this count. - txCount := msg.Header.TxnCount if txCount > maxTxPerBlock { str := fmt.Sprintf("too many transactions to fit into a block "+ "[count %d, max %d]", txCount, maxTxPerBlock) @@ -163,13 +167,16 @@ func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) { // See Serialize for encoding blocks to be stored to disk, such as in a // database, as opposed to encoding blocks for the wire. func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32) error { - msg.Header.TxnCount = uint64(len(msg.Transactions)) - err := writeBlockHeader(w, pver, &msg.Header) if err != nil { return err } + err = writeVarInt(w, pver, uint64(len(msg.Transactions))) + if err != nil { + return err + } + for _, tx := range msg.Transactions { err = tx.BtcEncode(w, pver) if err != nil { @@ -205,8 +212,9 @@ func (msg *MsgBlock) Command() string { // MaxPayloadLength returns the maximum length the payload can be for the // receiver. This is part of the Message interface implementation. func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 { - // Block header at 81 bytes + max transactions which can vary up to the - // maxBlockPayload (including the block header). + // Block header at 80 bytes + transaction count + max transactions + // which can vary up to the MaxBlockPayload (including the block header + // and transaction count). return MaxBlockPayload } diff --git a/msgblock_test.go b/msgblock_test.go index 8e659e73..ae252436 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -468,7 +468,6 @@ var blockOne = btcwire.MsgBlock{ Timestamp: time.Unix(0x4966bc61, 0), // 2009-01-08 20:54:25 -0600 CST Bits: 0x1d00ffff, // 486604799 Nonce: 0x9962e301, // 2573394689 - TxnCount: 1, }, Transactions: []*btcwire.MsgTx{ &btcwire.MsgTx{ diff --git a/msgheaders.go b/msgheaders.go index aace3c0f..a9f5fe07 100644 --- a/msgheaders.go +++ b/msgheaders.go @@ -57,10 +57,15 @@ func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32) error { return err } + txCount, err := readVarInt(r, pver) + if err != nil { + return err + } + // Ensure the transaction count is zero for headers. - if bh.TxnCount > 0 { + if txCount > 0 { str := fmt.Sprintf("block headers may not contain "+ - "transactions [count %v]", bh.TxnCount) + "transactions [count %v]", txCount) return messageError("MsgHeaders.BtcDecode", str) } msg.AddBlockHeader(&bh) @@ -86,17 +91,20 @@ func (msg *MsgHeaders) BtcEncode(w io.Writer, pver uint32) error { } for _, bh := range msg.Headers { - // Ensure block headers do not contain a transaction count. - if bh.TxnCount > 0 { - str := fmt.Sprintf("block headers may not contain "+ - "transactions [count %v]", bh.TxnCount) - return messageError("MsgHeaders.BtcEncode", str) - } - err := writeBlockHeader(w, pver, bh) if err != nil { return err } + + // The wire protocol encoding always includes a 0 for the number + // of transactions on header messages. This is really just an + // artifact of the way the original implementation serializes + // block headers, but it is required. + err = writeVarInt(w, pver, 0) + if err != nil { + return err + } + } return nil @@ -111,8 +119,10 @@ func (msg *MsgHeaders) Command() string { // MaxPayloadLength returns the maximum length the payload can be for the // receiver. This is part of the Message interface implementation. func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 { - // Num headers (varInt) + max allowed headers. - return maxVarIntPayload + (maxBlockHeaderPayload * MaxBlockHeadersPerMsg) + // Num headers (varInt) + max allowed headers (header length + 1 byte + // for the number of transactions which is always 0). + return maxVarIntPayload + ((maxBlockHeaderPayload + 1) * + MaxBlockHeadersPerMsg) } // NewMsgHeaders returns a new bitcoin headers message that conforms to the diff --git a/msgheaders_test.go b/msgheaders_test.go index 67eaa76a..1eec69e1 100644 --- a/msgheaders_test.go +++ b/msgheaders_test.go @@ -26,8 +26,9 @@ func TestHeaders(t *testing.T) { } // Ensure max payload is expected value for latest protocol version. - // Num headers (varInt) + max allowed headers. - wantPayload := uint32(178009) + // Num headers (varInt) + max allowed headers (header length + 1 byte + // for the number of transactions which is always 0). + wantPayload := uint32(162009) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { t.Errorf("MaxPayloadLength: wrong max payload length for "+ @@ -262,7 +263,6 @@ func TestHeadersWireErrors(t *testing.T) { bhTrans := btcwire.NewBlockHeader(&hash, &merkleHash, bits, nonce) bhTrans.Version = blockOne.Header.Version bhTrans.Timestamp = blockOne.Header.Timestamp - bhTrans.TxnCount = 1 transHeader := btcwire.NewMsgHeaders() transHeader.AddBlockHeader(bhTrans) @@ -298,8 +298,10 @@ func TestHeadersWireErrors(t *testing.T) { {oneHeader, oneHeaderEncoded, pver, 5, io.ErrShortWrite, io.EOF}, // Force error with greater than max headers. {maxHeaders, maxHeadersEncoded, pver, 3, btcwireErr, btcwireErr}, + // Force error with number of transactions. + {transHeader, transHeaderEncoded, pver, 81, io.ErrShortWrite, io.EOF}, // Force error with included transactions. - {transHeader, transHeaderEncoded, pver, len(transHeaderEncoded), btcwireErr, btcwireErr}, + {transHeader, transHeaderEncoded, pver, len(transHeaderEncoded), nil, btcwireErr}, } t.Logf("Running %d tests", len(tests)) From d6aea22adb80ac93ef7feb57dce3070c9f5cbbb5 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 18 Jan 2014 20:35:45 -0600 Subject: [PATCH 152/219] Remove deprecated InvType_* constants. This closes #13. --- legacy.go | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 legacy.go diff --git a/legacy.go b/legacy.go deleted file mode 100644 index ee18b357..00000000 --- a/legacy.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package btcwire - -// These constants are deprecated as they do not follow the standard Go style -// guidelines and are only provided for backwards compatibility. Use the -// InvType* constants instead. -const ( - InvVect_Error InvType = InvTypeError // DEPRECATED - InvVect_Tx InvType = InvTypeTx // DEPRECATED - InvVect_Block InvType = InvTypeBlock // DEPRECATED -) From 06d1236d490d5db07f7ba0b9b3428981b4fd3379 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 18 Jan 2014 17:32:36 -0600 Subject: [PATCH 153/219] Add Serialize/Deserialize for BlockHeader. This commit introduces two new functions for Blockheader named Serialize and Deserialize. The functions provide a stable mechanism for serializing and deserializing block headers to and from disk. The main benefit here is deserialization of the header since typically only full blocks are serialized to disk. Then when a header is needed, only the header portion of the block is read and deserialized. --- blockheader.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/blockheader.go b/blockheader.go index 28f75cba..9eb643e6 100644 --- a/blockheader.go +++ b/blockheader.go @@ -63,6 +63,26 @@ func (h *BlockHeader) BlockSha() (ShaHash, error) { return sha, nil } +// Deserialize decodes a block header from r into the receiver using a format +// that is suitable for long-term storage such as a database while respecting +// the Version field. +func (h *BlockHeader) Deserialize(r io.Reader) 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 readBlockHeader. + return readBlockHeader(r, 0, h) +} + +// Serialize encodes a block header from r into the receiver using a format +// that is suitable for long-term storage such as a database while respecting +// the Version field. +func (h *BlockHeader) 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 writeBlockHeader. + return writeBlockHeader(w, 0, h) +} + // NewBlockHeader returns a new BlockHeader using the provided previous block // hash, merkle root hash, difficulty bits, and nonce used to generate the // block with defaults for the remaining fields. @@ -79,7 +99,9 @@ func NewBlockHeader(prevHash *ShaHash, merkleRootHash *ShaHash, bits uint32, } } -// readBlockHeader reads a bitcoin block header from r. +// readBlockHeader reads a bitcoin block header from r. See Deserialize for +// decoding block headers stored to disk, such as in a database, as opposed to +// decoding from the wire. func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error { var sec uint32 err := readElements(r, &bh.Version, &bh.PrevBlock, &bh.MerkleRoot, &sec, @@ -92,7 +114,9 @@ func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error { return nil } -// writeBlockHeader writes a bitcoin block header to w. +// writeBlockHeader writes a bitcoin block header to w. See Serialize for +// encoding block headers to be stored to disk, such as in a database, as +// opposed to encoding for the wire. func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { sec := uint32(bh.Timestamp.Unix()) err := writeElements(w, bh.Version, &bh.PrevBlock, &bh.MerkleRoot, From 6672f71d68ecdd68bfdcfe9b297711045621443e Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 18 Jan 2014 20:31:08 -0600 Subject: [PATCH 154/219] Add tests for new Serialize/Deserialize functions. --- blockheader_test.go | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/blockheader_test.go b/blockheader_test.go index d8195544..903e7c34 100644 --- a/blockheader_test.go +++ b/blockheader_test.go @@ -156,3 +156,79 @@ func TestBlockHeaderWire(t *testing.T) { } } } + +// TestBlockHeaderSerialize tests BlockHeader serialize and deserialize. +func TestBlockHeaderSerialize(t *testing.T) { + nonce := uint32(123123) // 0x1e0f3 + + // baseBlockHdr is used in the various tests as a baseline BlockHeader. + hash := btcwire.GenesisHash + merkleHash := btcwire.GenesisMerkleRoot + bits := uint32(0x1d00ffff) + baseBlockHdr := &btcwire.BlockHeader{ + Version: 1, + PrevBlock: hash, + MerkleRoot: merkleHash, + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST + Bits: bits, + Nonce: nonce, + } + + // baseBlockHdrEncoded is the wire encoded bytes of baseBlockHdr. + baseBlockHdrEncoded := []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 + 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, // MerkleRoot + 0x29, 0xab, 0x5f, 0x49, // Timestamp + 0xff, 0xff, 0x00, 0x1d, // Bits + 0xf3, 0xe0, 0x01, 0x00, // Nonce + } + + tests := []struct { + in *btcwire.BlockHeader // Data to encode + out *btcwire.BlockHeader // Expected decoded data + buf []byte // Serialized data + }{ + { + baseBlockHdr, + baseBlockHdr, + baseBlockHdrEncoded, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Serialize the block header. + var buf bytes.Buffer + err := test.in.Serialize(&buf) + if err != nil { + t.Errorf("Serialize #%d error %v", i, err) + continue + } + if !bytes.Equal(buf.Bytes(), test.buf) { + t.Errorf("Serialize #%d\n got: %s want: %s", i, + spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) + continue + } + + // Deserialize the block header. + var bh btcwire.BlockHeader + rbuf := bytes.NewBuffer(test.buf) + err = bh.Deserialize(rbuf) + if err != nil { + t.Errorf("Deserialize #%d error %v", i, err) + continue + } + if !reflect.DeepEqual(&bh, test.out) { + t.Errorf("Deserialize #%d\n got: %s want: %s", i, + spew.Sdump(&bh), spew.Sdump(test.out)) + continue + } + } +} From ff783faf530a841544821099485c67463ac6de21 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 18 Jan 2014 22:29:44 -0600 Subject: [PATCH 155/219] Add Read/WriteMessageN to return number of bytes. This commit adds two new funtions named ReadMessageN and WriteMessageN which return an additional paramter for the number of bytes read or written, respectively. It also adds tests to ensure the number of bytes read and written are the expected values both for successful reads/writes and unsuccessful ones. Closes #6. --- internal_test.go | 2 +- message.go | 126 ++++++++++++++++++++++++--------- message_test.go | 114 +++++++++++++++++++++++------- test_coverage.txt | 176 ++++++++++++++++++++++++---------------------- 4 files changed, 271 insertions(+), 147 deletions(-) diff --git a/internal_test.go b/internal_test.go index 686bdb7e..c2fce9c5 100644 --- a/internal_test.go +++ b/internal_test.go @@ -115,7 +115,7 @@ func TstWriteBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { // TstReadMessageHeader makes the internal readMessageHeader function available // to the test package. -func TstReadMessageHeader(r io.Reader) (*messageHeader, error) { +func TstReadMessageHeader(r io.Reader) (int, *messageHeader, error) { return readMessageHeader(r) } diff --git a/message.go b/message.go index 32e813b8..98561734 100644 --- a/message.go +++ b/message.go @@ -11,6 +11,11 @@ import ( "unicode/utf8" ) +// MessageHeaderSize is the number of bytes in a bitcoin message header. +// Bitcoin network (magic) 4 bytes + command 12 bytes + payload length 4 bytes + +// checksum 4 bytes. +const MessageHeaderSize = 24 + // commandSize is the fixed size of all commands in the common bitcoin message // header. Shorter commands must be zero padded. const commandSize = 12 @@ -118,19 +123,27 @@ type messageHeader struct { } // readMessageHeader reads a bitcoin message header from r. -func readMessageHeader(r io.Reader) (*messageHeader, error) { - var command [commandSize]byte - - hdr := messageHeader{} - err := readElements(r, &hdr.magic, &command, &hdr.length, &hdr.checksum) +func readMessageHeader(r io.Reader) (int, *messageHeader, error) { + // Since readElements doesn't return the amount of bytes read, attempt + // to read the entire header into a buffer first in case there is a + // short read so the proper amount of read bytes are known. This works + // since the header is a fixed size. + headerBytes := make([]byte, MessageHeaderSize) + n, err := io.ReadFull(r, headerBytes) if err != nil { - return nil, err + return n, nil, err } + hr := bytes.NewBuffer(headerBytes) + + // Create and populate a messageHeader struct from the raw header bytes. + hdr := messageHeader{} + var command [commandSize]byte + readElements(hr, &hdr.magic, &command, &hdr.length, &hdr.checksum) // Strip trailing zeros from command string. hdr.command = string(bytes.TrimRight(command[:], string(0))) - return &hdr, nil + return n, &hdr, nil } // discardInput reads n bytes from reader r in chunks and discards the read @@ -153,17 +166,19 @@ func discardInput(r io.Reader, n uint32) { } } -// WriteMessage writes a bitcoin Message to w including the necessary header -// information. -func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) error { - var command [commandSize]byte +// WriteMessageN writes a bitcoin Message to w including the necessary header +// information and returns the number of bytes written. This function is the +// same as WriteMessage except it also returns the number of bytes written. +func WriteMessageN(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) (int, error) { + totalBytes := 0 // Enforce max command size. + var command [commandSize]byte cmd := msg.Command() if len(cmd) > commandSize { str := fmt.Sprintf("command [%s] is too long [max %v]", cmd, commandSize) - return messageError("WriteMessage", str) + return totalBytes, messageError("WriteMessage", str) } copy(command[:], []byte(cmd)) @@ -171,7 +186,7 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro var bw bytes.Buffer err := msg.BtcEncode(&bw, pver) if err != nil { - return err + return totalBytes, err } payload := bw.Bytes() lenp := len(payload) @@ -181,7 +196,7 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro str := fmt.Sprintf("message payload is too large - encoded "+ "%d bytes, but maximum message payload is %d bytes", lenp, maxMessagePayload) - return messageError("WriteMessage", str) + return totalBytes, messageError("WriteMessage", str) } // Enforce maximum message payload based on the message type. @@ -190,7 +205,7 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro str := fmt.Sprintf("message payload is too large - encoded "+ "%d bytes, but maximum message payload size for "+ "messages of type [%s] is %d.", lenp, cmd, mpl) - return messageError("WriteMessage", str) + return totalBytes, messageError("WriteMessage", str) } // Create header for the message. @@ -200,34 +215,61 @@ func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) erro hdr.length = uint32(lenp) copy(hdr.checksum[:], DoubleSha256(payload)[0:4]) + // Encode the header for the message. This is done to a buffer + // rather than directly to the writer since writeElements doesn't + // return the number of bytes written. + var hw bytes.Buffer + writeElements(&hw, hdr.magic, command, hdr.length, hdr.checksum) + // Write header. - err = writeElements(w, hdr.magic, command, hdr.length, hdr.checksum) + n, err := w.Write(hw.Bytes()) if err != nil { - return err + totalBytes += n + return totalBytes, err } + totalBytes += n // Write payload. - _, err = w.Write(payload) + n, err = w.Write(payload) if err != nil { - return err + totalBytes += n + return totalBytes, err } - return nil + totalBytes += n + + return totalBytes, nil } -// ReadMessage reads, validates, and parses the next bitcoin Message from r for -// the provided protocol version and bitcoin network. -func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, error) { - hdr, err := readMessageHeader(r) +// WriteMessage writes a bitcoin Message to w including the necessary header +// information. This function is the same as WriteMessageN except it doesn't +// doesn't return the number of bytes written. This function is mainly provided +// for backwards compatibility with the original API, but it's also useful for +// callers that don't care about byte counts. +func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) error { + _, err := WriteMessageN(w, msg, pver, btcnet) + return err +} + +// ReadMessageN reads, validates, and parses the next bitcoin Message from r for +// the provided protocol version and bitcoin network. It returns the number of +// bytes read in addition to the parsed Message and raw bytes which comprise the +// message. This function is the same as ReadMessage except it also returns the +// number of bytes read. +func ReadMessageN(r io.Reader, pver uint32, btcnet BitcoinNet) (int, Message, []byte, error) { + totalBytes := 0 + n, hdr, err := readMessageHeader(r) if err != nil { - return nil, nil, err + totalBytes += n + return totalBytes, nil, nil, err } + totalBytes += n // Enforce maximum message payload. if hdr.length > maxMessagePayload { str := fmt.Sprintf("message payload is too large - header "+ "indicates %d bytes, but max message payload is %d "+ "bytes.", hdr.length, maxMessagePayload) - return nil, nil, messageError("ReadMessage", str) + return totalBytes, nil, nil, messageError("ReadMessage", str) } @@ -235,7 +277,7 @@ func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, if hdr.magic != btcnet { discardInput(r, hdr.length) str := fmt.Sprintf("message from other network [%v]", hdr.magic) - return nil, nil, messageError("ReadMessage", str) + return totalBytes, nil, nil, messageError("ReadMessage", str) } // Check for malformed commands. @@ -243,14 +285,15 @@ func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, if !utf8.ValidString(command) { discardInput(r, hdr.length) str := fmt.Sprintf("invalid command %v", []byte(command)) - return nil, nil, messageError("ReadMessage", str) + return totalBytes, nil, nil, messageError("ReadMessage", str) } // Create struct of appropriate message type based on the command. msg, err := makeEmptyMessage(command) if err != nil { discardInput(r, hdr.length) - return nil, nil, messageError("ReadMessage", err.Error()) + return totalBytes, nil, nil, messageError("ReadMessage", + err.Error()) } // Check for maximum length based on the message type as a malicious client @@ -262,15 +305,17 @@ func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, str := fmt.Sprintf("payload exceeds max length - header "+ "indicates %v bytes, but max payload size for "+ "messages of type [%v] is %v.", hdr.length, command, mpl) - return nil, nil, messageError("ReadMessage", str) + return totalBytes, nil, nil, messageError("ReadMessage", str) } // Read payload. payload := make([]byte, hdr.length) - _, err = io.ReadFull(r, payload) + n, err = io.ReadFull(r, payload) if err != nil { - return nil, nil, err + totalBytes += n + return totalBytes, nil, nil, err } + totalBytes += n // Test checksum. checksum := DoubleSha256(payload)[0:4] @@ -278,15 +323,26 @@ func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, str := fmt.Sprintf("payload checksum failed - header "+ "indicates %v, but actual checksum is %v.", hdr.checksum, checksum) - return nil, nil, messageError("ReadMessage", str) + return totalBytes, nil, nil, messageError("ReadMessage", str) } // Unmarshal message. pr := bytes.NewBuffer(payload) err = msg.BtcDecode(pr, pver) if err != nil { - return nil, nil, err + return totalBytes, nil, nil, err } - return msg, payload, nil + return totalBytes, msg, payload, nil +} + +// ReadMessage reads, validates, and parses the next bitcoin Message from r for +// the provided protocol version and bitcoin network. It returns the parsed +// Message and raw bytes which comprise the message. This function only differs +// from ReadMessageN in that it doesn't return the number of bytes read. This +// function is mainly provided for backwards compatibility with the original +// API, but it's also useful for callers that don't care about byte counts. +func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, error) { + _, msg, buf, err := ReadMessageN(r, pver, btcnet) + return msg, buf, err } diff --git a/message_test.go b/message_test.go index be29e7ef..ba542891 100644 --- a/message_test.go +++ b/message_test.go @@ -32,7 +32,7 @@ func makeHeader(btcnet btcwire.BitcoinNet, command string, return buf } -// TestMessage tests the Read/WriteMessage API. +// TestMessage tests the Read/WriteMessage and Read/WriteMessageN API. func TestMessage(t *testing.T) { pver := btcwire.ProtocolVersion @@ -74,25 +74,65 @@ func TestMessage(t *testing.T) { out btcwire.Message // Expected decoded value pver uint32 // Protocol version for wire encoding btcnet btcwire.BitcoinNet // Network to use for wire encoding + bytes int // Expected num bytes read/written }{ - {msgVersion, msgVersion, pver, btcwire.MainNet}, - {msgVerack, msgVerack, pver, btcwire.MainNet}, - {msgGetAddr, msgGetAddr, pver, btcwire.MainNet}, - {msgAddr, msgAddr, pver, btcwire.MainNet}, - {msgGetBlocks, msgGetBlocks, pver, btcwire.MainNet}, - {msgBlock, msgBlock, pver, btcwire.MainNet}, - {msgInv, msgInv, pver, btcwire.MainNet}, - {msgGetData, msgGetData, pver, btcwire.MainNet}, - {msgNotFound, msgNotFound, pver, btcwire.MainNet}, - {msgTx, msgTx, pver, btcwire.MainNet}, - {msgPing, msgPing, pver, btcwire.MainNet}, - {msgPong, msgPong, pver, btcwire.MainNet}, - {msgGetHeaders, msgGetHeaders, pver, btcwire.MainNet}, - {msgHeaders, msgHeaders, pver, btcwire.MainNet}, - {msgAlert, msgAlert, pver, btcwire.MainNet}, - {msgMemPool, msgMemPool, pver, btcwire.MainNet}, + {msgVersion, msgVersion, pver, btcwire.MainNet, 121}, + {msgVerack, msgVerack, pver, btcwire.MainNet, 24}, + {msgGetAddr, msgGetAddr, pver, btcwire.MainNet, 24}, + {msgAddr, msgAddr, pver, btcwire.MainNet, 25}, + {msgGetBlocks, msgGetBlocks, pver, btcwire.MainNet, 61}, + {msgBlock, msgBlock, pver, btcwire.MainNet, 239}, + {msgInv, msgInv, pver, btcwire.MainNet, 25}, + {msgGetData, msgGetData, pver, btcwire.MainNet, 25}, + {msgNotFound, msgNotFound, pver, btcwire.MainNet, 25}, + {msgTx, msgTx, pver, btcwire.MainNet, 34}, + {msgPing, msgPing, pver, btcwire.MainNet, 32}, + {msgPong, msgPong, pver, btcwire.MainNet, 32}, + {msgGetHeaders, msgGetHeaders, pver, btcwire.MainNet, 61}, + {msgHeaders, msgHeaders, pver, btcwire.MainNet, 25}, + {msgAlert, msgAlert, pver, btcwire.MainNet, 42}, + {msgMemPool, msgMemPool, pver, btcwire.MainNet, 24}, } + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Encode to wire format. + var buf bytes.Buffer + nw, err := btcwire.WriteMessageN(&buf, test.in, test.pver, test.btcnet) + if err != nil { + t.Errorf("WriteMessage #%d error %v", i, err) + continue + } + + // Ensure the number of bytes written match the expected value. + if nw != test.bytes { + t.Errorf("WriteMessage #%d unexpected num bytes "+ + "written - got %d, want %d", i, nw, test.bytes) + } + + // Decode from wire format. + rbuf := bytes.NewBuffer(buf.Bytes()) + nr, msg, _, err := btcwire.ReadMessageN(rbuf, test.pver, test.btcnet) + if err != nil { + t.Errorf("ReadMessage #%d error %v, msg %v", i, err, + spew.Sdump(msg)) + continue + } + if !reflect.DeepEqual(msg, test.out) { + t.Errorf("ReadMessage #%d\n got: %v want: %v", i, + spew.Sdump(msg), spew.Sdump(test.out)) + continue + } + + // Ensure the number of bytes read match the expected value. + if nr != test.bytes { + t.Errorf("ReadMessage #%d unexpected num bytes read - "+ + "got %d, want %d", i, nr, test.bytes) + } + } + + // Do the same thing for Read/WriteMessage, but ignore the bytes since + // they don't return them. t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Encode to wire format. @@ -186,6 +226,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet btcwire.BitcoinNet // Bitcoin network for wire encoding max int // Max size of fixed buffer to induce errors readErr error // Expected read error + bytes int // Expected num bytes read }{ // Latest protocol version with intentional read errors. @@ -196,6 +237,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet, 0, io.EOF, + 0, }, // Wrong network. Want MainNet, but giving TestNet3. @@ -205,6 +247,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet, len(testNet3Bytes), &btcwire.MessageError{}, + 24, }, // Exceed max overall message payload length. @@ -214,6 +257,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet, len(exceedMaxPayloadBytes), &btcwire.MessageError{}, + 24, }, // Invalid UTF-8 command. @@ -223,6 +267,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet, len(badCommandBytes), &btcwire.MessageError{}, + 24, }, // Valid, but unsupported command. @@ -232,6 +277,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet, len(unsupportedCommandBytes), &btcwire.MessageError{}, + 24, }, // Exceed max allowed payload for a message of a specific type. @@ -241,6 +287,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet, len(exceedTypePayloadBytes), &btcwire.MessageError{}, + 24, }, // Message with a payload shorter than the header indicates. @@ -250,6 +297,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet, len(shortPayloadBytes), io.EOF, + 24, }, // Message with a bad checksum. @@ -259,6 +307,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet, len(badChecksumBytes), &btcwire.MessageError{}, + 26, }, // Message with a valid header, but wrong format. @@ -268,6 +317,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet, len(badMessageBytes), io.EOF, + 25, }, // 15k bytes of data to discard. @@ -277,6 +327,7 @@ func TestReadMessageWireErrors(t *testing.T) { btcnet, len(discardBytes), &btcwire.MessageError{}, + 24, }, } @@ -284,13 +335,19 @@ func TestReadMessageWireErrors(t *testing.T) { for i, test := range tests { // Decode from wire format. r := newFixedReader(test.max, test.buf) - _, _, err := btcwire.ReadMessage(r, test.pver, test.btcnet) + nr, _, _, err := btcwire.ReadMessageN(r, test.pver, test.btcnet) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { t.Errorf("ReadMessage #%d wrong error got: %v <%T>, "+ "want: %T", i, err, err, test.readErr) continue } + // Ensure the number of bytes written match the expected value. + if nr != test.bytes { + t.Errorf("ReadMessage #%d unexpected num bytes read - "+ + "got %d, want %d", i, nr, test.bytes) + } + // For errors which are not of type btcwire.MessageError, check // them for equality. if _, ok := err.(*btcwire.MessageError); !ok { @@ -336,32 +393,39 @@ func TestWriteMessageWireErrors(t *testing.T) { btcnet btcwire.BitcoinNet // Bitcoin network for wire encoding max int // Max size of fixed buffer to induce errors err error // Expected error + bytes int // Expected num bytes written }{ // Command too long. - {badCommandMsg, pver, btcnet, 0, btcwireErr}, + {badCommandMsg, pver, btcnet, 0, btcwireErr, 0}, // Force error in payload encode. - {encodeErrMsg, pver, btcnet, 0, btcwireErr}, + {encodeErrMsg, pver, btcnet, 0, btcwireErr, 0}, // Force error due to exceeding max overall message payload size. - {exceedOverallPayloadErrMsg, pver, btcnet, 0, btcwireErr}, + {exceedOverallPayloadErrMsg, pver, btcnet, 0, btcwireErr, 0}, // Force error due to exceeding max payload for message type. - {exceedPayloadErrMsg, pver, btcnet, 0, btcwireErr}, + {exceedPayloadErrMsg, pver, btcnet, 0, btcwireErr, 0}, // Force error in header write. - {bogusMsg, pver, btcnet, 0, io.ErrShortWrite}, + {bogusMsg, pver, btcnet, 0, io.ErrShortWrite, 0}, // Force error in payload write. - {bogusMsg, pver, btcnet, 24, io.ErrShortWrite}, + {bogusMsg, pver, btcnet, 24, io.ErrShortWrite, 24}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Encode wire format. w := newFixedWriter(test.max) - err := btcwire.WriteMessage(w, test.msg, test.pver, test.btcnet) + nw, err := btcwire.WriteMessageN(w, test.msg, test.pver, test.btcnet) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("WriteMessage #%d wrong error got: %v <%T>, "+ "want: %T", i, err, err, test.err) continue } + // Ensure the number of bytes written match the expected value. + if nw != test.bytes { + t.Errorf("WriteMessage #%d unexpected num bytes "+ + "written - got %d, want %d", i, nw, test.bytes) + } + // For errors which are not of type btcwire.MessageError, check // them for equality. if _, ok := err.(*btcwire.MessageError); !ok { diff --git a/test_coverage.txt b/test_coverage.txt index 0df2bc76..6b9fac8b 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,111 +1,107 @@ -github.com/conformal/btcwire/common.go readElement 100.00% (61/61) github.com/conformal/btcwire/common.go writeElement 100.00% (61/61) -github.com/conformal/btcwire/message.go ReadMessage 100.00% (37/37) +github.com/conformal/btcwire/common.go readElement 100.00% (61/61) +github.com/conformal/btcwire/message.go ReadMessageN 100.00% (42/42) +github.com/conformal/btcwire/message.go WriteMessageN 100.00% (38/38) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (36/36) -github.com/conformal/btcwire/message.go WriteMessage 100.00% (31/31) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (26/26) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) -github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (22/22) +github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) +github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (21/21) github.com/conformal/btcwire/common.go readVarInt 100.00% (21/21) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) -github.com/conformal/btcwire/common.go writeVarInt 100.00% (20/20) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) -github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) -github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (19/19) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) +github.com/conformal/btcwire/common.go writeVarInt 100.00% (20/20) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (20/20) +github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (17/17) github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (17/17) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (17/17) github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (16/16) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (15/15) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) +github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (13/13) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) +github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) +github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (11/11) github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (10/10) -github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (9/9) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (9/9) +github.com/conformal/btcwire/message.go readMessageHeader 100.00% (10/10) github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (9/9) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) +github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (9/9) github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (8/8) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) +github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) +github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) +github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (6/6) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) +github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/common.go readElements 100.00% (5/5) +github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) +github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) +github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) +github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) +github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) +github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) +github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) +github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) +github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/msggetdata.go NewMsgGetDataSizeHint 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/msginv.go NewMsgInvSizeHint 100.00% (3/3) +github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) +github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) +github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) +github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) +github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) github.com/conformal/btcwire/protocol.go BitcoinNet.String 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) +github.com/conformal/btcwire/msggetdata.go NewMsgGetDataSizeHint 100.00% (3/3) +github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) +github.com/conformal/btcwire/msginv.go NewMsgInvSizeHint 100.00% (3/3) +github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) +github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) +github.com/conformal/btcwire/message.go ReadMessage 100.00% (2/2) +github.com/conformal/btcwire/message.go WriteMessage 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) +github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (2/2) github.com/conformal/btcwire/netaddress.go NewNetAddressIPPort 100.00% (2/2) -github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (2/2) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) -github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) github.com/conformal/btcwire/msgping.go NewMsgPing 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) github.com/conformal/btcwire/msgpong.go MsgPong.Command 100.00% (1/1) -github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) github.com/conformal/btcwire/msgpong.go NewMsgPong 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewOutPoint 100.00% (1/1) github.com/conformal/btcwire/msgtx.go TxIn.SerializeSize 100.00% (1/1) @@ -114,52 +110,60 @@ github.com/conformal/btcwire/msgtx.go TxOut.SerializeSize 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewTxOut 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxIn 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.AddTxOut 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Deserialize 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Serialize 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.Command 100.00% (1/1) github.com/conformal/btcwire/msgtx.go MsgTx.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgtx.go NewMsgTx 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) +github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) +github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcDecode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.AddService 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/error.go messageError 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) -github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) +github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) -github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) -github.com/conformal/btcwire/error.go messageError 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) +github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) +github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) +github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) +github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) +github.com/conformal/btcwire/blockheader.go BlockHeader.Serialize 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) +github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) +github.com/conformal/btcwire/blockheader.go BlockHeader.Deserialize 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) +github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) +github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (1132/1132) +github.com/conformal/btcwire --------------------------------- 100.00% (1153/1153) From d0dfff8292cd09e85db4ff5da0732115ff93f1a8 Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 4 Feb 2014 14:35:38 -0500 Subject: [PATCH 156/219] fix typo in test: use %s for strings --- common_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common_test.go b/common_test.go index c5ca0291..f75ad8c6 100644 --- a/common_test.go +++ b/common_test.go @@ -406,7 +406,7 @@ func TestVarStringWire(t *testing.T) { continue } if val != test.out { - t.Errorf("readVarString #%d\n got: %d want: %d", i, + t.Errorf("readVarString #%d\n got: %s want: %s", i, val, test.out) continue } From f6b03bf8a8308837a5663e537be297956279dd67 Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 4 Feb 2014 16:14:08 -0500 Subject: [PATCH 157/219] gofmt --- genesis.go | 4 ++-- msgblock_test.go | 8 ++++---- msgtx_test.go | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/genesis.go b/genesis.go index 3ec7b63f..adbfbb0b 100644 --- a/genesis.go +++ b/genesis.go @@ -13,7 +13,7 @@ import ( var genesisCoinbaseTx = MsgTx{ Version: 1, TxIn: []*TxIn{ - &TxIn{ + { PreviousOutpoint: OutPoint{ Hash: ShaHash{}, Index: 0xffffffff, @@ -34,7 +34,7 @@ var genesisCoinbaseTx = MsgTx{ }, }, TxOut: []*TxOut{ - &TxOut{ + { Value: 0x12a05f200, PkScript: []byte{ 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ diff --git a/msgblock_test.go b/msgblock_test.go index ae252436..c736e6ce 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -470,10 +470,10 @@ var blockOne = btcwire.MsgBlock{ Nonce: 0x9962e301, // 2573394689 }, Transactions: []*btcwire.MsgTx{ - &btcwire.MsgTx{ + { Version: 1, TxIn: []*btcwire.TxIn{ - &btcwire.TxIn{ + { PreviousOutpoint: btcwire.OutPoint{ Hash: btcwire.ShaHash{}, Index: 0xffffffff, @@ -485,7 +485,7 @@ var blockOne = btcwire.MsgBlock{ }, }, TxOut: []*btcwire.TxOut{ - &btcwire.TxOut{ + { Value: 0x12a05f200, PkScript: []byte{ 0x41, // OP_DATA_65 @@ -551,5 +551,5 @@ var blockOneBytes = []byte{ // Transaction location information for block one transactions. var blockOneTxLocs = []btcwire.TxLoc{ - btcwire.TxLoc{TxStart: 81, TxLen: 134}, + {TxStart: 81, TxLen: 134}, } diff --git a/msgtx_test.go b/msgtx_test.go index 47b1f1d9..5688baa2 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -620,7 +620,7 @@ func TestTxSerializeSize(t *testing.T) { var multiTx = &btcwire.MsgTx{ Version: 1, TxIn: []*btcwire.TxIn{ - &btcwire.TxIn{ + { PreviousOutpoint: btcwire.OutPoint{ Hash: btcwire.ShaHash{}, Index: 0xffffffff, @@ -632,7 +632,7 @@ var multiTx = &btcwire.MsgTx{ }, }, TxOut: []*btcwire.TxOut{ - &btcwire.TxOut{ + { Value: 0x12a05f200, PkScript: []byte{ 0x41, // OP_DATA_65 From 13e0b0e7b9b6cf79e7b14d2adee40a2f52437150 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 24 Feb 2014 09:53:31 -0600 Subject: [PATCH 158/219] Limit generated timestamps to one second precision. This commit changes all cases which generate default timestamps to time.Now to limit the timestamp to one second precision. The code which serializes and deserializes timestamps already does this, but it is useful to make sure defaults don't exceed the precision of the protocol either. With this change there is less chance that developers using defaults will end up with structures that have a higher time precision than what will ultimately be sent across the wire. --- blockheader.go | 4 +++- msgversion.go | 2 +- netaddress.go | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/blockheader.go b/blockheader.go index 9eb643e6..d04d83b3 100644 --- a/blockheader.go +++ b/blockheader.go @@ -89,11 +89,13 @@ func (h *BlockHeader) Serialize(w io.Writer) error { func NewBlockHeader(prevHash *ShaHash, merkleRootHash *ShaHash, bits uint32, nonce uint32) *BlockHeader { + // Limit the timestamp to one second precision since the protocol + // doesn't support better. return &BlockHeader{ Version: BlockVersion, PrevBlock: *prevHash, MerkleRoot: *merkleRootHash, - Timestamp: time.Now(), + Timestamp: time.Unix(time.Now().Unix(), 0), Bits: bits, Nonce: nonce, } diff --git a/msgversion.go b/msgversion.go index c8ac391b..6b215759 100644 --- a/msgversion.go +++ b/msgversion.go @@ -176,7 +176,7 @@ func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 { func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64, userAgent string, lastBlock int32) *MsgVersion { - // Limit the Timestamp to millisecond precision since the protocol + // Limit the timestamp to one second precision since the protocol // doesn't support better. return &MsgVersion{ ProtocolVersion: int32(ProtocolVersion), diff --git a/netaddress.go b/netaddress.go index 8d060f8e..f4017111 100644 --- a/netaddress.go +++ b/netaddress.go @@ -75,8 +75,10 @@ func (na *NetAddress) SetAddress(ip net.IP, port uint16) { // NewNetAddressIPPort returns a new NetAddress using the provided IP, port, and // supported services with defaults for the remaining fields. func NewNetAddressIPPort(ip net.IP, port uint16, services ServiceFlag) *NetAddress { + // Limit the timestamp to one second precision since the protocol + // doesn't support better. na := NetAddress{ - Timestamp: time.Now(), + Timestamp: time.Unix(time.Now().Unix(), 0), Services: services, IP: ip, Port: port, From 1623818c1201d7333118695fa0824ec004db7644 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 25 Feb 2014 16:00:03 -0600 Subject: [PATCH 159/219] Export a new constant for MaxPrevOutIndex. This commit exports a new constant for the maximum index a previous outpoint can contain. --- msgtx.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/msgtx.go b/msgtx.go index c5cc93d2..dc6f59e0 100644 --- a/msgtx.go +++ b/msgtx.go @@ -11,12 +11,18 @@ import ( "io" ) -// TxVersion is the current latest supported transaction version. -const TxVersion = 1 +const ( + // TxVersion is the current latest supported transaction version. + TxVersion = 1 -// MaxTxInSequenceNum is the maximum sequence number the sequence field -// of a transaction input can be. -const MaxTxInSequenceNum uint32 = 0xffffffff + // MaxTxInSequenceNum is the maximum sequence number the sequence field + // of a transaction input can be. + MaxTxInSequenceNum uint32 = 0xffffffff + + // MaxPrevOutIndex is the maximum index the index field of a previous + // outpoint can be. + MaxPrevOutIndex uint32 = 0xffffffff +) // defaultTxInOutAlloc is the default size used for the backing array for // transaction inputs and outputs. The array will dynamically grow as needed, From b9c21bd5186a3ba654eafce7315419ba1cdd2ed0 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 3 Mar 2014 18:43:09 -0600 Subject: [PATCH 160/219] Export VarIntSerializeSize function. This commit exports the VarIntSerializeSize function to provide callers with an easy method to determine how many bytes it would take to serialize the passed value as a variable length integer. --- common.go | 4 ++-- common_test.go | 4 ++-- internal_test.go | 6 ------ msgtx.go | 8 ++++---- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/common.go b/common.go index ef47f7ac..375bff0a 100644 --- a/common.go +++ b/common.go @@ -325,9 +325,9 @@ func writeVarInt(w io.Writer, pver uint32, val uint64) error { return err } -// varIntSerializeSize returns the number of bytes it would take to serialize +// VarIntSerializeSize returns the number of bytes it would take to serialize // val as a variable length integer. -func varIntSerializeSize(val uint64) int { +func VarIntSerializeSize(val uint64) int { // The value is small enough to be represented by itself, so it's // just 1 byte. if val < 0xfd { diff --git a/common_test.go b/common_test.go index f75ad8c6..d27f41a3 100644 --- a/common_test.go +++ b/common_test.go @@ -352,9 +352,9 @@ func TestVarIntSerializeSize(t *testing.T) { t.Logf("Running %d tests", len(tests)) for i, test := range tests { - serializedSize := btcwire.TstVarIntSerializeSize(test.val) + serializedSize := btcwire.VarIntSerializeSize(test.val) if serializedSize != test.size { - t.Errorf("varIntSerializeSize #%d got: %d, want: %d", i, + t.Errorf("VarIntSerializeSize #%d got: %d, want: %d", i, serializedSize, test.size) continue } diff --git a/internal_test.go b/internal_test.go index c2fce9c5..2bb0c380 100644 --- a/internal_test.go +++ b/internal_test.go @@ -53,12 +53,6 @@ func TstWriteVarInt(w io.Writer, pver uint32, val uint64) error { return writeVarInt(w, pver, val) } -// TstVarIntSerializeSize makes the internal varIntSerializeSize function -// available to the test package. -func TstVarIntSerializeSize(val uint64) int { - return varIntSerializeSize(val) -} - // TstReadVarString makes the internal readVarString function available to the // test package. func TstReadVarString(r io.Reader, pver uint32) (string, error) { diff --git a/msgtx.go b/msgtx.go index dc6f59e0..f7cd87d0 100644 --- a/msgtx.go +++ b/msgtx.go @@ -88,7 +88,7 @@ func (t *TxIn) SerializeSize() int { // Outpoint Hash 32 bytes + Outpoint Index 4 bytes + Sequence 4 bytes + // serialized varint size for the length of SignatureScript + // SignatureScript bytes. - return 40 + varIntSerializeSize(uint64(len(t.SignatureScript))) + + return 40 + VarIntSerializeSize(uint64(len(t.SignatureScript))) + len(t.SignatureScript) } @@ -114,7 +114,7 @@ type TxOut struct { func (t *TxOut) SerializeSize() int { // Value 8 bytes + serialized varint size for the length of PkScript + // PkScript bytes. - return 8 + varIntSerializeSize(uint64(len(t.PkScript))) + len(t.PkScript) + return 8 + VarIntSerializeSize(uint64(len(t.PkScript))) + len(t.PkScript) } // NewTxOut returns a new bitcoin transaction output with the provided @@ -388,8 +388,8 @@ func (msg *MsgTx) Serialize(w io.Writer) error { func (msg *MsgTx) SerializeSize() int { // Version 4 bytes + LockTime 4 bytes + Serialized varint size for the // number of transaction inputs and outputs. - n := 8 + varIntSerializeSize(uint64(len(msg.TxIn))) + - varIntSerializeSize(uint64(len(msg.TxOut))) + n := 8 + VarIntSerializeSize(uint64(len(msg.TxIn))) + + VarIntSerializeSize(uint64(len(msg.TxOut))) for _, txIn := range msg.TxIn { n += txIn.SerializeSize() From e5d15b0fa8a1e311fef6925502761c9f27bf292d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 11 Mar 2014 20:09:55 -0500 Subject: [PATCH 161/219] Export MaxVarIntPayload. --- common.go | 2 +- msgaddr.go | 4 ++-- msggetblocks.go | 2 +- msggetdata.go | 2 +- msggetheaders.go | 2 +- msgheaders.go | 2 +- msginv.go | 2 +- msgnotfound.go | 2 +- msgversion.go | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common.go b/common.go index 375bff0a..e8f34f4f 100644 --- a/common.go +++ b/common.go @@ -14,7 +14,7 @@ import ( ) // Maximum payload size for a variable length integer. -const maxVarIntPayload = 9 +const MaxVarIntPayload = 9 // readElement reads the next sequence of bytes from r using little endian // depending on the concrete type of element pointed to. diff --git a/msgaddr.go b/msgaddr.go index 800e65fa..678de22d 100644 --- a/msgaddr.go +++ b/msgaddr.go @@ -126,11 +126,11 @@ func (msg *MsgAddr) Command() string { func (msg *MsgAddr) MaxPayloadLength(pver uint32) uint32 { if pver < MultipleAddressVersion { // Num addresses (varInt) + a single net addresses. - return maxVarIntPayload + maxNetAddressPayload(pver) + return MaxVarIntPayload + maxNetAddressPayload(pver) } // Num addresses (varInt) + max allowed addresses. - return maxVarIntPayload + (MaxAddrPerMsg * maxNetAddressPayload(pver)) + return MaxVarIntPayload + (MaxAddrPerMsg * maxNetAddressPayload(pver)) } // NewMsgAddr returns a new bitcoin addr message that conforms to the diff --git a/msggetblocks.go b/msggetblocks.go index 1996ae44..45ec0d47 100644 --- a/msggetblocks.go +++ b/msggetblocks.go @@ -129,7 +129,7 @@ func (msg *MsgGetBlocks) Command() string { func (msg *MsgGetBlocks) MaxPayloadLength(pver uint32) uint32 { // Protocol version 4 bytes + num hashes (varInt) + max block locator // hashes + hash stop. - return 4 + maxVarIntPayload + (MaxBlockLocatorsPerMsg * HashSize) + HashSize + return 4 + MaxVarIntPayload + (MaxBlockLocatorsPerMsg * HashSize) + HashSize } // NewMsgGetBlocks returns a new bitcoin getblocks message that conforms to the diff --git a/msggetdata.go b/msggetdata.go index a7494f70..3add4782 100644 --- a/msggetdata.go +++ b/msggetdata.go @@ -97,7 +97,7 @@ func (msg *MsgGetData) Command() string { // receiver. This is part of the Message interface implementation. func (msg *MsgGetData) MaxPayloadLength(pver uint32) uint32 { // Num inventory vectors (varInt) + max allowed inventory vectors. - return maxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload) + return MaxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload) } // NewMsgGetData returns a new bitcoin getdata message that conforms to the diff --git a/msggetheaders.go b/msggetheaders.go index bbd6cc17..607fba49 100644 --- a/msggetheaders.go +++ b/msggetheaders.go @@ -127,7 +127,7 @@ func (msg *MsgGetHeaders) Command() string { func (msg *MsgGetHeaders) MaxPayloadLength(pver uint32) uint32 { // Version 4 bytes + num block locator hashes (varInt) + max allowed block // locators + hash stop. - return 4 + maxVarIntPayload + (MaxBlockLocatorsPerMsg * HashSize) + HashSize + return 4 + MaxVarIntPayload + (MaxBlockLocatorsPerMsg * HashSize) + HashSize } // NewMsgGetHeaders returns a new bitcoin getheaders message that conforms to diff --git a/msgheaders.go b/msgheaders.go index a9f5fe07..fdb3d5d4 100644 --- a/msgheaders.go +++ b/msgheaders.go @@ -121,7 +121,7 @@ func (msg *MsgHeaders) Command() string { func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 { // Num headers (varInt) + max allowed headers (header length + 1 byte // for the number of transactions which is always 0). - return maxVarIntPayload + ((maxBlockHeaderPayload + 1) * + return MaxVarIntPayload + ((maxBlockHeaderPayload + 1) * MaxBlockHeadersPerMsg) } diff --git a/msginv.go b/msginv.go index 594bda0d..55ca11ca 100644 --- a/msginv.go +++ b/msginv.go @@ -105,7 +105,7 @@ func (msg *MsgInv) Command() string { // receiver. This is part of the Message interface implementation. func (msg *MsgInv) MaxPayloadLength(pver uint32) uint32 { // Num inventory vectors (varInt) + max allowed inventory vectors. - return maxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload) + return MaxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload) } // NewMsgInv returns a new bitcoin inv message that conforms to the Message diff --git a/msgnotfound.go b/msgnotfound.go index 47188299..fa439f55 100644 --- a/msgnotfound.go +++ b/msgnotfound.go @@ -95,7 +95,7 @@ func (msg *MsgNotFound) Command() string { func (msg *MsgNotFound) MaxPayloadLength(pver uint32) uint32 { // Max var int 9 bytes + max InvVects at 36 bytes each. // Num inventory vectors (varInt) + max allowed inventory vectors. - return maxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload) + return MaxVarIntPayload + (MaxInvPerMsg * maxInvVectPayload) } // NewMsgNotFound returns a new bitcoin notfound message that conforms to the diff --git a/msgversion.go b/msgversion.go index 6b215759..0fc18b3f 100644 --- a/msgversion.go +++ b/msgversion.go @@ -167,7 +167,7 @@ func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 { // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + remote // and local net addresses + nonce 8 bytes + length of user agent (varInt) + // max allowed useragent length + last block 4 bytes. - return 32 + (maxNetAddressPayload(pver) * 2) + maxVarIntPayload + MaxUserAgentLen + return 32 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload + MaxUserAgentLen } // NewMsgVersion returns a new bitcoin version message that conforms to the From 0e1f6a6628100803b2e0e0e7e14da1a74e688bf3 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 11 Mar 2014 20:22:32 -0500 Subject: [PATCH 162/219] Export MaxBlockHeaderPayload. --- blockheader.go | 2 +- msgheaders.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blockheader.go b/blockheader.go index d04d83b3..d9ed680a 100644 --- a/blockheader.go +++ b/blockheader.go @@ -15,7 +15,7 @@ const BlockVersion uint32 = 2 // Version 4 bytes + Timestamp 4 bytes + Bits 4 bytes + Nonce 4 bytes + // PrevBlock and MerkleRoot hashes. -const maxBlockHeaderPayload = 16 + (HashSize * 2) +const MaxBlockHeaderPayload = 16 + (HashSize * 2) // BlockHeader defines information about a block and is used in the bitcoin // block (MsgBlock) and headers (MsgHeaders) messages. diff --git a/msgheaders.go b/msgheaders.go index fdb3d5d4..b4a44426 100644 --- a/msgheaders.go +++ b/msgheaders.go @@ -121,7 +121,7 @@ func (msg *MsgHeaders) Command() string { func (msg *MsgHeaders) MaxPayloadLength(pver uint32) uint32 { // Num headers (varInt) + max allowed headers (header length + 1 byte // for the number of transactions which is always 0). - return MaxVarIntPayload + ((maxBlockHeaderPayload + 1) * + return MaxVarIntPayload + ((MaxBlockHeaderPayload + 1) * MaxBlockHeadersPerMsg) } From 2de1b73d122516c0c194698328e4f3fb7d87382d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 20 Mar 2014 10:46:03 -0500 Subject: [PATCH 163/219] Add a benchmark for TxSha. This commit adds a benchmark for the TxSha function of a MsgTx. --- bench_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bench_test.go b/bench_test.go index d127c328..dda4fb14 100644 --- a/bench_test.go +++ b/bench_test.go @@ -281,3 +281,12 @@ func BenchmarkWriteBlockHeader(b *testing.B) { btcwire.TstWriteBlockHeader(ioutil.Discard, 0, &header) } } + +// BenchmarkTxSha performs a benchmark on how long it takes to hash a +// transaction. +func BenchmarkTxSha(b *testing.B) { + tx := btcwire.GenesisBlock.Transactions[0] + for i := 0; i < b.N; i++ { + tx.TxSha() + } +} From b6e6fc25dbb8bb1a820ddf22ef0e9aead704de1a Mon Sep 17 00:00:00 2001 From: David Hill Date: Thu, 20 Mar 2014 13:14:38 -0400 Subject: [PATCH 164/219] Preallocate memory for the message header in WriteMessageN and the serialization buffer in MsgTx's TxSha(). Benchmarking shows this is slightly faster due to avoiding the extra garbage collection in addition to less peak memory usage. Before: BenchmarkTxShaOld 500000 5626 ns/op After: BenchmarkTxShaNew 500000 5457 ns/op --- message.go | 4 ++-- msgtx.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/message.go b/message.go index 98561734..83f51e6f 100644 --- a/message.go +++ b/message.go @@ -218,8 +218,8 @@ func WriteMessageN(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) (in // Encode the header for the message. This is done to a buffer // rather than directly to the writer since writeElements doesn't // return the number of bytes written. - var hw bytes.Buffer - writeElements(&hw, hdr.magic, command, hdr.length, hdr.checksum) + hw := bytes.NewBuffer(make([]byte, 0, MessageHeaderSize)) + writeElements(hw, hdr.magic, command, hdr.length, hdr.checksum) // Write header. n, err := w.Write(hw.Bytes()) diff --git a/msgtx.go b/msgtx.go index f7cd87d0..61b77c99 100644 --- a/msgtx.go +++ b/msgtx.go @@ -157,9 +157,9 @@ func (msg *MsgTx) TxSha() (ShaHash, error) { // cause a run-time panic. Also, SetBytes can't fail here due to the // fact DoubleSha256 always returns a []byte of the right size // regardless of input. - var buf bytes.Buffer + buf := bytes.NewBuffer(make([]byte, 0, msg.SerializeSize())) + _ = msg.Serialize(buf) var sha ShaHash - _ = msg.Serialize(&buf) _ = sha.SetBytes(DoubleSha256(buf.Bytes())) // Even though this function can't currently fail, it still returns From dfb2c149f6806408cb4a43cd59792cf775b4ffab Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 30 Mar 2014 12:19:17 -0500 Subject: [PATCH 165/219] Finish uncompleted comments in fixedIO_test.go. --- fixedIO_test.go | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/fixedIO_test.go b/fixedIO_test.go index 139b248a..3bb834bb 100644 --- a/fixedIO_test.go +++ b/fixedIO_test.go @@ -16,7 +16,11 @@ type fixedWriter struct { pos int } -// Write ... +// Write writes the contents of p to w. When the contents of p would cause +// the writer to exceed the maximum allowed size of the fixed writer, +// io.ErrShortWrite is returned and the writer is left unchanged. +// +// This satisfies the io.Writer interface. func (w *fixedWriter) Write(p []byte) (n int, err error) { lenp := len(p) if w.pos+lenp > cap(w.b) { @@ -27,13 +31,14 @@ func (w *fixedWriter) Write(p []byte) (n int, err error) { return } -// Bytes ... +// Bytes returns the bytes alreayd written to the fixed writer. func (w *fixedWriter) Bytes() []byte { return w.b } -// newFixedWriter... -func newFixedWriter(max int) *fixedWriter { +// newFixedWriter returns a new io.Writer that will error once more bytes than +// the specified max have been written. +func newFixedWriter(max int) io.Writer { b := make([]byte, max, max) fw := fixedWriter{b, 0} return &fw @@ -47,15 +52,20 @@ type fixedReader struct { iobuf *bytes.Buffer } -// Read .... +// Read reads the next len(p) bytes from the fixed reader. When the number of +// bytes read would exceed the maximum number of allowed bytes to be read from +// the fixed writer, an error is returned. +// +// This satisfies the io.Reader interface. func (fr *fixedReader) Read(p []byte) (n int, err error) { n, err = fr.iobuf.Read(p) fr.pos += n return } -// newFixedReader ... -func newFixedReader(max int, buf []byte) *fixedReader { +// newFixedReader returns a new io.Reader that will error once more bytes than +// the specified max have been read. +func newFixedReader(max int, buf []byte) io.Reader { b := make([]byte, max, max) if buf != nil { copy(b[:], buf) From c9178993037dcd44bc3c64ab6031bec0baa9bf8a Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 30 Mar 2014 15:56:52 -0500 Subject: [PATCH 166/219] Allow optional fields in MsgVersion decode. This commit modifies the MsgVersion.BtcDecode function to match the behavior where fields after the first address field (AddrYou) are optional and only read if the buffer contains remaining bytes. Unfortunately this means the reader for MsgVersion.BtcDecode must be a *bytes.Buffer or an error is returned. This is not an issue for the vast majority of cases since all of the message reading code which is the main way messages are read is already using a *bytes.Buffer, however, this change might affect external callers if they are doing something special with custom readers. Fixes #14. --- msgversion.go | 71 ++++++++++++++++++++++++++++++---------------- msgversion_test.go | 22 +++++++++----- test_coverage.txt | 8 +++--- 3 files changed, 66 insertions(+), 35 deletions(-) diff --git a/msgversion.go b/msgversion.go index 0fc18b3f..15a4e212 100644 --- a/msgversion.go +++ b/msgversion.go @@ -5,6 +5,7 @@ package btcwire import ( + "bytes" "fmt" "io" "net" @@ -66,44 +67,66 @@ func (msg *MsgVersion) AddService(service ServiceFlag) { } // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// The version message is special in that the protocol version hasn't been +// negotiated yet. As a result, the pver field is ignored and any fields which +// are added in new versions are optional. This also mean that r must be a +// *bytes.Buffer so the number of remaining bytes can be ascertained. +// // This is part of the Message interface implementation. func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error { + buf, ok := r.(*bytes.Buffer) + if !ok { + return fmt.Errorf("MsgVersion.BtcDecode reader is not a " + + "*bytes.Buffer") + } + var sec int64 - err := readElements(r, &msg.ProtocolVersion, &msg.Services, &sec) + err := readElements(buf, &msg.ProtocolVersion, &msg.Services, &sec) if err != nil { return err } msg.Timestamp = time.Unix(sec, 0) - err = readNetAddress(r, pver, &msg.AddrYou, false) + err = readNetAddress(buf, pver, &msg.AddrYou, false) if err != nil { return err } - err = readNetAddress(r, pver, &msg.AddrMe, false) - if err != nil { - return err + // Protocol versions >= 106 added a from address, nonce, and user agent + // field and they are only considered present if there are bytes + // remaining in the message. + if buf.Len() > 0 { + err = readNetAddress(buf, pver, &msg.AddrMe, false) + if err != nil { + return err + } + } + if buf.Len() > 0 { + err = readElement(buf, &msg.Nonce) + if err != nil { + return err + } + } + if buf.Len() > 0 { + userAgent, err := readVarString(buf, pver) + if err != nil { + return err + } + if len(userAgent) > MaxUserAgentLen { + str := fmt.Sprintf("user agent too long [len %v, max %v]", + len(userAgent), MaxUserAgentLen) + return messageError("MsgVersion.BtcDecode", str) + } + msg.UserAgent = userAgent } - err = readElement(r, &msg.Nonce) - if err != nil { - return err - } - - userAgent, err := readVarString(r, pver) - if err != nil { - return err - } - if len(userAgent) > MaxUserAgentLen { - str := fmt.Sprintf("user agent too long [len %v, max %v]", - len(userAgent), MaxUserAgentLen) - return messageError("MsgVersion.BtcDecode", str) - } - msg.UserAgent = userAgent - - err = readElement(r, &msg.LastBlock) - if err != nil { - return err + // Protocol versions >= 209 added a last known block field. It is only + // considered present if there are bytes remaining in the message. + if buf.Len() > 0 { + err = readElement(buf, &msg.LastBlock) + if err != nil { + return err + } } return nil diff --git a/msgversion_test.go b/msgversion_test.go index d12e7044..45561d13 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -236,6 +236,14 @@ func TestVersionWireErrors(t *testing.T) { pver := uint32(60002) btcwireErr := &btcwire.MessageError{} + // Ensure calling MsgVersion.BtcDecode with a non *bytes.Buffer returns + // error. + fr := newFixedReader(0, []byte{}) + if err := baseVersion.BtcDecode(fr, pver); err == nil { + t.Errorf("Did not received error when calling " + + "MsgVersion.BtcDecode with non *bytes.Buffer") + } + // Copy the base version and change the user agent to exceed max limits. bvc := *baseVersion exceedUAVer := &bvc @@ -277,15 +285,15 @@ func TestVersionWireErrors(t *testing.T) { // Force error in remote address. {baseVersion, baseVersionEncoded, pver, 20, io.ErrShortWrite, io.EOF}, // Force error in local address. - {baseVersion, baseVersionEncoded, pver, 46, io.ErrShortWrite, io.EOF}, + {baseVersion, baseVersionEncoded, pver, 47, io.ErrShortWrite, io.ErrUnexpectedEOF}, // Force error in nonce. - {baseVersion, baseVersionEncoded, pver, 72, io.ErrShortWrite, io.EOF}, + {baseVersion, baseVersionEncoded, pver, 73, io.ErrShortWrite, io.ErrUnexpectedEOF}, // Force error in user agent length. - {baseVersion, baseVersionEncoded, pver, 80, io.ErrShortWrite, io.EOF}, - // Force error in user agent. {baseVersion, baseVersionEncoded, pver, 81, io.ErrShortWrite, io.EOF}, + // Force error in user agent. + {baseVersion, baseVersionEncoded, pver, 82, io.ErrShortWrite, io.ErrUnexpectedEOF}, // Force error in last block. - {baseVersion, baseVersionEncoded, pver, 97, io.ErrShortWrite, io.EOF}, + {baseVersion, baseVersionEncoded, pver, 98, io.ErrShortWrite, io.ErrUnexpectedEOF}, // Force error due to user agent too big. {exceedUAVer, exceedUAVerEncoded, pver, newLen, btcwireErr, btcwireErr}, } @@ -313,8 +321,8 @@ func TestVersionWireErrors(t *testing.T) { // Decode from wire format. var msg btcwire.MsgVersion - r := newFixedReader(test.max, test.buf) - err = msg.BtcDecode(r, test.pver) + buf := bytes.NewBuffer(test.buf[0:test.max]) + err = msg.BtcDecode(buf, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { t.Errorf("BtcDecode #%d wrong error got: %v, want: %v", i, err, test.readErr) diff --git a/test_coverage.txt b/test_coverage.txt index 6b9fac8b..4672a003 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,11 +1,11 @@ -github.com/conformal/btcwire/common.go writeElement 100.00% (61/61) github.com/conformal/btcwire/common.go readElement 100.00% (61/61) +github.com/conformal/btcwire/common.go writeElement 100.00% (61/61) github.com/conformal/btcwire/message.go ReadMessageN 100.00% (42/42) github.com/conformal/btcwire/message.go WriteMessageN 100.00% (38/38) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (36/36) +github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (32/32) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (26/26) -github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (25/25) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (22/22) github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) @@ -48,7 +48,7 @@ github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/common.go varIntSerializeSize 100.00% (7/7) +github.com/conformal/btcwire/common.go VarIntSerializeSize 100.00% (7/7) github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (6/6) github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) @@ -165,5 +165,5 @@ github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (1153/1153) +github.com/conformal/btcwire --------------------------------- 100.00% (1160/1160) From 872134805129ccfeb696870c0a8d6bf8d981f806 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 30 Mar 2014 23:39:28 -0500 Subject: [PATCH 167/219] Add tests for optional message fields. Since fields of a version message after the AddrMe field are optional, this commit adds a series of tests which ensure parsing version messages which omit each of the optional fields works properly. --- msgversion_test.go | 101 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/msgversion_test.go b/msgversion_test.go index 45561d13..ca069699 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -341,6 +341,107 @@ func TestVersionWireErrors(t *testing.T) { } } +// TestVersionOptionalFields performs tests to ensure that an encoded version +// messages that omit optional fields are handled correctly. +func TestVersionOptionalFields(t *testing.T) { + // onlyRequiredVersion is a version message that only contains the + // required versions and all other values set to their default values. + onlyRequiredVersion := btcwire.MsgVersion{ + ProtocolVersion: 60002, + Services: btcwire.SFNodeNetwork, + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST) + AddrYou: btcwire.NetAddress{ + Timestamp: time.Time{}, // Zero value -- no timestamp in version + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("192.168.0.1"), + Port: 8333, + }, + } + onlyRequiredVersionEncoded := make([]byte, len(baseVersionEncoded)-55) + copy(onlyRequiredVersionEncoded, baseVersionEncoded) + + // addrMeVersion is a version message that contains all fields through + // the AddrMe field. + addrMeVersion := onlyRequiredVersion + addrMeVersion.AddrMe = btcwire.NetAddress{ + Timestamp: time.Time{}, // Zero value -- no timestamp in version + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("127.0.0.1"), + Port: 8333, + } + addrMeVersionEncoded := make([]byte, len(baseVersionEncoded)-29) + copy(addrMeVersionEncoded, baseVersionEncoded) + + // nonceVersion is a version message that contains all fields through + // the Nonce field. + nonceVersion := addrMeVersion + nonceVersion.Nonce = 123123 // 0x1e0f3 + nonceVersionEncoded := make([]byte, len(baseVersionEncoded)-21) + copy(nonceVersionEncoded, baseVersionEncoded) + + // uaVersion is a version message that contains all fields through + // the UserAgent field. + uaVersion := nonceVersion + uaVersion.UserAgent = "/btcdtest:0.0.1/" + uaVersionEncoded := make([]byte, len(baseVersionEncoded)-4) + copy(uaVersionEncoded, baseVersionEncoded) + + // lastBlockVersion is a version message that contains all fields + // through the LastBlock field. + lastBlockVersion := uaVersion + lastBlockVersion.LastBlock = 234234 // 0x392fa + lastBlockVersionEncoded := make([]byte, len(baseVersionEncoded)) + copy(lastBlockVersionEncoded, baseVersionEncoded) + + tests := []struct { + msg *btcwire.MsgVersion // Expected message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + { + &onlyRequiredVersion, + onlyRequiredVersionEncoded, + btcwire.ProtocolVersion, + }, + { + &addrMeVersion, + addrMeVersionEncoded, + btcwire.ProtocolVersion, + }, + { + &nonceVersion, + nonceVersionEncoded, + btcwire.ProtocolVersion, + }, + { + &uaVersion, + uaVersionEncoded, + btcwire.ProtocolVersion, + }, + { + &lastBlockVersion, + lastBlockVersionEncoded, + btcwire.ProtocolVersion, + }, + } + + for i, test := range tests { + // Decode the message from wire format. + var msg btcwire.MsgVersion + 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.msg) { + t.Errorf("BtcDecode #%d\n got: %s want: %s", i, + spew.Sdump(msg), spew.Sdump(test.msg)) + continue + } + } +} + // baseVersion is used in the various tests as a baseline MsgVersion. var baseVersion = &btcwire.MsgVersion{ ProtocolVersion: 60002, From e9a18fb14c58c516399977ebe738c85061ce2542 Mon Sep 17 00:00:00 2001 From: David Hill Date: Thu, 27 Mar 2014 15:19:03 -0400 Subject: [PATCH 168/219] Support RelayTx param in ver message for 70001+. This commit adds support for the version message RelayTx parameter for protocol version 70001+ as added by BIP0037. --- common.go | 26 ++++++++ message_test.go | 2 +- msgversion.go | 22 ++++++- msgversion_test.go | 146 ++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 186 insertions(+), 10 deletions(-) diff --git a/common.go b/common.go index e8f34f4f..dc946c88 100644 --- a/common.go +++ b/common.go @@ -60,6 +60,19 @@ func readElement(r io.Reader, element interface{}) error { *e = binary.LittleEndian.Uint64(b) return nil + case *bool: + b := scratch[0:1] + _, err := io.ReadFull(r, b) + if err != nil { + return err + } + if b[0] == 0x00 { + *e = false + } else { + *e = true + } + return nil + // Message header checksum. case *[4]byte: _, err := io.ReadFull(r, e[:]) @@ -179,6 +192,19 @@ func writeElement(w io.Writer, element interface{}) error { } return nil + case bool: + b := scratch[0:1] + if e == true { + b[0] = 0x01 + } else { + b[0] = 0x00 + } + _, err := w.Write(b) + if err != nil { + return err + } + return nil + // Message header checksum. case [4]byte: _, err := w.Write(e[:]) diff --git a/message_test.go b/message_test.go index ba542891..a3f4cddb 100644 --- a/message_test.go +++ b/message_test.go @@ -76,7 +76,7 @@ func TestMessage(t *testing.T) { btcnet btcwire.BitcoinNet // Network to use for wire encoding bytes int // Expected num bytes read/written }{ - {msgVersion, msgVersion, pver, btcwire.MainNet, 121}, + {msgVersion, msgVersion, pver, btcwire.MainNet, 122}, {msgVerack, msgVerack, pver, btcwire.MainNet, 24}, {msgGetAddr, msgGetAddr, pver, btcwire.MainNet, 24}, {msgAddr, msgAddr, pver, btcwire.MainNet, 25}, diff --git a/msgversion.go b/msgversion.go index 15a4e212..bfa09b96 100644 --- a/msgversion.go +++ b/msgversion.go @@ -49,6 +49,9 @@ type MsgVersion struct { // Last block seen by the generator of the version message. LastBlock int32 + + // Announce transactions to peer. + RelayTx bool } // HasService returns whether the specified service is supported by the peer @@ -129,6 +132,14 @@ func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error { } } + if pver >= BIP0037Version { + err = readElement(r, &msg.RelayTx) + if err != nil { + // Optional + msg.RelayTx = true + } + } + return nil } @@ -172,6 +183,12 @@ func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32) error { return err } + if pver >= BIP0037Version { + err = writeElement(w, msg.RelayTx) + if err != nil { + return err + } + } return nil } @@ -189,8 +206,8 @@ func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 { // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + remote // and local net addresses + nonce 8 bytes + length of user agent (varInt) + - // max allowed useragent length + last block 4 bytes. - return 32 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload + MaxUserAgentLen + // max allowed useragent length + last block 4 bytes + relay tx 1 byte. + return 32 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload + MaxUserAgentLen + 1 } // NewMsgVersion returns a new bitcoin version message that conforms to the @@ -210,6 +227,7 @@ func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64, Nonce: nonce, UserAgent: userAgent, LastBlock: lastBlock, + RelayTx: true, } } diff --git a/msgversion_test.go b/msgversion_test.go index ca069699..dc935fd2 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -64,6 +64,10 @@ func TestVersion(t *testing.T) { t.Errorf("NewMsgVersion: wrong last block - got %v, want %v", msg.LastBlock, lastBlock) } + if msg.RelayTx != true { + t.Errorf("NewMsgVersion: relaytx is not true by default: - got %v, want %v", + msg.RelayTx, true) + } // Version message should not have any services set by default. if msg.Services != 0 { @@ -85,8 +89,8 @@ func TestVersion(t *testing.T) { // Ensure max payload is expected value. // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + // remote and local net addresses + nonce 8 bytes + length of user agent - // (varInt) + max allowed user agent length + last block 4 bytes. - wantPayload := uint32(2101) + // (varInt) + max allowed user agent length + last block 4 bytes + relay tx 1 byte. + wantPayload := uint32(2102) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { t.Errorf("MaxPayloadLength: wrong max payload length for "+ @@ -157,9 +161,9 @@ func TestVersionWire(t *testing.T) { }{ // Latest protocol version. { - baseVersion, - baseVersion, - baseVersionEncoded, + baseVersion70001, + baseVersion70001, + baseVersion70001Encoded, btcwire.ProtocolVersion, }, @@ -179,6 +183,14 @@ func TestVersionWire(t *testing.T) { btcwire.BIP0031Version, }, + // Protocol version BIP0037Version. + { + baseVersion70001, + baseVersion70001, + baseVersion70001Encoded, + btcwire.BIP0037Version, + }, + // Protocol version NetAddressTimeVersion. { baseVersion, @@ -293,8 +305,10 @@ func TestVersionWireErrors(t *testing.T) { // Force error in user agent. {baseVersion, baseVersionEncoded, pver, 82, io.ErrShortWrite, io.ErrUnexpectedEOF}, // Force error in last block. - {baseVersion, baseVersionEncoded, pver, 98, io.ErrShortWrite, io.ErrUnexpectedEOF}, - // Force error due to user agent too big. + {baseVersion, baseVersionEncoded, pver, 97, io.ErrShortWrite, io.EOF}, + // Force error in relay tx. + {baseVersion70001, baseVersion70001Encoded, uint32(70001), 101, io.ErrShortWrite, io.EOF}, + // Force error due to user agent too big {exceedUAVer, exceedUAVerEncoded, pver, newLen, btcwireErr, btcwireErr}, } @@ -442,6 +456,77 @@ func TestVersionOptionalFields(t *testing.T) { } } +// TestVersionRelayTx tests the MsgVersion RelayTx API +func TestVersionRelayTx(t *testing.T) { + // Create version message data. + userAgent := "/btcdtest:0.0.1/" + lastBlock := int32(234234) + tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} + me, err := btcwire.NewNetAddress(tcpAddrMe, btcwire.SFNodeNetwork) + if err != nil { + t.Errorf("NewNetAddress: %v", err) + } + tcpAddrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333} + you, err := btcwire.NewNetAddress(tcpAddrYou, btcwire.SFNodeNetwork) + if err != nil { + t.Errorf("NewNetAddress: %v", err) + } + nonce, err := btcwire.RandomUint64() + if err != nil { + t.Errorf("RandomUint64: error generating nonce: %v", err) + } + + // Ensure we get the correct data back out. + msg := btcwire.NewMsgVersion(me, you, nonce, userAgent, lastBlock) + + // Explictly set RelayTx to false since true by default. + msg.RelayTx = false + + // Encode the message to wire format. + var buf bytes.Buffer + err = msg.BtcEncode(&buf, btcwire.BIP0037Version) + if err != nil { + t.Errorf("BtcEncode error %v", err) + } + b := buf.Bytes() + if len(b) != 102 || b[101] != 0x00 { + t.Errorf("Relay Tx is not false") + } + + wantBuf := []byte{ + 0x71, 0x11, 0x01, 0x00, // Protocol version 70001 + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp + // AddrYou -- No timestamp for NetAddress in version message + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01, // IP 192.168.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + // AddrMe -- No timestamp for NetAddress in version message + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + 0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Nonce + 0x10, // Varint for user agent length + 0x2f, 0x62, 0x74, 0x63, 0x64, 0x74, 0x65, 0x73, + 0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent + 0xfa, 0x92, 0x03, 0x00, // Last block + 0x00, // Relay tx (false) + } + + // Decode the message from wire format. + msg = &btcwire.MsgVersion{} + rbuf := bytes.NewBuffer(wantBuf) + err = msg.BtcDecode(rbuf, btcwire.BIP0037Version) + if err != nil { + t.Errorf("BtcDecode error %v", err) + } + if msg.RelayTx != false { + t.Errorf("Relay Tx is not false") + } +} + // baseVersion is used in the various tests as a baseline MsgVersion. var baseVersion = &btcwire.MsgVersion{ ProtocolVersion: 60002, @@ -486,3 +571,50 @@ var baseVersionEncoded = []byte{ 0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent 0xfa, 0x92, 0x03, 0x00, // Last block } + +// baseVersion70001 is used in the various tests as a baseline MsgVersion. +var baseVersion70001 = &btcwire.MsgVersion{ + ProtocolVersion: 70001, + Services: btcwire.SFNodeNetwork, + Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST) + AddrYou: btcwire.NetAddress{ + Timestamp: time.Time{}, // Zero value -- no timestamp in version + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("192.168.0.1"), + Port: 8333, + }, + AddrMe: btcwire.NetAddress{ + Timestamp: time.Time{}, // Zero value -- no timestamp in version + Services: btcwire.SFNodeNetwork, + IP: net.ParseIP("127.0.0.1"), + Port: 8333, + }, + Nonce: 123123, // 0x1e0f3 + UserAgent: "/btcdtest:0.0.1/", + LastBlock: 234234, // 0x392fa + RelayTx: true, +} + +// baseVersion70001Encoded is the wire encoded bytes for baseVersion using protocol +// version 70001 and is used in the various tests. +var baseVersion70001Encoded = []byte{ + 0x71, 0x11, 0x01, 0x00, // Protocol version 70001 + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp + // AddrYou -- No timestamp for NetAddress in version message + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01, // IP 192.168.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + // AddrMe -- No timestamp for NetAddress in version message + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1 + 0x20, 0x8d, // Port 8333 in big-endian + 0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Nonce + 0x10, // Varint for user agent length + 0x2f, 0x62, 0x74, 0x63, 0x64, 0x74, 0x65, 0x73, + 0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent + 0xfa, 0x92, 0x03, 0x00, // Last block + 0x01, // Relay tx +} From 937374c95a0fa242080c2f3024d54d63651b1e38 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 30 Mar 2014 11:00:23 -0500 Subject: [PATCH 169/219] Cleanup and finish relay transaction work. - Coalesce the new bytes into the max message size constant to stay consistent - Correct optional relay tx field handling - Rename the relay transactions field to DisableRelayTx so the zero value of false has the correct default behavior - Add tests for new bool fast paths in read/writeElement - Stay consistent with version order in tests - Add a single entry to TestVersionWire to test the new functionality instead of adding a whole new TextVersionRelayTx function. - Use BIP0037 in tests instead of hard coding 70001 - Nuke XXX that 70001 is different since this is handled now - Fix and cleanup some comments - Update test coverage report --- common_test.go | 9 +++ msgversion.go | 40 +++++++----- msgversion_test.go | 147 +++++++++++++++------------------------------ test_coverage.txt | 12 ++-- 4 files changed, 90 insertions(+), 118 deletions(-) diff --git a/common_test.go b/common_test.go index d27f41a3..577d3190 100644 --- a/common_test.go +++ b/common_test.go @@ -52,6 +52,14 @@ func TestElementWire(t *testing.T) { 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}, @@ -159,6 +167,7 @@ func TestElementWireErrors(t *testing.T) { {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}, { [btcwire.CommandSize]byte{ diff --git a/msgversion.go b/msgversion.go index bfa09b96..85feee63 100644 --- a/msgversion.go +++ b/msgversion.go @@ -50,8 +50,8 @@ type MsgVersion struct { // Last block seen by the generator of the version message. LastBlock int32 - // Announce transactions to peer. - RelayTx bool + // Don't announce transactions to peer. + DisableRelayTx bool } // HasService returns whether the specified service is supported by the peer @@ -132,12 +132,18 @@ func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error { } } - if pver >= BIP0037Version { - err = readElement(r, &msg.RelayTx) - if err != nil { - // Optional - msg.RelayTx = true - } + // There was no relay transactions field before BIP0037Version, but + // the default behavior prior to the addition of the field was to always + // relay transactions. + if buf.Len() > 0 { + // It's safe to ignore the error here since the buffer has at + // least one byte and that byte will result in a boolean value + // regardless of its value. Also, the wire encoding for the + // field is true when transactions should be relayed, so reverse + // it for the DisableRelayTx field. + var relayTx bool + readElement(r, &relayTx) + msg.DisableRelayTx = !relayTx } return nil @@ -183,8 +189,11 @@ func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32) error { return err } + // There was no relay transactions field before BIP0037Version. Also, + // the wire encoding for the field is true when transactions should be + // relayed, so reverse it from the DisableRelayTx field. if pver >= BIP0037Version { - err = writeElement(w, msg.RelayTx) + err = writeElement(w, !msg.DisableRelayTx) if err != nil { return err } @@ -202,12 +211,13 @@ func (msg *MsgVersion) Command() string { // receiver. This is part of the Message interface implementation. func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 { // XXX: <= 106 different - // XXX: >= 70001 different - // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + remote - // and local net addresses + nonce 8 bytes + length of user agent (varInt) + - // max allowed useragent length + last block 4 bytes + relay tx 1 byte. - return 32 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload + MaxUserAgentLen + 1 + // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + + // remote and local net addresses + nonce 8 bytes + length of user + // agent (varInt) + max allowed useragent length + last block 4 bytes + + // relay transactions flag 1 byte. + return 33 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload + + MaxUserAgentLen } // NewMsgVersion returns a new bitcoin version message that conforms to the @@ -227,7 +237,7 @@ func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64, Nonce: nonce, UserAgent: userAgent, LastBlock: lastBlock, - RelayTx: true, + DisableRelayTx: false, } } diff --git a/msgversion_test.go b/msgversion_test.go index dc935fd2..5e2c2147 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -64,9 +64,9 @@ func TestVersion(t *testing.T) { t.Errorf("NewMsgVersion: wrong last block - got %v, want %v", msg.LastBlock, lastBlock) } - if msg.RelayTx != true { - t.Errorf("NewMsgVersion: relaytx is not true by default: - got %v, want %v", - msg.RelayTx, true) + if msg.DisableRelayTx != false { + t.Errorf("NewMsgVersion: disable relay tx is not false by "+ + "default - got %v, want %v", msg.DisableRelayTx, false) } // Version message should not have any services set by default. @@ -89,7 +89,8 @@ func TestVersion(t *testing.T) { // Ensure max payload is expected value. // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + // remote and local net addresses + nonce 8 bytes + length of user agent - // (varInt) + max allowed user agent length + last block 4 bytes + relay tx 1 byte. + // (varInt) + max allowed user agent length + last block 4 bytes + + // relay transactions flag 1 byte. wantPayload := uint32(2102) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { @@ -150,9 +151,18 @@ func TestVersion(t *testing.T) { return } -// TestAlertWire tests the MsgAlert wire encode and decode for various protocol -// versions. +// TestVersionWire tests the MsgVersion wire encode and decode for various +// protocol versions. func TestVersionWire(t *testing.T) { + // verRelayTxFalse and verRelayTxFalseEncoded is a version message as of + // BIP0037Version with the transaction relay disabled. + baseVersionBIP0037Copy := *baseVersionBIP0037 + verRelayTxFalse := &baseVersionBIP0037Copy + verRelayTxFalse.DisableRelayTx = true + verRelayTxFalseEncoded := make([]byte, len(baseVersionBIP0037Encoded)) + copy(verRelayTxFalseEncoded, baseVersionBIP0037Encoded) + verRelayTxFalseEncoded[len(verRelayTxFalseEncoded)-1] = 0 + tests := []struct { in *btcwire.MsgVersion // Message to encode out *btcwire.MsgVersion // Expected decoded message @@ -161,12 +171,30 @@ func TestVersionWire(t *testing.T) { }{ // Latest protocol version. { - baseVersion70001, - baseVersion70001, - baseVersion70001Encoded, + baseVersionBIP0037, + baseVersionBIP0037, + baseVersionBIP0037Encoded, btcwire.ProtocolVersion, }, + // Protocol version BIP0037Version with relay transactions field + // true. + { + baseVersionBIP0037, + baseVersionBIP0037, + baseVersionBIP0037Encoded, + btcwire.BIP0037Version, + }, + + // Protocol version BIP0037Version with relay transactions field + // false. + { + verRelayTxFalse, + verRelayTxFalse, + verRelayTxFalseEncoded, + btcwire.BIP0037Version, + }, + // Protocol version BIP0035Version. { baseVersion, @@ -183,14 +211,6 @@ func TestVersionWire(t *testing.T) { btcwire.BIP0031Version, }, - // Protocol version BIP0037Version. - { - baseVersion70001, - baseVersion70001, - baseVersion70001Encoded, - btcwire.BIP0037Version, - }, - // Protocol version NetAddressTimeVersion. { baseVersion, @@ -305,9 +325,13 @@ func TestVersionWireErrors(t *testing.T) { // Force error in user agent. {baseVersion, baseVersionEncoded, pver, 82, io.ErrShortWrite, io.ErrUnexpectedEOF}, // Force error in last block. - {baseVersion, baseVersionEncoded, pver, 97, io.ErrShortWrite, io.EOF}, - // Force error in relay tx. - {baseVersion70001, baseVersion70001Encoded, uint32(70001), 101, io.ErrShortWrite, io.EOF}, + {baseVersion, baseVersionEncoded, pver, 98, io.ErrShortWrite, io.ErrUnexpectedEOF}, + // Force error in relay tx - no read error should happen since + // it's optional. + { + baseVersionBIP0037, baseVersionBIP0037Encoded, + btcwire.BIP0037Version, 101, io.ErrShortWrite, nil, + }, // Force error due to user agent too big {exceedUAVer, exceedUAVerEncoded, pver, newLen, btcwireErr, btcwireErr}, } @@ -456,77 +480,6 @@ func TestVersionOptionalFields(t *testing.T) { } } -// TestVersionRelayTx tests the MsgVersion RelayTx API -func TestVersionRelayTx(t *testing.T) { - // Create version message data. - userAgent := "/btcdtest:0.0.1/" - lastBlock := int32(234234) - tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} - me, err := btcwire.NewNetAddress(tcpAddrMe, btcwire.SFNodeNetwork) - if err != nil { - t.Errorf("NewNetAddress: %v", err) - } - tcpAddrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333} - you, err := btcwire.NewNetAddress(tcpAddrYou, btcwire.SFNodeNetwork) - if err != nil { - t.Errorf("NewNetAddress: %v", err) - } - nonce, err := btcwire.RandomUint64() - if err != nil { - t.Errorf("RandomUint64: error generating nonce: %v", err) - } - - // Ensure we get the correct data back out. - msg := btcwire.NewMsgVersion(me, you, nonce, userAgent, lastBlock) - - // Explictly set RelayTx to false since true by default. - msg.RelayTx = false - - // Encode the message to wire format. - var buf bytes.Buffer - err = msg.BtcEncode(&buf, btcwire.BIP0037Version) - if err != nil { - t.Errorf("BtcEncode error %v", err) - } - b := buf.Bytes() - if len(b) != 102 || b[101] != 0x00 { - t.Errorf("Relay Tx is not false") - } - - wantBuf := []byte{ - 0x71, 0x11, 0x01, 0x00, // Protocol version 70001 - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork - 0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp - // AddrYou -- No timestamp for NetAddress in version message - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01, // IP 192.168.0.1 - 0x20, 0x8d, // Port 8333 in big-endian - // AddrMe -- No timestamp for NetAddress in version message - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1 - 0x20, 0x8d, // Port 8333 in big-endian - 0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Nonce - 0x10, // Varint for user agent length - 0x2f, 0x62, 0x74, 0x63, 0x64, 0x74, 0x65, 0x73, - 0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent - 0xfa, 0x92, 0x03, 0x00, // Last block - 0x00, // Relay tx (false) - } - - // Decode the message from wire format. - msg = &btcwire.MsgVersion{} - rbuf := bytes.NewBuffer(wantBuf) - err = msg.BtcDecode(rbuf, btcwire.BIP0037Version) - if err != nil { - t.Errorf("BtcDecode error %v", err) - } - if msg.RelayTx != false { - t.Errorf("Relay Tx is not false") - } -} - // baseVersion is used in the various tests as a baseline MsgVersion. var baseVersion = &btcwire.MsgVersion{ ProtocolVersion: 60002, @@ -572,8 +525,9 @@ var baseVersionEncoded = []byte{ 0xfa, 0x92, 0x03, 0x00, // Last block } -// baseVersion70001 is used in the various tests as a baseline MsgVersion. -var baseVersion70001 = &btcwire.MsgVersion{ +// baseVersionBIP0037 is used in the various tests as a baseline MsgVersion for +// BIP0037. +var baseVersionBIP0037 = &btcwire.MsgVersion{ ProtocolVersion: 70001, Services: btcwire.SFNodeNetwork, Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST) @@ -592,12 +546,11 @@ var baseVersion70001 = &btcwire.MsgVersion{ Nonce: 123123, // 0x1e0f3 UserAgent: "/btcdtest:0.0.1/", LastBlock: 234234, // 0x392fa - RelayTx: true, } -// baseVersion70001Encoded is the wire encoded bytes for baseVersion using protocol -// version 70001 and is used in the various tests. -var baseVersion70001Encoded = []byte{ +// baseVersionBIP0037Encoded is the wire encoded bytes for baseVersionBIP0037 +// using protocol version BIP0037Version and is used in the various tests. +var baseVersionBIP0037Encoded = []byte{ 0x71, 0x11, 0x01, 0x00, // Protocol version 70001 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork 0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp diff --git a/test_coverage.txt b/test_coverage.txt index 4672a003..02773f17 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,16 +1,16 @@ -github.com/conformal/btcwire/common.go readElement 100.00% (61/61) -github.com/conformal/btcwire/common.go writeElement 100.00% (61/61) +github.com/conformal/btcwire/common.go readElement 100.00% (69/69) +github.com/conformal/btcwire/common.go writeElement 100.00% (69/69) github.com/conformal/btcwire/message.go ReadMessageN 100.00% (42/42) github.com/conformal/btcwire/message.go WriteMessageN 100.00% (38/38) github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (36/36) -github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (32/32) +github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (36/36) github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (26/26) +github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (26/26) github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (22/22) -github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (22/22) -github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (21/21) github.com/conformal/btcwire/common.go readVarInt 100.00% (21/21) +github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (21/21) github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) @@ -165,5 +165,5 @@ github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (1160/1160) +github.com/conformal/btcwire --------------------------------- 100.00% (1184/1184) From 0e1f8fda6df25a85026438ff763140c1f843c65b Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 5 Apr 2014 21:00:15 -0500 Subject: [PATCH 170/219] Correct some comments in block bytes breakdown. --- msgblock_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index c736e6ce..3a556aa1 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -523,16 +523,16 @@ var blockOneBytes = []byte{ 0x01, 0xe3, 0x62, 0x99, // Nonce 0x01, // TxnCount 0x01, 0x00, 0x00, 0x00, // Version - 0x01, // Varint for number of input transactions + 0x01, // Varint for number of transaction inputs 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // // Previous output hash + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash 0xff, 0xff, 0xff, 0xff, // Prevous output index 0x07, // Varint for length of signature script 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script 0xff, 0xff, 0xff, 0xff, // Sequence - 0x01, // Varint for number of output transactions + 0x01, // Varint for number of transaction outputs 0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount 0x43, // Varint for length of pk script 0x41, // OP_DATA_65 From f0581b565c5c3aa03bab01b324dd221f13fa91c1 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 6 Apr 2014 14:14:31 -0500 Subject: [PATCH 171/219] Correct two more comments in block bytes breakdown. --- msgblock_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/msgblock_test.go b/msgblock_test.go index 3a556aa1..c3a441af 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -530,7 +530,7 @@ var blockOneBytes = []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash 0xff, 0xff, 0xff, 0xff, // Prevous output index 0x07, // Varint for length of signature script - 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script (coinbase) 0xff, 0xff, 0xff, 0xff, // Sequence 0x01, // Varint for number of transaction outputs 0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount @@ -544,7 +544,7 @@ var blockOneBytes = []byte{ 0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6, 0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e, 0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58, - 0xee, // 65-byte signature + 0xee, // 65-byte uncompressed public key 0xac, // OP_CHECKSIG 0x00, 0x00, 0x00, 0x00, // Lock time } From 805ce37d31c3f92a69c75da28100a1786a924c1e Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 8 Apr 2014 15:28:02 -0400 Subject: [PATCH 172/219] Use the stack for most known sizes. By using the stack for known sizes, there is less pressure on the garbage collector. --- common.go | 28 +++++++++++++-------------- message.go | 6 +++--- msgtx.go | 56 +++++++++++++++++++++++++++--------------------------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/common.go b/common.go index dc946c88..203a3a4e 100644 --- a/common.go +++ b/common.go @@ -283,7 +283,7 @@ func writeElements(w io.Writer, elements ...interface{}) error { // readVarInt reads a variable length integer from r and returns it as a uint64. func readVarInt(r io.Reader, pver uint32) (uint64, error) { - b := make([]byte, 8) + var b [8]byte _, err := io.ReadFull(r, b[0:1]) if err != nil { return 0, err @@ -293,25 +293,25 @@ func readVarInt(r io.Reader, pver uint32) (uint64, error) { discriminant := uint8(b[0]) switch discriminant { case 0xff: - _, err := io.ReadFull(r, b) + _, err := io.ReadFull(r, b[:]) if err != nil { return 0, err } - rv = binary.LittleEndian.Uint64(b) + rv = binary.LittleEndian.Uint64(b[:]) case 0xfe: _, err := io.ReadFull(r, b[0:4]) if err != nil { return 0, err } - rv = uint64(binary.LittleEndian.Uint32(b)) + rv = uint64(binary.LittleEndian.Uint32(b[:])) case 0xfd: _, err := io.ReadFull(r, b[0:2]) if err != nil { return 0, err } - rv = uint64(binary.LittleEndian.Uint16(b)) + rv = uint64(binary.LittleEndian.Uint16(b[:])) default: rv = uint64(discriminant) @@ -329,25 +329,25 @@ func writeVarInt(w io.Writer, pver uint32, val uint64) error { } if val <= math.MaxUint16 { - buf := make([]byte, 3) + var buf [3]byte buf[0] = 0xfd binary.LittleEndian.PutUint16(buf[1:], uint16(val)) - _, err := w.Write(buf) + _, err := w.Write(buf[:]) return err } if val <= math.MaxUint32 { - buf := make([]byte, 5) + var buf [5]byte buf[0] = 0xfe binary.LittleEndian.PutUint32(buf[1:], uint32(val)) - _, err := w.Write(buf) + _, err := w.Write(buf[:]) return err } - buf := make([]byte, 9) + var buf [9]byte buf[0] = 0xff binary.LittleEndian.PutUint64(buf[1:], val) - _, err := w.Write(buf) + _, err := w.Write(buf[:]) return err } @@ -422,15 +422,15 @@ func writeVarString(w io.Writer, pver uint32, str string) error { // unexported version takes a reader primarily to ensure the error paths // can be properly tested by passing a fake reader in the tests. func randomUint64(r io.Reader) (uint64, error) { - b := make([]byte, 8) - n, err := r.Read(b) + var b [8]byte + n, err := r.Read(b[:]) if n != len(b) { return 0, io.ErrShortBuffer } if err != nil { return 0, err } - return binary.BigEndian.Uint64(b), nil + return binary.BigEndian.Uint64(b[:]), nil } // RandomUint64 returns a cryptographically random uint64 value. diff --git a/message.go b/message.go index 83f51e6f..1b502444 100644 --- a/message.go +++ b/message.go @@ -128,12 +128,12 @@ func readMessageHeader(r io.Reader) (int, *messageHeader, error) { // to read the entire header into a buffer first in case there is a // short read so the proper amount of read bytes are known. This works // since the header is a fixed size. - headerBytes := make([]byte, MessageHeaderSize) - n, err := io.ReadFull(r, headerBytes) + var headerBytes [MessageHeaderSize]byte + n, err := io.ReadFull(r, headerBytes[:]) if err != nil { return n, nil, err } - hr := bytes.NewBuffer(headerBytes) + hr := bytes.NewBuffer(headerBytes[:]) // Create and populate a messageHeader struct from the raw header bytes. hdr := messageHeader{} diff --git a/msgtx.go b/msgtx.go index 61b77c99..e31040b5 100644 --- a/msgtx.go +++ b/msgtx.go @@ -235,12 +235,12 @@ func (msg *MsgTx) Copy() *MsgTx { // See Deserialize for decoding transactions stored to disk, such as in a // database, as opposed to decoding transactions from the wire. func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { - buf := make([]byte, 4) - _, err := io.ReadFull(r, buf) + var buf [4]byte + _, err := io.ReadFull(r, buf[:]) if err != nil { return err } - msg.Version = binary.LittleEndian.Uint32(buf) + msg.Version = binary.LittleEndian.Uint32(buf[:]) count, err := readVarInt(r, pver) if err != nil { @@ -292,11 +292,11 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { msg.TxOut[i] = &to } - _, err = io.ReadFull(r, buf) + _, err = io.ReadFull(r, buf[:]) if err != nil { return err } - msg.LockTime = binary.LittleEndian.Uint32(buf) + msg.LockTime = binary.LittleEndian.Uint32(buf[:]) return nil } @@ -323,9 +323,9 @@ func (msg *MsgTx) Deserialize(r io.Reader) error { // See Serialize for encoding transactions to be stored to disk, such as in a // database, as opposed to encoding transactions for the wire. func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32) error { - buf := make([]byte, 4) - binary.LittleEndian.PutUint32(buf, msg.Version) - _, err := w.Write(buf) + var buf [4]byte + binary.LittleEndian.PutUint32(buf[:], msg.Version) + _, err := w.Write(buf[:]) if err != nil { return err } @@ -356,8 +356,8 @@ func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32) error { } } - binary.LittleEndian.PutUint32(buf, msg.LockTime) - _, err = w.Write(buf) + binary.LittleEndian.PutUint32(buf[:], msg.LockTime) + _, err = w.Write(buf[:]) if err != nil { return err } @@ -434,12 +434,12 @@ func readOutPoint(r io.Reader, pver uint32, version uint32, op *OutPoint) error return err } - buf := make([]byte, 4) - _, err = io.ReadFull(r, buf) + var buf [4]byte + _, err = io.ReadFull(r, buf[:]) if err != nil { return err } - op.Index = binary.LittleEndian.Uint32(buf) + op.Index = binary.LittleEndian.Uint32(buf[:]) return nil } @@ -451,9 +451,9 @@ func writeOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error return err } - buf := make([]byte, 4) - binary.LittleEndian.PutUint32(buf, op.Index) - _, err = w.Write(buf) + var buf [4]byte + binary.LittleEndian.PutUint32(buf[:], op.Index) + _, err = w.Write(buf[:]) if err != nil { return err } @@ -492,12 +492,12 @@ func readTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { } ti.SignatureScript = b - b = make([]byte, 4) - _, err = io.ReadFull(r, b) + var buf [4]byte + _, err = io.ReadFull(r, buf[:]) if err != nil { return err } - ti.Sequence = binary.LittleEndian.Uint32(b) + ti.Sequence = binary.LittleEndian.Uint32(buf[:]) return nil } @@ -521,9 +521,9 @@ func writeTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { return err } - buf := make([]byte, 4) - binary.LittleEndian.PutUint32(buf, ti.Sequence) - _, err = w.Write(buf) + var buf [4]byte + binary.LittleEndian.PutUint32(buf[:], ti.Sequence) + _, err = w.Write(buf[:]) if err != nil { return err } @@ -534,12 +534,12 @@ func writeTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { // readTxOut reads the next sequence of bytes from r as a transaction output // (TxOut). func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { - buf := make([]byte, 8) - _, err := io.ReadFull(r, buf) + var buf [8]byte + _, err := io.ReadFull(r, buf[:]) if err != nil { return err } - to.Value = int64(binary.LittleEndian.Uint64(buf)) + to.Value = int64(binary.LittleEndian.Uint64(buf[:])) count, err := readVarInt(r, pver) if err != nil { @@ -569,9 +569,9 @@ func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { // writeTxOut encodes to into the bitcoin protocol encoding for a transaction // output (TxOut) to w. func writeTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { - buf := make([]byte, 8) - binary.LittleEndian.PutUint64(buf, uint64(to.Value)) - _, err := w.Write(buf) + var buf [8]byte + binary.LittleEndian.PutUint64(buf[:], uint64(to.Value)) + _, err := w.Write(buf[:]) if err != nil { return err } From 9130de2de239b994f40bcd7727d6c14ed020b6ea Mon Sep 17 00:00:00 2001 From: Javed Khan Date: Sat, 19 Apr 2014 15:53:03 +0530 Subject: [PATCH 173/219] add tmp wire file to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 16e35934..c887bc15 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Temp files *~ +btcwire.test # Databases btcd.db From 6b82da13b4eff794bd9e79e39064546b811cefc2 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 19 Apr 2014 14:36:16 -0500 Subject: [PATCH 174/219] Setup TravisCI to report cov stats to coveralls.io. Also add a coveralls.io test coverage badge to the README. --- .travis.yml | 5 +++++ README.md | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 59c603be..9c1637bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,3 +3,8 @@ go: - release - tip install: go get -d -t -v ./... +script: go test -v -covermode=count -coverprofile=profile.cov +after_success: + - go get -v github.com/mattn/goveralls + - export PATH=$PATH:$HOME/gopath/bin + - goveralls -coverprofile=profile.cov -service=travis-ci diff --git a/README.md b/README.md index 5834bd01..7e15e7de 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ btcwire ======= [![Build Status](https://travis-ci.org/conformal/btcwire.png?branch=master)] -(https://travis-ci.org/conformal/btcwire) +(https://travis-ci.org/conformal/btcwire) [![Coverage Status] +(https://coveralls.io/repos/conformal/btcwire/badge.png?branch=master)] +(https://coveralls.io/r/conformal/btcwire?branch=master) Package btcwire implements the bitcoin wire protocol. A comprehensive suite of tests with 100% test coverage is provided to ensure proper functionality. See From 755944738a3abf64dcdc0f1d26f80506af926d05 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 19 Apr 2014 14:41:52 -0500 Subject: [PATCH 175/219] Instruct TravisCI to install coverage report tool. --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9c1637bc..7759ad70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,11 @@ language: go go: - release - tip -install: go get -d -t -v ./... -script: go test -v -covermode=count -coverprofile=profile.cov +install: + - go get -d -t -v ./... + - go get -v code.google.com/p/go.tools/cmd/cover +script: + - go test -v -covermode=count -coverprofile=profile.cov after_success: - go get -v github.com/mattn/goveralls - export PATH=$PATH:$HOME/gopath/bin From 44e34926a7051373472d332f6ed39e61fad68a5f Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 19 Apr 2014 14:44:14 -0500 Subject: [PATCH 176/219] Remove test coverage report refs from README.md. This is no longer needed since the repository is now configured to work with coveralls.io for test coverage reporting. Closes #17 --- README.md | 6 +- test_coverage.txt | 169 ---------------------------------------------- 2 files changed, 2 insertions(+), 173 deletions(-) delete mode 100644 test_coverage.txt diff --git a/README.md b/README.md index 7e15e7de..1b312de0 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,8 @@ btcwire (https://coveralls.io/r/conformal/btcwire?branch=master) Package btcwire implements the bitcoin wire protocol. A comprehensive suite of -tests with 100% test coverage is provided to ensure proper functionality. See -`test_coverage.txt` for the gocov coverage report. Alternatively, if you are -running a POSIX OS, you can run the `cov_report.sh` script for a real-time -report. Package btcwire is licensed under the liberal ISC license. +tests with 100% test coverage is provided to ensure proper functionality. +Package btcwire is licensed under the liberal ISC license. There is an associated blog post about the release of this package [here](https://blog.conformal.com/btcwire-the-bitcoin-wire-protocol-package-from-btcd/). diff --git a/test_coverage.txt b/test_coverage.txt deleted file mode 100644 index 02773f17..00000000 --- a/test_coverage.txt +++ /dev/null @@ -1,169 +0,0 @@ - -github.com/conformal/btcwire/common.go readElement 100.00% (69/69) -github.com/conformal/btcwire/common.go writeElement 100.00% (69/69) -github.com/conformal/btcwire/message.go ReadMessageN 100.00% (42/42) -github.com/conformal/btcwire/message.go WriteMessageN 100.00% (38/38) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcDecode 100.00% (36/36) -github.com/conformal/btcwire/msgversion.go MsgVersion.BtcDecode 100.00% (36/36) -github.com/conformal/btcwire/msgtx.go MsgTx.BtcEncode 100.00% (26/26) -github.com/conformal/btcwire/msgversion.go MsgVersion.BtcEncode 100.00% (26/26) -github.com/conformal/btcwire/msgtx.go MsgTx.Copy 100.00% (24/24) -github.com/conformal/btcwire/msgtx.go readTxIn 100.00% (22/22) -github.com/conformal/btcwire/common.go readVarInt 100.00% (21/21) -github.com/conformal/btcwire/msgblock.go MsgBlock.DeserializeTxLoc 100.00% (21/21) -github.com/conformal/btcwire/netaddress.go readNetAddress 100.00% (20/20) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcDecode 100.00% (20/20) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcDecode 100.00% (20/20) -github.com/conformal/btcwire/common.go writeVarInt 100.00% (20/20) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcDecode 100.00% (20/20) -github.com/conformal/btcwire/message.go makeEmptyMessage 100.00% (20/20) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.BtcEncode 100.00% (18/18) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.BtcEncode 100.00% (18/18) -github.com/conformal/btcwire/msgtx.go readTxOut 100.00% (17/17) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcDecode 100.00% (17/17) -github.com/conformal/btcwire/msgtx.go writeTxIn 100.00% (16/16) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.BtcEncode 100.00% (15/15) -github.com/conformal/btcwire/shahash.go NewShaHashFromStr 100.00% (15/15) -github.com/conformal/btcwire/msgaddr.go MsgAddr.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/netaddress.go writeNetAddress 100.00% (14/14) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/msginv.go MsgInv.BtcDecode 100.00% (14/14) -github.com/conformal/btcwire/msgtx.go writeTxOut 100.00% (13/13) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msggetdata.go MsgGetData.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/msginv.go MsgInv.BtcEncode 100.00% (12/12) -github.com/conformal/btcwire/protocol.go ServiceFlag.String 100.00% (12/12) -github.com/conformal/btcwire/common.go readVarString 100.00% (11/11) -github.com/conformal/btcwire/msgblock.go MsgBlock.BtcEncode 100.00% (11/11) -github.com/conformal/btcwire/message.go discardInput 100.00% (10/10) -github.com/conformal/btcwire/message.go readMessageHeader 100.00% (10/10) -github.com/conformal/btcwire/msgtx.go writeOutPoint 100.00% (9/9) -github.com/conformal/btcwire/msgtx.go readOutPoint 100.00% (9/9) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcDecode 100.00% (8/8) -github.com/conformal/btcwire/msgalert.go MsgAlert.BtcEncode 100.00% (8/8) -github.com/conformal/btcwire/common.go writeVarString 100.00% (7/7) -github.com/conformal/btcwire/common.go randomUint64 100.00% (7/7) -github.com/conformal/btcwire/msgversion.go NewMsgVersionFromConn 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcEncode 100.00% (7/7) -github.com/conformal/btcwire/msgpong.go MsgPong.BtcDecode 100.00% (7/7) -github.com/conformal/btcwire/common.go VarIntSerializeSize 100.00% (7/7) -github.com/conformal/btcwire/blockheader.go readBlockHeader 100.00% (6/6) -github.com/conformal/btcwire/common.go DoubleSha256 100.00% (6/6) -github.com/conformal/btcwire/msgtx.go MsgTx.SerializeSize 100.00% (6/6) -github.com/conformal/btcwire/blockheader.go BlockHeader.BlockSha 100.00% (5/5) -github.com/conformal/btcwire/blockheader.go writeBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/common.go readElements 100.00% (5/5) -github.com/conformal/btcwire/common.go writeElements 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddress 100.00% (5/5) -github.com/conformal/btcwire/msgaddr.go MsgAddr.AddAddresses 100.00% (5/5) -github.com/conformal/btcwire/msgblock.go MsgBlock.TxShas 100.00% (5/5) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msggetdata.go MsgGetData.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.AddBlockLocatorHash 100.00% (5/5) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.AddBlockHeader 100.00% (5/5) -github.com/conformal/btcwire/msginv.go MsgInv.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.AddInvVect 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcDecode 100.00% (5/5) -github.com/conformal/btcwire/msgping.go MsgPing.BtcEncode 100.00% (5/5) -github.com/conformal/btcwire/msgtx.go MsgTx.TxSha 100.00% (5/5) -github.com/conformal/btcwire/netaddress.go NewNetAddress 100.00% (5/5) -github.com/conformal/btcwire/shahash.go ShaHash.SetBytes 100.00% (5/5) -github.com/conformal/btcwire/shahash.go NewShaHash 100.00% (5/5) -github.com/conformal/btcwire/msgpong.go MsgPong.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcEncode 100.00% (4/4) -github.com/conformal/btcwire/invvect.go readInvVect 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.String 100.00% (4/4) -github.com/conformal/btcwire/invvect.go writeInvVect 100.00% (4/4) -github.com/conformal/btcwire/msgping.go MsgPing.MaxPayloadLength 100.00% (4/4) -github.com/conformal/btcwire/netaddress.go maxNetAddressPayload 100.00% (4/4) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.BtcDecode 100.00% (4/4) -github.com/conformal/btcwire/shahash.go ShaHash.Bytes 100.00% (3/3) -github.com/conformal/btcwire/error.go MessageError.Error 100.00% (3/3) -github.com/conformal/btcwire/protocol.go BitcoinNet.String 100.00% (3/3) -github.com/conformal/btcwire/msggetdata.go NewMsgGetDataSizeHint 100.00% (3/3) -github.com/conformal/btcwire/netaddress.go NetAddress.HasService 100.00% (3/3) -github.com/conformal/btcwire/msginv.go NewMsgInvSizeHint 100.00% (3/3) -github.com/conformal/btcwire/invvect.go InvType.String 100.00% (3/3) -github.com/conformal/btcwire/msgaddr.go MsgAddr.MaxPayloadLength 100.00% (3/3) -github.com/conformal/btcwire/msgversion.go MsgVersion.HasService 100.00% (3/3) -github.com/conformal/btcwire/message.go ReadMessage 100.00% (2/2) -github.com/conformal/btcwire/message.go WriteMessage 100.00% (2/2) -github.com/conformal/btcwire/netaddress.go NetAddress.SetAddress 100.00% (2/2) -github.com/conformal/btcwire/msgblock.go MsgBlock.AddTransaction 100.00% (2/2) -github.com/conformal/btcwire/netaddress.go NewNetAddressIPPort 100.00% (2/2) -github.com/conformal/btcwire/msgalert.go NewMsgAlert 100.00% (1/1) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.Command 100.00% (1/1) -github.com/conformal/btcwire/msgnotfound.go MsgNotFound.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgnotfound.go NewMsgNotFound 100.00% (1/1) -github.com/conformal/btcwire/msgping.go MsgPing.Command 100.00% (1/1) -github.com/conformal/btcwire/msgping.go NewMsgPing 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgalert.go MsgAlert.Command 100.00% (1/1) -github.com/conformal/btcwire/msgpong.go MsgPong.Command 100.00% (1/1) -github.com/conformal/btcwire/msgpong.go NewMsgPong 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go NewOutPoint 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go TxIn.SerializeSize 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go NewTxIn 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go TxOut.SerializeSize 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go NewTxOut 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go MsgTx.AddTxIn 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go MsgTx.AddTxOut 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.Command 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go NewMsgAddr 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go MsgTx.Deserialize 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go MsgTx.Serialize 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.Command 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go MsgTx.Command 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go MsgTx.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgtx.go NewMsgTx 100.00% (1/1) -github.com/conformal/btcwire/msgaddr.go MsgAddr.ClearAddresses 100.00% (1/1) -github.com/conformal/btcwire/invvect.go NewInvVect 100.00% (1/1) -github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcDecode 100.00% (1/1) -github.com/conformal/btcwire/msgverack.go MsgVerAck.BtcEncode 100.00% (1/1) -github.com/conformal/btcwire/msgverack.go MsgVerAck.Command 100.00% (1/1) -github.com/conformal/btcwire/msgverack.go MsgVerAck.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgverack.go NewMsgVerAck 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.AddService 100.00% (1/1) -github.com/conformal/btcwire/error.go messageError 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.Command 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go MsgVersion.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgversion.go NewMsgVersion 100.00% (1/1) -github.com/conformal/btcwire/common.go RandomUint64 100.00% (1/1) -github.com/conformal/btcwire/netaddress.go NetAddress.AddService 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go NewMsgGetAddr 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go MsgGetBlocks.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetblocks.go NewMsgGetBlocks 100.00% (1/1) -github.com/conformal/btcwire/shahash.go ShaHash.IsEqual 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcEncode 100.00% (1/1) -github.com/conformal/btcwire/msggetaddr.go MsgGetAddr.BtcDecode 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go MsgGetData.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Serialize 100.00% (1/1) -github.com/conformal/btcwire/blockheader.go NewBlockHeader 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go NewMsgBlock 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.BlockSha 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.Command 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go MsgGetHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msggetheaders.go NewMsgGetHeaders 100.00% (1/1) -github.com/conformal/btcwire/blockheader.go BlockHeader.Serialize 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Command 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go MsgHeaders.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgheaders.go NewMsgHeaders 100.00% (1/1) -github.com/conformal/btcwire/blockheader.go BlockHeader.Deserialize 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.Deserialize 100.00% (1/1) -github.com/conformal/btcwire/msgblock.go MsgBlock.ClearTransactions 100.00% (1/1) -github.com/conformal/btcwire/msginv.go MsgInv.Command 100.00% (1/1) -github.com/conformal/btcwire/msginv.go MsgInv.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msginv.go NewMsgInv 100.00% (1/1) -github.com/conformal/btcwire/msggetdata.go NewMsgGetData 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.Command 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go MsgMemPool.MaxPayloadLength 100.00% (1/1) -github.com/conformal/btcwire/msgmempool.go NewMsgMemPool 100.00% (1/1) -github.com/conformal/btcwire --------------------------------- 100.00% (1184/1184) - From a9293bd32eb0480649a15961290c918050ededa3 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 19 Apr 2014 15:46:03 -0500 Subject: [PATCH 177/219] Add godoc reference badge to README.md. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 1b312de0..feb942e6 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,9 @@ interface with bitcoin peers at the wire protocol level. ## Documentation +[![GoDoc](https://godoc.org/github.com/conformal/btcwire?status.png)] +(http://godoc.org/github.com/conformal/btcwire) + Full `go doc` style documentation for the project can be viewed online without installing this package by using the GoDoc site here: http://godoc.org/github.com/conformal/btcwire From 620cbdeb8e8d91f1977699b928d75f5f2d312f30 Mon Sep 17 00:00:00 2001 From: Javed Khan Date: Sat, 19 Apr 2014 14:27:53 +0530 Subject: [PATCH 178/219] Implemented BIP 0014 format for user agent the new function AddUserAgent adds the user agent to the stack and formats it as per BIP 0014 e.g: "/btcwire:0.1.4/myclient:1.2.3(optional; comments)/" the validation on UserAgent has been moved to a new function validateUserAgent --- README.md | 1 - doc.go | 1 + message_test.go | 4 ++-- msgversion.go | 56 +++++++++++++++++++++++++++++++++++----------- msgversion_test.go | 36 +++++++++++++++++++++++------ 5 files changed, 75 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index feb942e6..2ce3404d 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,6 @@ from a remote peer is: ## TODO -- Implement functions for [BIP 0014](https://en.bitcoin.it/wiki/BIP_0014) - 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) diff --git a/doc.go b/doc.go index a04d077f..ac5e4b45 100644 --- a/doc.go +++ b/doc.go @@ -150,6 +150,7 @@ Bitcoin Improvement Proposals 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) diff --git a/message_test.go b/message_test.go index a3f4cddb..a33fc977 100644 --- a/message_test.go +++ b/message_test.go @@ -51,7 +51,7 @@ func TestMessage(t *testing.T) { t.Errorf("NewNetAddress: %v", err) } me.Timestamp = time.Time{} // Version message has zero value timestamp. - msgVersion := btcwire.NewMsgVersion(me, you, 123123, "/test:0.0.1/", 0) + msgVersion := btcwire.NewMsgVersion(me, you, 123123, 0) msgVerack := btcwire.NewMsgVerAck() msgGetAddr := btcwire.NewMsgGetAddr() @@ -76,7 +76,7 @@ func TestMessage(t *testing.T) { btcnet btcwire.BitcoinNet // Network to use for wire encoding bytes int // Expected num bytes read/written }{ - {msgVersion, msgVersion, pver, btcwire.MainNet, 122}, + {msgVersion, msgVersion, pver, btcwire.MainNet, 125}, {msgVerack, msgVerack, pver, btcwire.MainNet, 24}, {msgGetAddr, msgGetAddr, pver, btcwire.MainNet, 24}, {msgAddr, msgAddr, pver, btcwire.MainNet, 25}, diff --git a/msgversion.go b/msgversion.go index 85feee63..26382625 100644 --- a/msgversion.go +++ b/msgversion.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "net" + "strings" "time" ) @@ -16,6 +17,9 @@ import ( // version message (MsgVersion). const MaxUserAgentLen = 2000 +// DefaultUserAgent for btcwire in the stack +const DefaultUserAgent = "/btcwire:0.1.4/" + // MsgVersion implements the Message interface and represents a bitcoin version // message. It is used for a peer to advertise itself as soon as an outbound // connection is made. The remote peer then uses this information along with @@ -115,10 +119,9 @@ func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error { if err != nil { return err } - if len(userAgent) > MaxUserAgentLen { - str := fmt.Sprintf("user agent too long [len %v, max %v]", - len(userAgent), MaxUserAgentLen) - return messageError("MsgVersion.BtcDecode", str) + err = validateUserAgent(userAgent) + if err != nil { + return err } msg.UserAgent = userAgent } @@ -152,13 +155,12 @@ func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error { // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. // This is part of the Message interface implementation. func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32) error { - if len(msg.UserAgent) > MaxUserAgentLen { - str := fmt.Sprintf("user agent too long [len %v, max %v]", - len(msg.UserAgent), MaxUserAgentLen) - return messageError("MsgVersion.BtcEncode", str) + err := validateUserAgent(msg.UserAgent) + if err != nil { + return err } - err := writeElements(w, msg.ProtocolVersion, msg.Services, + err = writeElements(w, msg.ProtocolVersion, msg.Services, msg.Timestamp.Unix()) if err != nil { return err @@ -224,7 +226,7 @@ func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 { // Message interface using the passed parameters and defaults for the remaining // fields. func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64, - userAgent string, lastBlock int32) *MsgVersion { + lastBlock int32) *MsgVersion { // Limit the timestamp to one second precision since the protocol // doesn't support better. @@ -235,7 +237,7 @@ func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64, AddrYou: *you, AddrMe: *me, Nonce: nonce, - UserAgent: userAgent, + UserAgent: DefaultUserAgent, LastBlock: lastBlock, DisableRelayTx: false, } @@ -244,7 +246,7 @@ func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64, // NewMsgVersionFromConn is a convenience function that extracts the remote // and local address from conn and returns a new bitcoin version message that // conforms to the Message interface. See NewMsgVersion. -func NewMsgVersionFromConn(conn net.Conn, nonce uint64, userAgent string, +func NewMsgVersionFromConn(conn net.Conn, nonce uint64, lastBlock int32) (*MsgVersion, error) { // Don't assume any services until we know otherwise. @@ -259,5 +261,33 @@ func NewMsgVersionFromConn(conn net.Conn, nonce uint64, userAgent string, return nil, err } - return NewMsgVersion(lna, rna, nonce, userAgent, lastBlock), nil + return NewMsgVersion(lna, rna, nonce, lastBlock), nil +} + +// validateUserAgent checks userAgent length against MaxUserAgentLen +func validateUserAgent(userAgent string) error { + if len(userAgent) > MaxUserAgentLen { + str := fmt.Sprintf("user agent too long [len %v, max %v]", + len(userAgent), MaxUserAgentLen) + return messageError("MsgVersion", str) + } + return nil +} + +// AddUserAgent adds a custom user agent +func (msg *MsgVersion) AddUserAgent(name string, version string, + comments ...string) error { + + newUserAgent := fmt.Sprintf("%s:%s", name, version) + if len(comments) != 0 { + newUserAgent = fmt.Sprintf("%s(%s)", newUserAgent, + strings.Join(comments, "; ")) + } + newUserAgent = fmt.Sprintf("%s%s/", msg.UserAgent, newUserAgent) + err := validateUserAgent(newUserAgent) + if err != nil { + return err + } + msg.UserAgent = newUserAgent + return nil } diff --git a/msgversion_test.go b/msgversion_test.go index 5e2c2147..bd8bd3aa 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -21,7 +21,6 @@ func TestVersion(t *testing.T) { pver := btcwire.ProtocolVersion // Create version message data. - userAgent := "/btcdtest:0.0.1/" lastBlock := int32(234234) tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} me, err := btcwire.NewNetAddress(tcpAddrMe, btcwire.SFNodeNetwork) @@ -39,7 +38,7 @@ func TestVersion(t *testing.T) { } // Ensure we get the correct data back out. - msg := btcwire.NewMsgVersion(me, you, nonce, userAgent, lastBlock) + msg := btcwire.NewMsgVersion(me, you, nonce, lastBlock) if msg.ProtocolVersion != int32(pver) { t.Errorf("NewMsgVersion: wrong protocol version - got %v, want %v", msg.ProtocolVersion, pver) @@ -56,9 +55,9 @@ func TestVersion(t *testing.T) { t.Errorf("NewMsgVersion: wrong nonce - got %v, want %v", msg.Nonce, nonce) } - if msg.UserAgent != userAgent { + if msg.UserAgent != btcwire.DefaultUserAgent { t.Errorf("NewMsgVersion: wrong user agent - got %v, want %v", - msg.UserAgent, userAgent) + msg.UserAgent, btcwire.DefaultUserAgent) } if msg.LastBlock != lastBlock { t.Errorf("NewMsgVersion: wrong last block - got %v, want %v", @@ -69,6 +68,29 @@ func TestVersion(t *testing.T) { "default - got %v, want %v", msg.DisableRelayTx, false) } + msg.AddUserAgent("myclient", "1.2.3", "optional", "comments") + customUserAgent := btcwire.DefaultUserAgent + "myclient:1.2.3(optional; comments)/" + if msg.UserAgent != customUserAgent { + t.Errorf("AddUserAgent: wrong user agent - got %s, want %s", + msg.UserAgent, customUserAgent) + } + + msg.AddUserAgent("mygui", "3.4.5") + customUserAgent += "mygui:3.4.5/" + if msg.UserAgent != customUserAgent { + t.Errorf("AddUserAgent: wrong user agent - got %s, want %s", + msg.UserAgent, customUserAgent) + } + + // accounting for ":", "/" + err = msg.AddUserAgent(strings.Repeat("t", + btcwire.MaxUserAgentLen-len(customUserAgent)-2+1), "") + if _, ok := err.(*btcwire.MessageError); !ok { + t.Errorf("AddUserAgent: expected error not received "+ + "- got %v, want %T", err, btcwire.MessageError{}) + + } + // Version message should not have any services set by default. if msg.Services != 0 { t.Errorf("NewMsgVersion: wrong default services - got %v, want %v", @@ -111,7 +133,7 @@ func TestVersion(t *testing.T) { // Use a fake connection. conn := &fakeConn{localAddr: tcpAddrMe, remoteAddr: tcpAddrYou} - msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, userAgent, lastBlock) + msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, lastBlock) if err != nil { t.Errorf("NewMsgVersionFromConn: %v", err) } @@ -131,7 +153,7 @@ func TestVersion(t *testing.T) { localAddr: &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333}, remoteAddr: tcpAddrYou, } - msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, userAgent, lastBlock) + msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, lastBlock) if err != btcwire.ErrInvalidNetAddr { t.Errorf("NewMsgVersionFromConn: expected error not received "+ "- got %v, want %v", err, btcwire.ErrInvalidNetAddr) @@ -142,7 +164,7 @@ func TestVersion(t *testing.T) { localAddr: tcpAddrMe, remoteAddr: &net.UDPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333}, } - msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, userAgent, lastBlock) + msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, lastBlock) if err != btcwire.ErrInvalidNetAddr { t.Errorf("NewMsgVersionFromConn: expected error not received "+ "- got %v, want %v", err, btcwire.ErrInvalidNetAddr) From d848bc453bebc744d17d6db7d2545f60be215ca4 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 20 Apr 2014 15:01:39 -0500 Subject: [PATCH 179/219] Improve comments on new AddUserAgent function. --- msgversion.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/msgversion.go b/msgversion.go index 26382625..f4ca826a 100644 --- a/msgversion.go +++ b/msgversion.go @@ -274,7 +274,9 @@ func validateUserAgent(userAgent string) error { return nil } -// AddUserAgent adds a custom user agent +// AddUserAgent adds a user agent to the user agent string for the version +// message. The version string is not defined to any strict format, although +// it is recommended to use the form "major.minor.revision" e.g. "2.6.41". func (msg *MsgVersion) AddUserAgent(name string, version string, comments ...string) error { From 8857485fa8c91f62b33b6179c45898762787ada6 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 20 Apr 2014 23:24:56 -0500 Subject: [PATCH 180/219] Remove note that is no longer true. The code was updated to automatically handle the transaction count in the block header without having the additional field some time ago. This comment was outdated. --- msgblock.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/msgblock.go b/msgblock.go index 9b2fe373..33186d8f 100644 --- a/msgblock.go +++ b/msgblock.go @@ -37,13 +37,6 @@ type TxLoc struct { // MsgBlock implements the Message interface and represents a bitcoin // block message. It is used to deliver block and transaction information in // response to a getdata message (MsgGetData) for a given block hash. -// -// NOTE: Unlike the other message types which contain slices, the number of -// transactions has a specific entry (Header.TxnCount) that must be kept in -// sync. The AddTransaction and ClearTransactions functions properly sync the -// value, but if you are manually modifying the public members, you will need -// to ensure you update the Header.TxnCount when you add and remove -// transactions. type MsgBlock struct { Header BlockHeader Transactions []*MsgTx From 2cc89bbf5ba47baf9f8f60d7d9408fe85474fd53 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 21 Apr 2014 10:53:22 -0500 Subject: [PATCH 181/219] Remove function name from ShaHash error message. This makes golint happy. --- shahash.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shahash.go b/shahash.go index 466aef58..b6ac8d11 100644 --- a/shahash.go +++ b/shahash.go @@ -47,8 +47,8 @@ func (hash *ShaHash) Bytes() []byte { func (hash *ShaHash) SetBytes(newHash []byte) error { nhlen := len(newHash) if nhlen != HashSize { - return fmt.Errorf("ShaHash: invalid sha length of %v, want %v", - nhlen, HashSize) + return fmt.Errorf("invalid sha length of %v, want %v", nhlen, + HashSize) } copy(hash[:], newHash[0:HashSize]) From bdec7f8abb55c26d87f2aecc7d5ea4844bffaa73 Mon Sep 17 00:00:00 2001 From: Javed Khan Date: Fri, 25 Apr 2014 01:18:22 +0530 Subject: [PATCH 182/219] Implemented alert message serialize/deserialize * Introduced common methods readVarBytes, writeVarBytes. * Added type Alert which knows how to deserialize the serialized payload and also serialize itself back. * Updated MsgAlert BtcEncode/BtcDecode methods to handle the new Alert. * Sane limits are placed on variable length fields like SetCancel and SetSubVer --- common.go | 41 ++++++ common_test.go | 133 +++++++++++++++++ internal_test.go | 20 +++ message_test.go | 2 +- msgalert.go | 361 +++++++++++++++++++++++++++++++++++++++++++++-- msgalert_test.go | 325 +++++++++++++++++++++++++++++++++++++----- msgtx.go | 57 +------- 7 files changed, 839 insertions(+), 100 deletions(-) diff --git a/common.go b/common.go index 203a3a4e..eb337dc9 100644 --- a/common.go +++ b/common.go @@ -281,6 +281,32 @@ func writeElements(w io.Writer, elements ...interface{}) error { return nil } +// readVarBytes reads a variable length byte array +func readVarBytes(r io.Reader, pver uint32, maxAllowed uint32, + fieldName string) ([]byte, error) { + + count, err := readVarInt(r, pver) + if err != nil { + return nil, err + } + + // Prevent byte array larger than the max message size. It would + // be possible to cause memory exhaustion and panics without a sane + // upper bound on this count. + if count > uint64(maxAllowed) { + str := fmt.Sprintf("%s is larger than the max allowed size "+ + "[count %d, max %d]", fieldName, count, maxAllowed) + return nil, messageError("readVarBytes", str) + } + + b := make([]byte, count) + _, err = io.ReadFull(r, b) + if err != nil { + return nil, err + } + return b, nil +} + // readVarInt reads a variable length integer from r and returns it as a uint64. func readVarInt(r io.Reader, pver uint32) (uint64, error) { var b [8]byte @@ -320,6 +346,21 @@ func readVarInt(r io.Reader, pver uint32) (uint64, error) { return rv, nil } +// writeVarBytes writes a variable length byte array +func writeVarBytes(w io.Writer, pver uint32, bytes []byte) error { + slen := uint64(len(bytes)) + err := writeVarInt(w, pver, slen) + if err != nil { + return err + } + + _, err = w.Write(bytes) + if err != nil { + return err + } + return nil +} + // writeVarInt serializes val to w using a variable number of bytes depending // on its value. func writeVarInt(w io.Writer, pver uint32, val uint64) error { diff --git a/common_test.go b/common_test.go index 577d3190..3a534d47 100644 --- a/common_test.go +++ b/common_test.go @@ -501,6 +501,139 @@ func TestVarStringOverflowErrors(t *testing.T) { } +// TestVarBytesWire tests wire encode and decode for variable length byte array. +func TestVarBytesWire(t *testing.T) { + pver := btcwire.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 := btcwire.TstWriteVarBytes(&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.NewBuffer(test.buf) + val, err := btcwire.TstReadVarBytes(rbuf, test.pver, btcwire.MaxMessagePayload, + "alert serialized 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 := btcwire.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 := btcwire.TstWriteVarBytes(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 = btcwire.TstReadVarBytes(r, test.pver, btcwire.MaxMessagePayload, + "alert serialized 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 := btcwire.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, &btcwire.MessageError{}}, + {[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + pver, &btcwire.MessageError{}}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Decode from wire format. + rbuf := bytes.NewBuffer(test.buf) + _, err := btcwire.TstReadVarBytes(rbuf, test.pver, btcwire.MaxMessagePayload, + "alert serialized 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 diff --git a/internal_test.go b/internal_test.go index 2bb0c380..031d3068 100644 --- a/internal_test.go +++ b/internal_test.go @@ -19,6 +19,14 @@ import ( // the test package. const MaxMessagePayload uint32 = maxMessagePayload +// MaxCountSetCancel makes the internal maxCountSetCancel constant available to +// the test package. +const MaxCountSetCancel uint32 = maxCountSetCancel + +// MaxCountSetSubVer makes the internal maxCountSetSubVer constant available to +// the test package. +const MaxCountSetSubVer uint32 = maxCountSetSubVer + // CommandSize makes the internal commandSize constant available to the test // package. const CommandSize = commandSize @@ -65,6 +73,18 @@ func TstWriteVarString(w io.Writer, pver uint32, str string) error { return writeVarString(w, pver, str) } +// TstReadVarBytes makes the internal readVarBytes function available to the +// test package. +func TstReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32, fieldName string) ([]byte, error) { + return readVarBytes(r, pver, maxAllowed, fieldName) +} + +// TstWriteVarBytes makes the internal writeVarBytes function available to the +// test package. +func TstWriteVarBytes(w io.Writer, pver uint32, bytes []byte) error { + return writeVarBytes(w, pver, bytes) +} + // TstReadNetAddress makes the internal readNetAddress function available to // the test package. func TstReadNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error { diff --git a/message_test.go b/message_test.go index a33fc977..c79f4e8d 100644 --- a/message_test.go +++ b/message_test.go @@ -66,7 +66,7 @@ func TestMessage(t *testing.T) { msgPong := btcwire.NewMsgPong(123123) msgGetHeaders := btcwire.NewMsgGetHeaders() msgHeaders := btcwire.NewMsgHeaders() - msgAlert := btcwire.NewMsgAlert("payload", "signature") + msgAlert := btcwire.NewMsgAlert([]byte("payload"), []byte("signature")) msgMemPool := btcwire.NewMsgMemPool() tests := []struct { diff --git a/msgalert.go b/msgalert.go index fdb1d66d..2bd45dfd 100644 --- a/msgalert.go +++ b/msgalert.go @@ -5,9 +5,317 @@ package btcwire import ( + "bytes" + "fmt" "io" ) +// MsgAlert contains a payload and a signature: +// +// =============================================== +// | Field | Data Type | Size | +// =============================================== +// | payload | []uchar | ? | +// ----------------------------------------------- +// | signature | []uchar | ? | +// ----------------------------------------------- +// +// Here payload is an Alert serialized into a byte array to ensure that +// versions using incompatible alert formats can still relay +// alerts among one another. +// +// An Alert is the payload deserialized as follows: +// +// =============================================== +// | Field | Data Type | Size | +// =============================================== +// | Version | int32 | 4 | +// ----------------------------------------------- +// | RelayUntil | int64 | 8 | +// ----------------------------------------------- +// | Expiration | int64 | 8 | +// ----------------------------------------------- +// | ID | int32 | 4 | +// ----------------------------------------------- +// | Cancel | int32 | 4 | +// ----------------------------------------------- +// | SetCancel | set | ? | +// ----------------------------------------------- +// | MinVer | int32 | 4 | +// ----------------------------------------------- +// | MaxVer | int32 | 4 | +// ----------------------------------------------- +// | SetSubVer | set | ? | +// ----------------------------------------------- +// | Priority | int32 | 4 | +// ----------------------------------------------- +// | Comment | string | ? | +// ----------------------------------------------- +// | StatusBar | string | ? | +// ----------------------------------------------- +// | Reserved | string | ? | +// ----------------------------------------------- +// | Total (Fixed) | 45 | +// ----------------------------------------------- +// +// note: +// * string is a VarString i.e VarInt length followed by the string itself +// * set is a VarInt followed by as many number of strings +// * set is a VarInt followed by as many number of ints +// * fixedAlertSize = 40 + 5*min(VarInt) = 40 + 5*1 = 45 + +// Now we can define bounds on Alert size, SetCancel and SetSubVer + +// Fixed size of the alert payload +const fixedAlertSize = 45 + +// Max size of the ECDSA signature +// note: since this size is fixed and < 255, size of VarInt +// required = 1 (fits in uint8) +const maxSignatureSize = 72 + +// Maximum size of the alert +// MessagePayload = VarInt(Alert) + Alert + VarInt(Signature) + Signature +// maxMessagePayload = maxAlertSize + max(VarInt) + maxSignatureSize + 1 +const maxAlertSize = maxMessagePayload - maxSignatureSize - MaxVarIntPayload - 1 + +// Maximum number of Cancel IDs from SetCancel to read +// maxAlertSize = fixedAlertSize + max(SetCancel) + max(SetSubVer) + 3*(string) +// for caculating maximum number of Cancel IDs, set all other variable sizes to 0 +// maxAlertSize = fixedAlertSize + (MaxVarIntPayload-1) + x*sizeOf(int32) +// x = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 4 +const maxCountSetCancel = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 4 + +// Maximum number of subversions from SetSubVer to read +// maxAlertSize = fixedAlertSize + max(SetCancel) + max(SetSubVer) + 3*(string) +// for caculating maximum number of subversions, set all other variable sizes to 0 +// maxAlertSize = fixedAlertSize + (MaxVarIntPayload-1) + x*sizeOf(string) +// x = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / sizeOf(string) +// subversion would typically be something like "/Satoshi:0.7.2/" (15 bytes) +// so assuming < 255 bytes, sizeOf(string) = sizeOf(uint8) + 255 = 256 +const maxCountSetSubVer = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 256 + +// Alert contains the data deserialized from the MsgAlert payload +type Alert struct { + + // Alert format version + Version int32 + + // Timestamp beyond which nodes should stop relaying this alert + RelayUntil int64 + + // Timestamp beyond which this alert is no longer in effect and + // should be ignored + Expiration int64 + + // A unique ID number for this alert + ID int32 + + // All alerts with an ID less than or equal to this number should + // cancelled, deleted and not accepted in the future + Cancel int32 + + // All alert IDs contained in this set should be cancelled as above + SetCancel []int32 + + // This alert only applies to versions greater than or equal to this + // version. Other versions should still relay it. + MinVer int32 + + // This alert only applies to versions less than or equal to this version. + // Other versions should still relay it. + MaxVer int32 + + // If this set contains any elements, then only nodes that have their + // subVer contained in this set are affected by the alert. Other versions + // should still relay it. + SetSubVer []string + + // Relative priority compared to other alerts + Priority int32 + + // A comment on the alert that is not displayed + Comment string + + // The alert message that is displayed to the user + StatusBar string + + // Reserved + Reserved string +} + +// NewAlert returns an new Alert with values provided +func NewAlert(version int32, relayuntil int64, expiration int64, + id int32, cancel int32, setcancel []int32, minver int32, + maxver int32, setsubver []string, priority int32, comment string, + statusbar string, reserved string) *Alert { + return &Alert{ + Version: version, + RelayUntil: relayuntil, + Expiration: expiration, + ID: id, + Cancel: cancel, + SetCancel: setcancel, + MinVer: minver, + MaxVer: maxver, + SetSubVer: setsubver, + Priority: priority, + Comment: comment, + StatusBar: statusbar, + Reserved: reserved, + } +} + +// NewAlertFromPayload returns an Alert with values deserialized +// from the serializedpayload +func NewAlertFromPayload(serializedpayload []byte, pver uint32) (*Alert, error) { + var alert Alert + r := bytes.NewReader(serializedpayload) + err := alert.Deserialize(r, pver) + if err != nil { + return nil, err + } + return &alert, nil +} + +// Serialize writes a serialized byte array of the Alert +func (alert *Alert) Serialize(w io.Writer, pver uint32) error { + err := writeElements(w, &alert.Version, + &alert.RelayUntil, &alert.Expiration, &alert.ID, &alert.Cancel) + if err != nil { + return err + } + + count := len(alert.SetCancel) + if count > maxCountSetCancel { + str := fmt.Sprintf("too many cancel alert IDs for alert "+ + "[count %v, max %v]", count, maxCountSetCancel) + return messageError("Alert.Serialize", str) + } + err = writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + for i := 0; i < int(count); i++ { + err = writeElement(w, &alert.SetCancel[i]) + if err != nil { + return err + } + } + + err = writeElements(w, &alert.MinVer, &alert.MaxVer) + if err != nil { + return err + } + + count = len(alert.SetSubVer) + if count > maxCountSetSubVer { + str := fmt.Sprintf("too many sub versions for alert "+ + "[count %v, max %v]", count, maxCountSetSubVer) + return messageError("Alert.Serialize", str) + } + err = writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + for i := 0; i < int(count); i++ { + err = writeVarString(w, pver, alert.SetSubVer[i]) + if err != nil { + return err + } + } + + err = writeElement(w, &alert.Priority) + if err != nil { + return err + } + err = writeVarString(w, pver, alert.Comment) + if err != nil { + return err + } + err = writeVarString(w, pver, alert.StatusBar) + if err != nil { + return err + } + err = writeVarString(w, pver, alert.Reserved) + if err != nil { + return err + } + return nil +} + +// Deserialize reads a byte array, deserializes +// it and updates the Alert +func (alert *Alert) Deserialize(r io.Reader, pver uint32) error { + err := readElements(r, &alert.Version, &alert.RelayUntil, + &alert.Expiration, &alert.ID, &alert.Cancel) + if err != nil { + return err + } + + // SetCancel: first read a VarInt that contains + // count - the number of Cancel IDs, then + // iterate count times and read them + count, err := readVarInt(r, pver) + if err != nil { + return err + } + if count > maxCountSetCancel { + str := fmt.Sprintf("too many cancel alert IDs for alert "+ + "[count %v, max %v]", count, maxCountSetCancel) + return messageError("Alert.Deserialize", str) + } + alert.SetCancel = make([]int32, count) + for i := 0; i < int(count); i++ { + err := readElement(r, &alert.SetCancel[i]) + if err != nil { + return err + } + } + + err = readElements(r, &alert.MinVer, &alert.MaxVer) + if err != nil { + return err + } + + // SetSubVer: similar to SetCancel + // but read count number of sub-version strings + count, err = readVarInt(r, pver) + if err != nil { + return err + } + if count > maxCountSetSubVer { + str := fmt.Sprintf("too many sub versions for alert "+ + "[count %v, max %v]", count, maxCountSetSubVer) + return messageError("Alert.Deserialize", str) + } + alert.SetSubVer = make([]string, count) + for i := 0; i < int(count); i++ { + alert.SetSubVer[i], err = readVarString(r, pver) + if err != nil { + return err + } + } + + err = readElement(r, &alert.Priority) + if err != nil { + return err + } + alert.Comment, err = readVarString(r, pver) + if err != nil { + return err + } + alert.StatusBar, err = readVarString(r, pver) + if err != nil { + return err + } + alert.Reserved, err = readVarString(r, pver) + if err != nil { + return err + } + return nil +} + // MsgAlert implements the Message interface and defines a bitcoin alert // message. // @@ -15,24 +323,36 @@ import ( // display if the signature matches the key. bitcoind/bitcoin-qt only checks // against a signature from the core developers. type MsgAlert struct { - // PayloadBlob is the alert payload serialized as a string so that the + // SerializedPayload is the alert payload serialized as a string so that the // version can change but the Alert can still be passed on by older // clients. - PayloadBlob string + SerializedPayload []byte // Signature is the ECDSA signature of the message. - Signature string + Signature []byte + + // Deserialized Payload + Payload *Alert } // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. // This is part of the Message interface implementation. func (msg *MsgAlert) BtcDecode(r io.Reader, pver uint32) error { var err error - msg.PayloadBlob, err = readVarString(r, pver) + + msg.SerializedPayload, err = readVarBytes(r, pver, maxMessagePayload, + "alert serialized payload") if err != nil { return err } - msg.Signature, err = readVarString(r, pver) + + msg.Payload, err = NewAlertFromPayload(msg.SerializedPayload, pver) + if err != nil { + msg.Payload = nil + } + + msg.Signature, err = readVarBytes(r, pver, maxMessagePayload, + "alert signature") if err != nil { return err } @@ -44,15 +364,33 @@ func (msg *MsgAlert) BtcDecode(r io.Reader, pver uint32) error { // This is part of the Message interface implementation. func (msg *MsgAlert) BtcEncode(w io.Writer, pver uint32) error { var err error - err = writeVarString(w, pver, msg.PayloadBlob) + var serializedpayload []byte + if msg.Payload != nil { + // try to Serialize Payload if possible + r := new(bytes.Buffer) + err = msg.Payload.Serialize(r, pver) + if err != nil { + // Serialize failed - ignore & fallback + // to SerializedPayload + serializedpayload = msg.SerializedPayload + } else { + serializedpayload = r.Bytes() + } + } else { + serializedpayload = msg.SerializedPayload + } + slen := uint64(len(serializedpayload)) + if slen == 0 { + return messageError("MsgAlert.BtcEncode", "empty serialized payload") + } + err = writeVarBytes(w, pver, serializedpayload) if err != nil { return err } - err = writeVarString(w, pver, msg.Signature) + err = writeVarBytes(w, pver, msg.Signature) if err != nil { return err } - return nil } @@ -72,9 +410,10 @@ func (msg *MsgAlert) MaxPayloadLength(pver uint32) uint32 { // NewMsgAlert returns a new bitcoin alert message that conforms to the Message // interface. See MsgAlert for details. -func NewMsgAlert(payloadblob string, signature string) *MsgAlert { +func NewMsgAlert(serializedpayload []byte, signature []byte) *MsgAlert { return &MsgAlert{ - PayloadBlob: payloadblob, - Signature: signature, + SerializedPayload: serializedpayload, + Signature: signature, + Payload: nil, } } diff --git a/msgalert_test.go b/msgalert_test.go index 3e9e3ce5..1ae012c9 100644 --- a/msgalert_test.go +++ b/msgalert_test.go @@ -13,19 +13,19 @@ import ( "testing" ) -// TestAlert tests the MsgAlert API. -func TestAlert(t *testing.T) { +// TestMsgAlert tests the MsgAlert API. +func TestMsgAlert(t *testing.T) { pver := btcwire.ProtocolVersion - payloadblob := "some message" - signature := "some sig" + serializedpayload := []byte("some message") + signature := []byte("some sig") // Ensure we get the same payload and signature back out. - msg := btcwire.NewMsgAlert(payloadblob, signature) - if msg.PayloadBlob != payloadblob { - t.Errorf("NewMsgAlert: wrong payloadblob - got %v, want %v", - msg.PayloadBlob, payloadblob) + msg := btcwire.NewMsgAlert(serializedpayload, signature) + if !reflect.DeepEqual(msg.SerializedPayload, serializedpayload) { + t.Errorf("NewMsgAlert: wrong serializedpayload - got %v, want %v", + msg.SerializedPayload, serializedpayload) } - if msg.Signature != signature { + if !reflect.DeepEqual(msg.Signature, signature) { t.Errorf("NewMsgAlert: wrong signature - got %v, want %v", msg.Signature, signature) } @@ -46,14 +46,46 @@ func TestAlert(t *testing.T) { maxPayload, wantPayload) } - return + // Test BtcEncode with Payload == nil + var buf bytes.Buffer + err := msg.BtcEncode(&buf, pver) + if err != nil { + t.Error(err.Error()) + } + // expected = 0x0c + serializedpayload + 0x08 + signature + expectedBuf := append([]byte{0x0c}, serializedpayload...) + expectedBuf = append(expectedBuf, []byte{0x08}...) + expectedBuf = append(expectedBuf, signature...) + if !bytes.Equal(buf.Bytes(), expectedBuf) { + t.Errorf("BtcEncode got: %s want: %s", + spew.Sdump(buf.Bytes()), spew.Sdump(expectedBuf)) + } + + // Test BtcEncode with Payload != nil + // note: Payload is an empty Alert but not nil + msg.Payload = new(btcwire.Alert) + buf = *new(bytes.Buffer) + err = msg.BtcEncode(&buf, pver) + if err != nil { + t.Error(err.Error()) + } + // empty Alert is 45 null bytes, see Alert comments + // for details + // expected = 0x2d + 45*0x00 + 0x08 + signature + expectedBuf = append([]byte{0x2d}, bytes.Repeat([]byte{0x00}, 45)...) + expectedBuf = append(expectedBuf, []byte{0x08}...) + expectedBuf = append(expectedBuf, signature...) + if !bytes.Equal(buf.Bytes(), expectedBuf) { + t.Errorf("BtcEncode got: %s want: %s", + spew.Sdump(buf.Bytes()), spew.Sdump(expectedBuf)) + } } -// TestAlertWire tests the MsgAlert wire encode and decode for various protocol +// TestMsgAlertWire tests the MsgAlert wire encode and decode for various protocol // versions. -func TestAlertWire(t *testing.T) { - baseAlert := btcwire.NewMsgAlert("some payload", "somesig") - baseAlertEncoded := []byte{ +func TestMsgAlertWire(t *testing.T) { + baseMsgAlert := btcwire.NewMsgAlert([]byte("some payload"), []byte("somesig")) + baseMsgAlertEncoded := []byte{ 0x0c, // Varint for payload length 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, // "some payload" @@ -69,41 +101,41 @@ func TestAlertWire(t *testing.T) { }{ // Latest protocol version. { - baseAlert, - baseAlert, - baseAlertEncoded, + baseMsgAlert, + baseMsgAlert, + baseMsgAlertEncoded, btcwire.ProtocolVersion, }, // Protocol version BIP0035Version. { - baseAlert, - baseAlert, - baseAlertEncoded, + baseMsgAlert, + baseMsgAlert, + baseMsgAlertEncoded, btcwire.BIP0035Version, }, // Protocol version BIP0031Version. { - baseAlert, - baseAlert, - baseAlertEncoded, + baseMsgAlert, + baseMsgAlert, + baseMsgAlertEncoded, btcwire.BIP0031Version, }, // Protocol version NetAddressTimeVersion. { - baseAlert, - baseAlert, - baseAlertEncoded, + baseMsgAlert, + baseMsgAlert, + baseMsgAlertEncoded, btcwire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion. { - baseAlert, - baseAlert, - baseAlertEncoded, + baseMsgAlert, + baseMsgAlert, + baseMsgAlertEncoded, btcwire.MultipleAddressVersion, }, } @@ -139,13 +171,13 @@ func TestAlertWire(t *testing.T) { } } -// TestAlertWireErrors performs negative tests against wire encode and decode +// TestMsgAlertWireErrors performs negative tests against wire encode and decode // of MsgAlert to confirm error paths work correctly. -func TestAlertWireErrors(t *testing.T) { +func TestMsgAlertWireErrors(t *testing.T) { pver := btcwire.ProtocolVersion - baseAlert := btcwire.NewMsgAlert("some payload", "somesig") - baseAlertEncoded := []byte{ + baseMsgAlert := btcwire.NewMsgAlert([]byte("some payload"), []byte("somesig")) + baseMsgAlertEncoded := []byte{ 0x0c, // Varint for payload length 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, // "some payload" @@ -162,13 +194,13 @@ func TestAlertWireErrors(t *testing.T) { readErr error // Expected read error }{ // Force error in payload length. - {baseAlert, baseAlertEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + {baseMsgAlert, baseMsgAlertEncoded, pver, 0, io.ErrShortWrite, io.EOF}, // Force error in payload. - {baseAlert, baseAlertEncoded, pver, 1, io.ErrShortWrite, io.EOF}, + {baseMsgAlert, baseMsgAlertEncoded, pver, 1, io.ErrShortWrite, io.EOF}, // Force error in signature length. - {baseAlert, baseAlertEncoded, pver, 13, io.ErrShortWrite, io.EOF}, + {baseMsgAlert, baseMsgAlertEncoded, pver, 13, io.ErrShortWrite, io.EOF}, // Force error in signature. - {baseAlert, baseAlertEncoded, pver, 14, io.ErrShortWrite, io.EOF}, + {baseMsgAlert, baseMsgAlertEncoded, pver, 14, io.ErrShortWrite, io.EOF}, } t.Logf("Running %d tests", len(tests)) @@ -212,4 +244,223 @@ func TestAlertWireErrors(t *testing.T) { } } } + + // Test Error on empty Payload + baseMsgAlert.SerializedPayload = []byte{} + w := new(bytes.Buffer) + err := baseMsgAlert.BtcEncode(w, pver) + if _, ok := err.(*btcwire.MessageError); !ok { + t.Errorf("MsgAlert.BtcEncode wrong error got: %T, want: %T", + err, btcwire.MessageError{}) + } + + // Test Payload Serialize error + // overflow the max number of elements in SetCancel + baseMsgAlert.Payload = new(btcwire.Alert) + baseMsgAlert.Payload.SetCancel = make([]int32, btcwire.MaxCountSetCancel+1) + buf := *new(bytes.Buffer) + err = baseMsgAlert.BtcEncode(&buf, pver) + if _, ok := err.(*btcwire.MessageError); !ok { + t.Errorf("MsgAlert.BtcEncode wrong error got: %T, want: %T", + err, btcwire.MessageError{}) + } + + // overflow the max number of elements in SetSubVer + baseMsgAlert.Payload = new(btcwire.Alert) + baseMsgAlert.Payload.SetSubVer = make([]string, btcwire.MaxCountSetSubVer+1) + buf = *new(bytes.Buffer) + err = baseMsgAlert.BtcEncode(&buf, pver) + if _, ok := err.(*btcwire.MessageError); !ok { + t.Errorf("MsgAlert.BtcEncode wrong error got: %T, want: %T", + err, btcwire.MessageError{}) + } +} + +// TestAlert tests serialization and deserialization +// of the payload to Alert +func TestAlert(t *testing.T) { + pver := btcwire.ProtocolVersion + alert := btcwire.NewAlert( + 1, 1337093712, 1368628812, 1015, + 1013, []int32{1014}, 0, 40599, []string{"/Satoshi:0.7.2/"}, 5000, "", + "URGENT: upgrade required, see http://bitcoin.org/dos for details", "", + ) + w := new(bytes.Buffer) + err := alert.Serialize(w, pver) + if err != nil { + t.Error(err.Error()) + } + serializedpayload := w.Bytes() + newAlert, err := btcwire.NewAlertFromPayload(serializedpayload, pver) + if err != nil { + t.Error(err.Error()) + } + + if alert.Version != newAlert.Version { + t.Errorf("NewAlertFromPayload: wrong Version - got %v, want %v ", + alert.Version, newAlert.Version) + } + if alert.RelayUntil != newAlert.RelayUntil { + t.Errorf("NewAlertFromPayload: wrong RelayUntil - got %v, want %v ", + alert.RelayUntil, newAlert.RelayUntil) + } + if alert.Expiration != newAlert.Expiration { + t.Errorf("NewAlertFromPayload: wrong Expiration - got %v, want %v ", + alert.Expiration, newAlert.Expiration) + } + if alert.ID != newAlert.ID { + t.Errorf("NewAlertFromPayload: wrong ID - got %v, want %v ", + alert.ID, newAlert.ID) + } + if alert.Cancel != newAlert.Cancel { + t.Errorf("NewAlertFromPayload: wrong Cancel - got %v, want %v ", + alert.Cancel, newAlert.Cancel) + } + if len(alert.SetCancel) != len(newAlert.SetCancel) { + t.Errorf("NewAlertFromPayload: wrong number of SetCancel - got %v, want %v ", + len(alert.SetCancel), len(newAlert.SetCancel)) + } + for i := 0; i < len(alert.SetCancel); i++ { + if alert.SetCancel[i] != newAlert.SetCancel[i] { + t.Errorf("NewAlertFromPayload: wrong SetCancel[%v] - got %v, want %v ", + len(alert.SetCancel), alert.SetCancel[i], newAlert.SetCancel[i]) + } + } + if alert.MinVer != newAlert.MinVer { + t.Errorf("NewAlertFromPayload: wrong MinVer - got %v, want %v ", + alert.MinVer, newAlert.MinVer) + } + if alert.MaxVer != newAlert.MaxVer { + t.Errorf("NewAlertFromPayload: wrong MaxVer - got %v, want %v ", + alert.MaxVer, newAlert.MaxVer) + } + if len(alert.SetSubVer) != len(newAlert.SetSubVer) { + t.Errorf("NewAlertFromPayload: wrong number of SetSubVer - got %v, want %v ", + len(alert.SetSubVer), len(newAlert.SetSubVer)) + } + for i := 0; i < len(alert.SetSubVer); i++ { + if alert.SetSubVer[i] != newAlert.SetSubVer[i] { + t.Errorf("NewAlertFromPayload: wrong SetSubVer[%v] - got %v, want %v ", + len(alert.SetSubVer), alert.SetSubVer[i], newAlert.SetSubVer[i]) + } + } + if alert.Priority != newAlert.Priority { + t.Errorf("NewAlertFromPayload: wrong Priority - got %v, want %v ", + alert.Priority, newAlert.Priority) + } + if alert.Comment != newAlert.Comment { + t.Errorf("NewAlertFromPayload: wrong Comment - got %v, want %v ", + alert.Comment, newAlert.Comment) + } + if alert.StatusBar != newAlert.StatusBar { + t.Errorf("NewAlertFromPayload: wrong StatusBar - got %v, want %v ", + alert.StatusBar, newAlert.StatusBar) + } + if alert.Reserved != newAlert.Reserved { + t.Errorf("NewAlertFromPayload: wrong Reserved - got %v, want %v ", + alert.Reserved, newAlert.Reserved) + } +} + +// TestAlertErrors performs negative tests against payload serialization, +// deserialization of Alert to confirm error paths work correctly. +func TestAlertErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + + baseAlert := btcwire.NewAlert( + 1, 1337093712, 1368628812, 1015, + 1013, []int32{1014}, 0, 40599, []string{"/Satoshi:0.7.2/"}, 5000, "", + "URGENT", "", + ) + baseAlertEncoded := []byte{ + 0x01, 0x00, 0x00, 0x00, 0x50, 0x6e, 0xb2, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x9e, 0x93, 0x51, //|....Pn.O....L..Q| + 0x00, 0x00, 0x00, 0x00, 0xf7, 0x03, 0x00, 0x00, 0xf5, 0x03, 0x00, 0x00, 0x01, 0xf6, 0x03, 0x00, //|................| + 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x9e, 0x00, 0x00, 0x01, 0x0f, 0x2f, 0x53, 0x61, 0x74, 0x6f, //|.........../Sato| + 0x73, 0x68, 0x69, 0x3a, 0x30, 0x2e, 0x37, 0x2e, 0x32, 0x2f, 0x88, 0x13, 0x00, 0x00, 0x00, 0x06, //|shi:0.7.2/......| + 0x55, 0x52, 0x47, 0x45, 0x4e, 0x54, 0x00, //|URGENT.| + } + tests := []struct { + in *btcwire.Alert // 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 + {baseAlert, baseAlertEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in SetCancel VarInt. + {baseAlert, baseAlertEncoded, pver, 28, io.ErrShortWrite, io.EOF}, + // Force error in SetCancel ints. + {baseAlert, baseAlertEncoded, pver, 29, io.ErrShortWrite, io.EOF}, + // Force error in MinVer + {baseAlert, baseAlertEncoded, pver, 40, io.ErrShortWrite, io.EOF}, + // Force error in SetSubVer string VarInt. + {baseAlert, baseAlertEncoded, pver, 41, io.ErrShortWrite, io.EOF}, + // Force error in SetSubVer strings. + {baseAlert, baseAlertEncoded, pver, 48, io.ErrShortWrite, io.EOF}, + // Force error in Priority + {baseAlert, baseAlertEncoded, pver, 60, io.ErrShortWrite, io.EOF}, + // Force error in Comment string. + {baseAlert, baseAlertEncoded, pver, 62, io.ErrShortWrite, io.EOF}, + // Force error in StatusBar string. + {baseAlert, baseAlertEncoded, pver, 64, io.ErrShortWrite, io.EOF}, + // Force error in Reserved string. + {baseAlert, baseAlertEncoded, pver, 70, io.ErrShortWrite, io.EOF}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + w := newFixedWriter(test.max) + err := test.in.Serialize(w, test.pver) + if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) { + t.Errorf("Alert.Serialize #%d wrong error got: %v, want: %v", + i, err, test.writeErr) + continue + } + + var alert btcwire.Alert + r := newFixedReader(test.max, test.buf) + err = alert.Deserialize(r, test.pver) + if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { + t.Errorf("Alert.Deserialize #%d wrong error got: %v, want: %v", + i, err, test.readErr) + continue + } + } + + // overflow the max number of elements in SetCancel + // maxCountSetCancel + 1 == 8388575 == \xdf\xff\x7f\x00 + // replace bytes 29-33 + badAlertEncoded := []byte{ + 0x01, 0x00, 0x00, 0x00, 0x50, 0x6e, 0xb2, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x9e, 0x93, 0x51, //|....Pn.O....L..Q| + 0x00, 0x00, 0x00, 0x00, 0xf7, 0x03, 0x00, 0x00, 0xf5, 0x03, 0x00, 0x00, 0xfe, 0xdf, 0xff, 0x7f, //|................| + 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x9e, 0x00, 0x00, 0x01, 0x0f, 0x2f, 0x53, 0x61, 0x74, 0x6f, //|.........../Sato| + 0x73, 0x68, 0x69, 0x3a, 0x30, 0x2e, 0x37, 0x2e, 0x32, 0x2f, 0x88, 0x13, 0x00, 0x00, 0x00, 0x06, //|shi:0.7.2/......| + 0x55, 0x52, 0x47, 0x45, 0x4e, 0x54, 0x00, //|URGENT.| + } + var alert btcwire.Alert + r := bytes.NewBuffer(badAlertEncoded) + err := alert.Deserialize(r, pver) + if _, ok := err.(*btcwire.MessageError); !ok { + t.Errorf("Alert.Deserialize wrong error got: %T, want: %T", + err, btcwire.MessageError{}) + } + + // overflow the max number of elements in SetSubVer + // maxCountSetSubVer + 1 == 131071 + 1 == \x00\x00\x02\x00 + // replace bytes 42-46 + badAlertEncoded = []byte{ + 0x01, 0x00, 0x00, 0x00, 0x50, 0x6e, 0xb2, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x9e, 0x93, 0x51, //|....Pn.O....L..Q| + 0x00, 0x00, 0x00, 0x00, 0xf7, 0x03, 0x00, 0x00, 0xf5, 0x03, 0x00, 0x00, 0x01, 0xf6, 0x03, 0x00, //|................| + 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x9e, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x02, 0x00, 0x74, 0x6f, //|.........../Sato| + 0x73, 0x68, 0x69, 0x3a, 0x30, 0x2e, 0x37, 0x2e, 0x32, 0x2f, 0x88, 0x13, 0x00, 0x00, 0x00, 0x06, //|shi:0.7.2/......| + 0x55, 0x52, 0x47, 0x45, 0x4e, 0x54, 0x00, //|URGENT.| + } + r = bytes.NewBuffer(badAlertEncoded) + err = alert.Deserialize(r, pver) + if _, ok := err.(*btcwire.MessageError); !ok { + t.Errorf("Alert.Deserialize wrong error got: %T, want: %T", + err, btcwire.MessageError{}) + } } diff --git a/msgtx.go b/msgtx.go index e31040b5..fc93faa4 100644 --- a/msgtx.go +++ b/msgtx.go @@ -470,28 +470,12 @@ func readTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { } ti.PreviousOutpoint = op - count, err := readVarInt(r, pver) + ti.SignatureScript, err = readVarBytes(r, pver, maxMessagePayload, + "transaction input signature script") if err != nil { return err } - // Prevent signature script larger than the max message size. It would - // be possible to cause memory exhaustion and panics without a sane - // upper bound on this count. - if count > uint64(maxMessagePayload) { - str := fmt.Sprintf("transaction input signature script is "+ - "larger than max message size [count %d, max %d]", - count, maxMessagePayload) - return messageError("MsgTx.BtcDecode", str) - } - - b := make([]byte, count) - _, err = io.ReadFull(r, b) - if err != nil { - return err - } - ti.SignatureScript = b - var buf [4]byte _, err = io.ReadFull(r, buf[:]) if err != nil { @@ -510,13 +494,7 @@ func writeTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { return err } - slen := uint64(len(ti.SignatureScript)) - err = writeVarInt(w, pver, slen) - if err != nil { - return err - } - - _, err = w.Write(ti.SignatureScript) + err = writeVarBytes(w, pver, ti.SignatureScript) if err != nil { return err } @@ -541,28 +519,12 @@ func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { } to.Value = int64(binary.LittleEndian.Uint64(buf[:])) - count, err := readVarInt(r, pver) + to.PkScript, err = readVarBytes(r, pver, maxMessagePayload, + "transaction output public key script") if err != nil { return err } - // Prevent public key script larger than the max message size. It would - // be possible to cause memory exhaustion and panics without a sane - // upper bound on this count. - if count > uint64(maxMessagePayload) { - str := fmt.Sprintf("transaction output public key script is "+ - "larger than max message size [count %d, max %d]", - count, maxMessagePayload) - return messageError("MsgTx.BtcDecode", str) - } - - b := make([]byte, count) - _, err = io.ReadFull(r, b) - if err != nil { - return err - } - to.PkScript = b - return nil } @@ -576,16 +538,9 @@ func writeTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { return err } - pkLen := uint64(len(to.PkScript)) - err = writeVarInt(w, pver, pkLen) + err = writeVarBytes(w, pver, to.PkScript) if err != nil { return err } - - _, err = w.Write(to.PkScript) - if err != nil { - return err - } - return nil } From a98f5ca38ee39e35962c55b500d3a02c89182997 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 7 May 2014 17:44:46 -0500 Subject: [PATCH 183/219] Cleanup a few nitpicks with recent alert additions. - Group the new read/writeVarBytes functions together to be consistent with the existing code - Modify the comments on the new read/writeVarBytes to be a little more descriptive and consistent with existing code - Use "test payload" for field name in the tests for the read/writeVarBytes functions which is more accurate - Remove reserved param from NewAlert since there is no point is having the caller deal with a reserved param - Various comment tweaks for clarity and consistency - Use camel case for fuction params for consistency - Move the NewAlert and NewAlertFromPayload functions after the receiver definitions for code layout consistency Closes #11. --- common.go | 91 +++++++++++++++++++++------------------- common_test.go | 12 +++--- msgalert.go | 105 ++++++++++++++++++++++++----------------------- msgalert_test.go | 4 +- 4 files changed, 111 insertions(+), 101 deletions(-) diff --git a/common.go b/common.go index eb337dc9..b84afa32 100644 --- a/common.go +++ b/common.go @@ -281,32 +281,6 @@ func writeElements(w io.Writer, elements ...interface{}) error { return nil } -// readVarBytes reads a variable length byte array -func readVarBytes(r io.Reader, pver uint32, maxAllowed uint32, - fieldName string) ([]byte, error) { - - count, err := readVarInt(r, pver) - if err != nil { - return nil, err - } - - // Prevent byte array larger than the max message size. It would - // be possible to cause memory exhaustion and panics without a sane - // upper bound on this count. - if count > uint64(maxAllowed) { - str := fmt.Sprintf("%s is larger than the max allowed size "+ - "[count %d, max %d]", fieldName, count, maxAllowed) - return nil, messageError("readVarBytes", str) - } - - b := make([]byte, count) - _, err = io.ReadFull(r, b) - if err != nil { - return nil, err - } - return b, nil -} - // readVarInt reads a variable length integer from r and returns it as a uint64. func readVarInt(r io.Reader, pver uint32) (uint64, error) { var b [8]byte @@ -346,21 +320,6 @@ func readVarInt(r io.Reader, pver uint32) (uint64, error) { return rv, nil } -// writeVarBytes writes a variable length byte array -func writeVarBytes(w io.Writer, pver uint32, bytes []byte) error { - slen := uint64(len(bytes)) - err := writeVarInt(w, pver, slen) - if err != nil { - return err - } - - _, err = w.Write(bytes) - if err != nil { - return err - } - return nil -} - // writeVarInt serializes val to w using a variable number of bytes depending // on its value. func writeVarInt(w io.Writer, pver uint32, val uint64) error { @@ -420,7 +379,7 @@ func VarIntSerializeSize(val uint64) int { // string, and the bytes that represent the string itself. An error is returned // if the length is greater than the maximum block payload size, since it would // not be possible to put a varString of that size into a block anyways and it -// also helps protect against memory exhuastion attacks and forced panics +// also helps protect against memory exhaustion attacks and forced panics // through malformed messages. func readVarString(r io.Reader, pver uint32) (string, error) { count, err := readVarInt(r, pver) @@ -459,6 +418,54 @@ func writeVarString(w io.Writer, pver uint32, str string) error { return nil } +// readVarBytes reads a variable length byte array. A byte array is encoded +// as a varInt containing the length of the array followed by the bytes +// themselves. An error is returned if the length is greater than the +// passed maxAllowed parameter which helps protect against memory exhuastion +// attacks and forced panics thorugh malformed messages. The fieldName +// parameter is only used for the error message so it provides more context in +// the error. +func readVarBytes(r io.Reader, pver uint32, maxAllowed uint32, + fieldName string) ([]byte, error) { + + count, err := readVarInt(r, pver) + if err != nil { + return nil, err + } + + // Prevent byte array larger than the max message size. It would + // be possible to cause memory exhaustion and panics without a sane + // upper bound on this count. + if count > uint64(maxAllowed) { + str := fmt.Sprintf("%s is larger than the max allowed size "+ + "[count %d, max %d]", fieldName, count, maxAllowed) + return nil, messageError("readVarBytes", str) + } + + b := make([]byte, count) + _, err = io.ReadFull(r, b) + if err != nil { + return nil, err + } + return b, nil +} + +// writeVarInt serializes a variable length byte array to w as a varInt +// containing the number of bytes, followed by the bytes themselves. +func writeVarBytes(w io.Writer, pver uint32, bytes []byte) error { + slen := uint64(len(bytes)) + err := writeVarInt(w, pver, slen) + if err != nil { + return err + } + + _, err = w.Write(bytes) + if err != nil { + return err + } + return nil +} + // randomUint64 returns a cryptographically random uint64 value. This // unexported version takes a reader primarily to ensure the error paths // can be properly tested by passing a fake reader in the tests. diff --git a/common_test.go b/common_test.go index 3a534d47..b9418974 100644 --- a/common_test.go +++ b/common_test.go @@ -539,8 +539,8 @@ func TestVarBytesWire(t *testing.T) { // Decode from wire format. rbuf := bytes.NewBuffer(test.buf) - val, err := btcwire.TstReadVarBytes(rbuf, test.pver, btcwire.MaxMessagePayload, - "alert serialized payload") + val, err := btcwire.TstReadVarBytes(rbuf, test.pver, + btcwire.MaxMessagePayload, "test payload") if err != nil { t.Errorf("readVarBytes #%d error %v", i, err) continue @@ -591,8 +591,8 @@ func TestVarBytesWireErrors(t *testing.T) { // Decode from wire format. r := newFixedReader(test.max, test.buf) - _, err = btcwire.TstReadVarBytes(r, test.pver, btcwire.MaxMessagePayload, - "alert serialized payload") + _, err = btcwire.TstReadVarBytes(r, test.pver, + btcwire.MaxMessagePayload, "test payload") if err != test.readErr { t.Errorf("readVarBytes #%d wrong error got: %v, want: %v", i, err, test.readErr) @@ -623,8 +623,8 @@ func TestVarBytesOverflowErrors(t *testing.T) { for i, test := range tests { // Decode from wire format. rbuf := bytes.NewBuffer(test.buf) - _, err := btcwire.TstReadVarBytes(rbuf, test.pver, btcwire.MaxMessagePayload, - "alert serialized payload") + _, err := btcwire.TstReadVarBytes(rbuf, test.pver, + btcwire.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)) diff --git a/msgalert.go b/msgalert.go index 2bd45dfd..d1026c2a 100644 --- a/msgalert.go +++ b/msgalert.go @@ -58,46 +58,49 @@ import ( // | Total (Fixed) | 45 | // ----------------------------------------------- // -// note: +// NOTE: // * string is a VarString i.e VarInt length followed by the string itself // * set is a VarInt followed by as many number of strings // * set is a VarInt followed by as many number of ints // * fixedAlertSize = 40 + 5*min(VarInt) = 40 + 5*1 = 45 - +// // Now we can define bounds on Alert size, SetCancel and SetSubVer // Fixed size of the alert payload const fixedAlertSize = 45 -// Max size of the ECDSA signature -// note: since this size is fixed and < 255, size of VarInt -// required = 1 (fits in uint8) +// maxSignatureSize is the max size of an ECDSA signature. +// NOTE: Since this size is fixed and < 255, the size of VarInt required = 1. const maxSignatureSize = 72 -// Maximum size of the alert +// maxAlertSize is the maximum size an alert. +// // MessagePayload = VarInt(Alert) + Alert + VarInt(Signature) + Signature // maxMessagePayload = maxAlertSize + max(VarInt) + maxSignatureSize + 1 const maxAlertSize = maxMessagePayload - maxSignatureSize - MaxVarIntPayload - 1 -// Maximum number of Cancel IDs from SetCancel to read +// maxCountSetCancel is the maximum number of cancel IDs that could possibly +// fit into a maximum size alert. +// // maxAlertSize = fixedAlertSize + max(SetCancel) + max(SetSubVer) + 3*(string) -// for caculating maximum number of Cancel IDs, set all other variable sizes to 0 +// for caculating maximum number of cancel IDs, set all other var sizes to 0 // maxAlertSize = fixedAlertSize + (MaxVarIntPayload-1) + x*sizeOf(int32) // x = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 4 const maxCountSetCancel = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 4 -// Maximum number of subversions from SetSubVer to read +// maxCountSetSubVer is the maximum number of subversions that could possibly +// fit into a maximum size alert. +// // maxAlertSize = fixedAlertSize + max(SetCancel) + max(SetSubVer) + 3*(string) -// for caculating maximum number of subversions, set all other variable sizes to 0 +// for caculating maximum number of subversions, set all other var sizes to 0 // maxAlertSize = fixedAlertSize + (MaxVarIntPayload-1) + x*sizeOf(string) // x = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / sizeOf(string) // subversion would typically be something like "/Satoshi:0.7.2/" (15 bytes) // so assuming < 255 bytes, sizeOf(string) = sizeOf(uint8) + 255 = 256 const maxCountSetSubVer = (maxAlertSize - fixedAlertSize - MaxVarIntPayload + 1) / 256 -// Alert contains the data deserialized from the MsgAlert payload +// Alert contains the data deserialized from the MsgAlert payload. type Alert struct { - // Alert format version Version int32 @@ -144,41 +147,7 @@ type Alert struct { Reserved string } -// NewAlert returns an new Alert with values provided -func NewAlert(version int32, relayuntil int64, expiration int64, - id int32, cancel int32, setcancel []int32, minver int32, - maxver int32, setsubver []string, priority int32, comment string, - statusbar string, reserved string) *Alert { - return &Alert{ - Version: version, - RelayUntil: relayuntil, - Expiration: expiration, - ID: id, - Cancel: cancel, - SetCancel: setcancel, - MinVer: minver, - MaxVer: maxver, - SetSubVer: setsubver, - Priority: priority, - Comment: comment, - StatusBar: statusbar, - Reserved: reserved, - } -} - -// NewAlertFromPayload returns an Alert with values deserialized -// from the serializedpayload -func NewAlertFromPayload(serializedpayload []byte, pver uint32) (*Alert, error) { - var alert Alert - r := bytes.NewReader(serializedpayload) - err := alert.Deserialize(r, pver) - if err != nil { - return nil, err - } - return &alert, nil -} - -// Serialize writes a serialized byte array of the Alert +// Serialize encodes the alert to w using the alert protocol encoding format. func (alert *Alert) Serialize(w io.Writer, pver uint32) error { err := writeElements(w, &alert.Version, &alert.RelayUntil, &alert.Expiration, &alert.ID, &alert.Cancel) @@ -244,8 +213,8 @@ func (alert *Alert) Serialize(w io.Writer, pver uint32) error { return nil } -// Deserialize reads a byte array, deserializes -// it and updates the Alert +// Deserialize decodes from r into the receiver using the alert protocol +// encoding format. func (alert *Alert) Deserialize(r io.Reader, pver uint32) error { err := readElements(r, &alert.Version, &alert.RelayUntil, &alert.Expiration, &alert.ID, &alert.Cancel) @@ -316,6 +285,40 @@ func (alert *Alert) Deserialize(r io.Reader, pver uint32) error { return nil } +// NewAlert returns an new Alert with values provided. +func NewAlert(version int32, relayUntil int64, expiration int64, + id int32, cancel int32, setCancel []int32, minVer int32, + maxVer int32, setSubVer []string, priority int32, comment string, + statusBar string) *Alert { + return &Alert{ + Version: version, + RelayUntil: relayUntil, + Expiration: expiration, + ID: id, + Cancel: cancel, + SetCancel: setCancel, + MinVer: minVer, + MaxVer: maxVer, + SetSubVer: setSubVer, + Priority: priority, + Comment: comment, + StatusBar: statusBar, + Reserved: "", + } +} + +// NewAlertFromPayload returns an Alert with values deserialized from the +// serialized payload. +func NewAlertFromPayload(serializedPayload []byte, pver uint32) (*Alert, error) { + var alert Alert + r := bytes.NewReader(serializedPayload) + err := alert.Deserialize(r, pver) + if err != nil { + return nil, err + } + return &alert, nil +} + // MsgAlert implements the Message interface and defines a bitcoin alert // message. // @@ -410,9 +413,9 @@ func (msg *MsgAlert) MaxPayloadLength(pver uint32) uint32 { // NewMsgAlert returns a new bitcoin alert message that conforms to the Message // interface. See MsgAlert for details. -func NewMsgAlert(serializedpayload []byte, signature []byte) *MsgAlert { +func NewMsgAlert(serializedPayload []byte, signature []byte) *MsgAlert { return &MsgAlert{ - SerializedPayload: serializedpayload, + SerializedPayload: serializedPayload, Signature: signature, Payload: nil, } diff --git a/msgalert_test.go b/msgalert_test.go index 1ae012c9..20f8287e 100644 --- a/msgalert_test.go +++ b/msgalert_test.go @@ -283,7 +283,7 @@ func TestAlert(t *testing.T) { alert := btcwire.NewAlert( 1, 1337093712, 1368628812, 1015, 1013, []int32{1014}, 0, 40599, []string{"/Satoshi:0.7.2/"}, 5000, "", - "URGENT: upgrade required, see http://bitcoin.org/dos for details", "", + "URGENT: upgrade required, see http://bitcoin.org/dos for details", ) w := new(bytes.Buffer) err := alert.Serialize(w, pver) @@ -370,7 +370,7 @@ func TestAlertErrors(t *testing.T) { baseAlert := btcwire.NewAlert( 1, 1337093712, 1368628812, 1015, 1013, []int32{1014}, 0, 40599, []string{"/Satoshi:0.7.2/"}, 5000, "", - "URGENT", "", + "URGENT", ) baseAlertEncoded := []byte{ 0x01, 0x00, 0x00, 0x00, 0x50, 0x6e, 0xb2, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x9e, 0x93, 0x51, //|....Pn.O....L..Q| From cf754d09bfbc9922c2e8544ac19bbd876b16c5e7 Mon Sep 17 00:00:00 2001 From: David Hill Date: Thu, 10 Apr 2014 22:29:00 -0400 Subject: [PATCH 184/219] Initial implementation of BIP0037. Implement filteradd, filterclear, filterload, and merkleblock. --- invvect.go | 14 +-- message.go | 48 ++++++--- message_test.go | 11 ++ msgfilteradd.go | 103 +++++++++++++++++++ msgfilteradd_test.go | 169 +++++++++++++++++++++++++++++++ msgfilterclear.go | 58 +++++++++++ msgfilterclear_test.go | 72 +++++++++++++ msgfilterload.go | 160 +++++++++++++++++++++++++++++ msgfilterload_test.go | 223 +++++++++++++++++++++++++++++++++++++++++ msgmerkleblock.go | 163 ++++++++++++++++++++++++++++++ msgmerkleblock_test.go | 109 ++++++++++++++++++++ 11 files changed, 1108 insertions(+), 22 deletions(-) create mode 100644 msgfilteradd.go create mode 100644 msgfilteradd_test.go create mode 100644 msgfilterclear.go create mode 100644 msgfilterclear_test.go create mode 100644 msgfilterload.go create mode 100644 msgfilterload_test.go create mode 100644 msgmerkleblock.go create mode 100644 msgmerkleblock_test.go diff --git a/invvect.go b/invvect.go index b0dbb697..e9b74dcb 100644 --- a/invvect.go +++ b/invvect.go @@ -23,16 +23,18 @@ type InvType uint32 // These constants define the various supported inventory vector types. const ( - InvTypeError InvType = 0 - InvTypeTx InvType = 1 - InvTypeBlock InvType = 2 + InvTypeError InvType = 0 + InvTypeTx InvType = 1 + InvTypeBlock InvType = 2 + InvTypeFilteredBlock InvType = 3 ) // Map of service flags back to their constant names for pretty printing. var ivStrings = map[InvType]string{ - InvTypeError: "ERROR", - InvTypeTx: "MSG_TX", - InvTypeBlock: "MSG_BLOCK", + InvTypeError: "ERROR", + InvTypeTx: "MSG_TX", + InvTypeBlock: "MSG_BLOCK", + InvTypeFilteredBlock: "MSG_FILTERED_BLOCK", } // String returns the InvType in human-readable form. diff --git a/message.go b/message.go index 1b502444..e007a594 100644 --- a/message.go +++ b/message.go @@ -26,22 +26,26 @@ const maxMessagePayload = (1024 * 1024 * 32) // 32MB // Commands used in bitcoin message headers which describe the type of message. const ( - cmdVersion = "version" - cmdVerAck = "verack" - cmdGetAddr = "getaddr" - cmdAddr = "addr" - cmdGetBlocks = "getblocks" - cmdInv = "inv" - cmdGetData = "getdata" - cmdNotFound = "notfound" - cmdBlock = "block" - cmdTx = "tx" - cmdGetHeaders = "getheaders" - cmdHeaders = "headers" - cmdPing = "ping" - cmdPong = "pong" - cmdAlert = "alert" - cmdMemPool = "mempool" + cmdVersion = "version" + cmdVerAck = "verack" + cmdGetAddr = "getaddr" + cmdAddr = "addr" + cmdGetBlocks = "getblocks" + cmdInv = "inv" + cmdGetData = "getdata" + cmdNotFound = "notfound" + cmdBlock = "block" + cmdTx = "tx" + cmdGetHeaders = "getheaders" + cmdHeaders = "headers" + cmdPing = "ping" + cmdPong = "pong" + cmdAlert = "alert" + cmdMemPool = "mempool" + cmdFilterAdd = "filteradd" + cmdFilterClear = "filterclear" + cmdFilterLoad = "filterload" + cmdMerkleBlock = "merkleblock" ) // Message is an interface that describes a bitcoin message. A type that @@ -108,6 +112,18 @@ func makeEmptyMessage(command string) (Message, error) { case cmdMemPool: msg = &MsgMemPool{} + case cmdFilterAdd: + msg = &MsgFilterAdd{} + + case cmdFilterClear: + msg = &MsgFilterClear{} + + case cmdFilterLoad: + msg = &MsgFilterLoad{} + + case cmdMerkleBlock: + msg = &MsgMerkleBlock{} + default: return nil, fmt.Errorf("unhandled command [%s]", command) } diff --git a/message_test.go b/message_test.go index c79f4e8d..bfbc8e1e 100644 --- a/message_test.go +++ b/message_test.go @@ -68,6 +68,13 @@ func TestMessage(t *testing.T) { msgHeaders := btcwire.NewMsgHeaders() msgAlert := btcwire.NewMsgAlert([]byte("payload"), []byte("signature")) msgMemPool := btcwire.NewMsgMemPool() + msgFilterAdd := btcwire.NewMsgFilterAdd([]byte{0x01}) + msgFilterClear := btcwire.NewMsgFilterClear() + msgFilterLoad := btcwire.NewMsgFilterLoad([]byte{0x01}, 10, 0, btcwire.BloomUpdateNone) + + // + bh := btcwire.NewBlockHeader(&btcwire.ShaHash{}, &btcwire.ShaHash{}, 0, 0) + msgMerkleBlock := btcwire.NewMsgMerkleBlock(bh) tests := []struct { in btcwire.Message // Value to encode @@ -92,6 +99,10 @@ func TestMessage(t *testing.T) { {msgHeaders, msgHeaders, pver, btcwire.MainNet, 25}, {msgAlert, msgAlert, pver, btcwire.MainNet, 42}, {msgMemPool, msgMemPool, pver, btcwire.MainNet, 24}, + {msgFilterAdd, msgFilterAdd, pver, btcwire.MainNet, 26}, + {msgFilterClear, msgFilterClear, pver, btcwire.MainNet, 24}, + {msgFilterLoad, msgFilterLoad, pver, btcwire.MainNet, 35}, + {msgMerkleBlock, msgMerkleBlock, pver, btcwire.MainNet, 110}, } t.Logf("Running %d tests", len(tests)) diff --git a/msgfilteradd.go b/msgfilteradd.go new file mode 100644 index 00000000..5e05177b --- /dev/null +++ b/msgfilteradd.go @@ -0,0 +1,103 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +const ( + // MaxFilterAddDataSize is the maximum byte size of a data + // element to add to the Bloom filter. It is equal to the + // maximum element size of a script. + 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. +// +// This message was not added until protocol version BIP0037Version. +type MsgFilterAdd struct { + Data []byte +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgFilterAdd) BtcDecode(r io.Reader, pver uint32) error { + if pver < BIP0037Version { + str := fmt.Sprintf("filteradd message invalid for protocol "+ + "version %d", pver) + 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) + if err != nil { + return err + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgFilterAdd) BtcEncode(w io.Writer, pver uint32) error { + if pver < BIP0037Version { + str := fmt.Sprintf("filteradd message invalid for protocol "+ + "version %d", pver) + return messageError("MsgFilterAdd.BtcEncode", str) + } + + size := len(msg.Data) + if size > MaxFilterAddDataSize { + str := fmt.Sprintf("filteradd size too large for message "+ + "[size %v, max %v]", size, MaxFilterAddDataSize) + return messageError("MsgFilterAdd.BtcEncode", str) + } + + err := writeVarInt(w, pver, uint64(size)) + if err != nil { + return err + } + + err = writeElement(w, msg.Data) + if err != nil { + return err + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgFilterAdd) Command() string { + return cmdFilterAdd +} + +// 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 +} + +// 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, + } +} diff --git a/msgfilteradd_test.go b/msgfilteradd_test.go new file mode 100644 index 00000000..9c111fc3 --- /dev/null +++ b/msgfilteradd_test.go @@ -0,0 +1,169 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "io" + "testing" +) + +// TestFilterCLearLatest tests the MsgFilterAdd API against the latest protocol version. +func TestFilterAddLatest(t *testing.T) { + pver := btcwire.ProtocolVersion + + data := []byte{0x01, 0x02} + msg := btcwire.NewMsgFilterAdd(data) + + // Ensure the command is expected value. + wantCmd := "filteradd" + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgFilterAdd: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + wantPayload := uint32(529) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Test encode with latest protocol version. + var buf bytes.Buffer + err := msg.BtcEncode(&buf, pver) + if err != nil { + t.Errorf("encode of MsgFilterAdd failed %v err <%v>", msg, err) + } + + // Test decode with latest protocol version. + readmsg := btcwire.MsgFilterAdd{} + err = readmsg.BtcDecode(&buf, pver) + if err != nil { + t.Errorf("decode of MsgFilterAdd failed [%v] err <%v>", buf, err) + } + + return +} + +// TestFilterAddCrossProtocol tests the MsgFilterAdd API when encoding with the latest +// protocol version and decoded with BIP0031Version. +func TestFilterAddCrossProtocol(t *testing.T) { + data := []byte{0x01, 0x02} + msg := btcwire.NewMsgFilterAdd(data) + + // Encode with old 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) + } + + // Decode with old protocol version. + 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) + } +} + +// TestFilterAddMaxDataSize tests the MsgFilterAdd API maximum data size. +func TestFilterAddMaxDataSize(t *testing.T) { + data := bytes.Repeat([]byte{0xff}, 521) + msg := btcwire.NewMsgFilterAdd(data) + + // Encode with latest protocol version. + 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) + } + + // 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) + } +} + +// TestFilterAddWireErrors performs negative tests against wire encode and decode +// of MsgFilterAdd to confirm error paths work correctly. +func TestFilterAddWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + + tests := []struct { + in *btcwire.MsgFilterAdd // 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. + { + &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, + }, + { + &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, + }, + { + &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, + }, + } + + 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 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 { + t.Errorf("BtcDecode #%d wrong error got: %v, want: %v", + i, err, test.readErr) + continue + } + } +} diff --git a/msgfilterclear.go b/msgfilterclear.go new file mode 100644 index 00000000..ea7cfcac --- /dev/null +++ b/msgfilterclear.go @@ -0,0 +1,58 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// 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. +type MsgFilterClear struct{} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgFilterClear) BtcDecode(r io.Reader, pver uint32) error { + if pver < BIP0037Version { + str := fmt.Sprintf("filterclear message invalid for protocol "+ + "version %d", pver) + return messageError("MsgFilterClear.BtcDecode", str) + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgFilterClear) BtcEncode(w io.Writer, pver uint32) error { + if pver < BIP0037Version { + str := fmt.Sprintf("filterclear message invalid for protocol "+ + "version %d", pver) + return messageError("MsgFilterClear.BtcEncode", str) + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgFilterClear) Command() string { + return cmdFilterClear +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgFilterClear) MaxPayloadLength(pver uint32) uint32 { + return 0 +} + +// NewMsgFilterClear returns a new bitcoin filterclear message that conforms to the Message +// interface. See MsgFilterClear for details. +func NewMsgFilterClear() *MsgFilterClear { + return &MsgFilterClear{} +} diff --git a/msgfilterclear_test.go b/msgfilterclear_test.go new file mode 100644 index 00000000..d8cf3396 --- /dev/null +++ b/msgfilterclear_test.go @@ -0,0 +1,72 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "testing" +) + +// TestFilterCLearLatest tests the MsgFilterClear API against the latest protocol version. +func TestFilterClearLatest(t *testing.T) { + pver := btcwire.ProtocolVersion + + msg := btcwire.NewMsgFilterClear() + + // Ensure the command is expected value. + wantCmd := "filterclear" + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgFilterClear: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + wantPayload := uint32(0) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Test encode with latest protocol version. + var buf bytes.Buffer + err := msg.BtcEncode(&buf, pver) + 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() + err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version) + if err == nil { + t.Errorf("decode of MsgFilterClear succeeded when it shouldn't have %v", + msg) + } +} diff --git a/msgfilterload.go b/msgfilterload.go new file mode 100644 index 00000000..412476b4 --- /dev/null +++ b/msgfilterload.go @@ -0,0 +1,160 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +type BloomUpdateType uint8 + +const ( + // 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. + 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 BloomUpdateType = 2 +) + +const ( + // 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. +// +// This message was not added until protocol version BIP0037Version. +type MsgFilterLoad struct { + Filter []byte + HashFuncs uint32 + Tweak uint32 + Flags BloomUpdateType +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgFilterLoad) BtcDecode(r io.Reader, pver uint32) error { + if pver < BIP0037Version { + str := fmt.Sprintf("filterload message invalid for protocol "+ + "version %d", pver) + 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) + if err != nil { + return err + } + + err = readElements(r, &msg.HashFuncs, &msg.Tweak, &msg.Flags) + if err != nil { + return err + } + + if msg.HashFuncs > MaxFilterLoadHashFuncs { + str := fmt.Sprintf("too many filter hash functions for message "+ + "[count %v, max %v]", msg.HashFuncs, MaxFilterLoadHashFuncs) + return messageError("MsgFilterLoad.BtcDecode", str) + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgFilterLoad) BtcEncode(w io.Writer, pver uint32) error { + if pver < BIP0037Version { + str := fmt.Sprintf("filterload message invalid for protocol "+ + "version %d", pver) + return messageError("MsgFilterLoad.BtcEncode", str) + } + + size := len(msg.Filter) + if size > MaxFilterLoadFilterSize { + str := fmt.Sprintf("filterload filter size too large for message "+ + "[size %v, max %v]", size, MaxFilterLoadFilterSize) + return messageError("MsgFilterLoad.BtcEncode", str) + } + + if msg.HashFuncs > MaxFilterLoadHashFuncs { + str := fmt.Sprintf("too many filter hash functions for message "+ + "[count %v, max %v]", msg.HashFuncs, MaxFilterLoadHashFuncs) + return messageError("MsgFilterLoad.BtcEncode", str) + } + + err := writeVarInt(w, pver, uint64(size)) + if err != nil { + return err + } + err = writeElements(w, msg.Filter, msg.HashFuncs, msg.Tweak, msg.Flags) + if err != nil { + return err + } + + 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 { + return cmdFilterLoad +} + +// 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 +} + +// 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, + HashFuncs: hashFuncs, + Tweak: tweak, + Flags: flags, + } +} diff --git a/msgfilterload_test.go b/msgfilterload_test.go new file mode 100644 index 00000000..2bf387fe --- /dev/null +++ b/msgfilterload_test.go @@ -0,0 +1,223 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "io" + "testing" +) + +// TestFilterCLearLatest tests the MsgFilterLoad API against the latest protocol version. +func TestFilterLoadLatest(t *testing.T) { + pver := btcwire.ProtocolVersion + + data := []byte{0x01, 0x02} + msg := btcwire.NewMsgFilterLoad(data, 10, 0, 0) + + // Ensure the command is expected value. + wantCmd := "filterload" + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgFilterLoad: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payadd is expected value for latest protocol version. + wantPayload := uint32(36018) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayLoadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Test encode with latest protocol version. + var buf bytes.Buffer + err := msg.BtcEncode(&buf, pver) + if err != nil { + t.Errorf("encode of MsgFilterLoad failed %v err <%v>", msg, err) + } + + // Test decode with latest protocol version. + readmsg := btcwire.MsgFilterLoad{} + err = readmsg.BtcDecode(&buf, pver) + if err != nil { + t.Errorf("decode of MsgFilterLoad failed [%v] err <%v>", buf, err) + } + + return +} + +// TestFilterLoadCrossProtocol tests the MsgFilterLoad API when encoding with the latest +// protocol version and decoded with BIP0031Version. +func TestFilterLoadCrossProtocol(t *testing.T) { + data := []byte{0x01, 0x02} + msg := btcwire.NewMsgFilterLoad(data, 10, 0, 0) + + // Encode with old 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) + } + + // Decode with old protocol version. + 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) + } +} + +// TestFilterLoadMaxFilterSize tests the MsgFilterLoad API maximum filter size. +func TestFilterLoadMaxFilterSize(t *testing.T) { + data := bytes.Repeat([]byte{0xff}, 36001) + msg := btcwire.NewMsgFilterLoad(data, 10, 0, 0) + + // Encode with latest protocol version. + 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) + } + + // 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) + } +} + +// TestFilterLoadMaxHashFuncsSize tests the MsgFilterLoad API maximum hash functions. +func TestFilterLoadMaxHashFuncsSize(t *testing.T) { + data := bytes.Repeat([]byte{0xff}, 10) + msg := btcwire.NewMsgFilterLoad(data, 61, 0, 0) + + // Encode with latest protocol version. + 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) + } + + newBuf := []byte{ + 0x0a, // filter size + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // filter + 0x3d, 0x00, 0x00, 0x00, // max hash funcs + 0x00, 0x00, 0x00, 0x00, // tweak + 0x00, // update Type + } + // Decode with latest protocol version. + buf1 := bytes.NewBuffer(newBuf) + readbuf := bytes.NewReader(buf1.Bytes()) + err = msg.BtcDecode(readbuf, btcwire.ProtocolVersion) + if err == nil { + t.Errorf("decode of MsgFilterLoad succeeded when it shouldn't have %v", + msg) + } +} + +// TestFilterLoadWireErrors performs negative tests against wire encode and decode +// of MsgFilterLoad to confirm error paths work correctly. +func TestFilterLoadWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + + tests := []struct { + in *btcwire.MsgFilterLoad // 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. + { + &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, + }, + { + &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, + }, + { + &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, + }, + } + + 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 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 { + t.Errorf("BtcDecode #%d wrong error got: %v, want: %v", + i, err, test.readErr) + continue + } + } +} diff --git a/msgmerkleblock.go b/msgmerkleblock.go new file mode 100644 index 00000000..a4cc8376 --- /dev/null +++ b/msgmerkleblock.go @@ -0,0 +1,163 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// 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 { + Header BlockHeader + Transactions uint32 + Hashes []*ShaHash + Flags []byte +} + +// AddTxHash adds a new transaction hash to the message. +func (msg *MsgMerkleBlock) AddTxHash(hash *ShaHash) error { + if len(msg.Hashes)+1 > maxTxPerBlock { + str := fmt.Sprintf("too many tx hashes for message [max %v]", + maxTxPerBlock) + return messageError("MsgMerkleBlock.AddTxHash", str) + } + + msg.Hashes = append(msg.Hashes, hash) + return nil +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32) error { + if pver < BIP0037Version { + str := fmt.Sprintf("merkleblock message invalid for protocol "+ + "version %d", pver) + return messageError("MsgMerkleBlock.BtcDecode", str) + } + + err := readBlockHeader(r, pver, &msg.Header) + if err != nil { + return err + } + + err = readElement(r, &msg.Transactions) + if err != nil { + return err + } + + // Read num block locator hashes and limit to max. + count, err := readVarInt(r, pver) + if err != nil { + return err + } + if count > maxTxPerBlock { + str := fmt.Sprintf("too many transaction hashes for message "+ + "[count %v, max %v]", count, maxTxPerBlock) + return messageError("MsgMerkleBlock.BtcDecode", str) + } + + msg.Hashes = make([]*ShaHash, 0, count) + for i := uint64(0); i < count; i++ { + sha := ShaHash{} + err := readElement(r, &sha) + if err != nil { + return err + } + msg.AddTxHash(&sha) + } + + count, err = readVarInt(r, pver) + if err != nil { + return err + } + + msg.Flags = make([]byte, 0, count) + err = readElement(r, &msg.Flags) + if err != nil { + return err + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32) error { + if pver < BIP0037Version { + str := fmt.Sprintf("merkleblock message invalid for protocol "+ + "version %d", pver) + return messageError("MsgMerkleBlock.BtcEncode", str) + } + + // Read num transaction hashes and limit to max. + count := len(msg.Hashes) + if count > maxTxPerBlock { + str := fmt.Sprintf("too many transaction hashes for message "+ + "[count %v, max %v]", count, maxTxPerBlock) + return messageError("MsgMerkleBlock.BtcDecode", str) + } + + err := writeBlockHeader(w, pver, &msg.Header) + if err != nil { + return err + } + + err = writeElement(w, msg.Transactions) + if err != nil { + return err + } + + err = writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + for _, hash := range msg.Hashes { + err = writeElement(w, hash) + if err != nil { + return err + } + } + + count = len(msg.Flags) + err = writeVarInt(w, pver, uint64(count)) + if err != nil { + return err + } + + err = writeElement(w, msg.Flags) + if err != nil { + return err + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgMerkleBlock) Command() string { + return cmdMerkleBlock +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +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. +func NewMsgMerkleBlock(bh *BlockHeader) *MsgMerkleBlock { + return &MsgMerkleBlock{ + Header: *bh, + Transactions: 0, + Hashes: make([]*ShaHash, 0), + Flags: make([]byte, 0), + } +} diff --git a/msgmerkleblock_test.go b/msgmerkleblock_test.go new file mode 100644 index 00000000..79144ce5 --- /dev/null +++ b/msgmerkleblock_test.go @@ -0,0 +1,109 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "crypto/rand" + "github.com/conformal/btcwire" + "testing" +) + +// TestMerkleBlock tests the MsgMerkleBlock API. +func TestMerkleBlock(t *testing.T) { + pver := btcwire.ProtocolVersion + pverOld := btcwire.BIP0037Version - 1 + + // 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) + + // Ensure the command is expected value. + wantCmd := "merkleblock" + msg := btcwire.NewMsgMerkleBlock(bh) + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgBlock: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + // Num addresses (varInt) + max allowed addresses. + wantPayload := uint32(1000000) + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Load maxTxPerBlock hashes + data := make([]byte, 32) + for i := 0; i < (btcwire.MaxBlockPayload/10)+1; i++ { + rand.Read(data) + hash, err := btcwire.NewShaHash(data) + if err != nil { + t.Errorf("NewShaHash failed: %v\n", err) + return + } + + if err = msg.AddTxHash(hash); err != nil { + t.Errorf("AddTxHash failed: %v\n", err) + return + } + } + + // Add one more Tx to test failure + rand.Read(data) + hash, err := btcwire.NewShaHash(data) + if err != nil { + t.Errorf("NewShaHash failed: %v\n", err) + return + } + + if err = msg.AddTxHash(hash); err == nil { + t.Errorf("AddTxHash succeeded when it should have failed") + return + } + + // Test encode with latest protocol version. + var buf bytes.Buffer + err = msg.BtcEncode(&buf, pver) + if err != nil { + 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) + if err != nil { + 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 + 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") + return + } +} From f8ec4766915de9333b0ba77b937481cbc84b60a0 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 5 May 2014 02:15:18 -0500 Subject: [PATCH 185/219] 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. --- README.md | 6 - common.go | 18 +++ doc.go | 1 + internal_test.go | 34 ++-- msgblock.go | 2 - msgfilteradd.go | 35 ++-- msgfilteradd_test.go | 111 +++++++------ msgfilterclear.go | 7 +- msgfilterclear_test.go | 182 +++++++++++++++++---- msgfilterload.go | 69 +++----- msgfilterload_test.go | 143 +++++++++-------- msgmerkleblock.go | 44 ++--- msgmerkleblock_test.go | 356 ++++++++++++++++++++++++++++++++++++++--- msgping_test.go | 2 +- msgpong_test.go | 4 +- 15 files changed, 737 insertions(+), 277 deletions(-) diff --git a/README.md b/README.md index 2ce3404d..74c7dfe9 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/common.go b/common.go index b84afa32..f9582a94 100644 --- a/common.go +++ b/common.go @@ -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 diff --git a/doc.go b/doc.go index ac5e4b45..f43328f5 100644 --- a/doc.go +++ b/doc.go @@ -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 diff --git a/internal_test.go b/internal_test.go index 031d3068..7b59992c 100644 --- a/internal_test.go +++ b/internal_test.go @@ -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. diff --git a/msgblock.go b/msgblock.go index 33186d8f..d03dc539 100644 --- a/msgblock.go +++ b/msgblock.go @@ -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 diff --git a/msgfilteradd.go b/msgfilteradd.go index 5e05177b..4b19a62e 100644 --- a/msgfilteradd.go +++ b/msgfilteradd.go @@ -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, diff --git a/msgfilteradd_test.go b/msgfilteradd_test.go index 9c111fc3..86429f7c 100644 --- a/msgfilteradd_test.go +++ b/msgfilteradd_test.go @@ -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 + } + } } } diff --git a/msgfilterclear.go b/msgfilterclear.go index ea7cfcac..5d736b6e 100644 --- a/msgfilterclear.go +++ b/msgfilterclear.go @@ -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. diff --git a/msgfilterclear_test.go b/msgfilterclear_test.go index d8cf3396..8579342c 100644 --- a/msgfilterclear_test.go +++ b/msgfilterclear_test.go @@ -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 + } + } + } } diff --git a/msgfilterload.go b/msgfilterload.go index 412476b4..35725f19 100644 --- a/msgfilterload.go +++ b/msgfilterload.go @@ -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, diff --git a/msgfilterload_test.go b/msgfilterload_test.go index 2bf387fe..4328b7b1 100644 --- a/msgfilterload_test.go +++ b/msgfilterload_test.go @@ -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 + } + } + } } diff --git a/msgmerkleblock.go b/msgmerkleblock.go index a4cc8376..18b579fb 100644 --- a/msgmerkleblock.go +++ b/msgmerkleblock.go @@ -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, diff --git a/msgmerkleblock_test.go b/msgmerkleblock_test.go index 79144ce5..e4040d05 100644 --- a/msgmerkleblock_test.go +++ b/msgmerkleblock_test.go @@ -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 +} diff --git a/msgping_test.go b/msgping_test.go index f84bae4e..c4958af5 100644 --- a/msgping_test.go +++ b/msgping_test.go @@ -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 { diff --git a/msgpong_test.go b/msgpong_test.go index d588c6fb..f1dc4b1d 100644 --- a/msgpong_test.go +++ b/msgpong_test.go @@ -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") } From c2a1444a8861bedf42da4613ca0f7027060ee1cd Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 11 Nov 2013 23:12:07 -0600 Subject: [PATCH 186/219] Add new reject command. This commit adds the new reject protocol message added to recent versions of the reference implementation. This message is intended to be used in response to messages from a remote peer when it is rejected for some reason such as blocks being rejected due to not conforming to the chain rules, transactions double spending inputs, and version messages sent after they're already sent. This is work toward issue #9. --- common.go | 18 +++++ message.go | 4 ++ msgreject.go | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++ protocol.go | 4 ++ 4 files changed, 210 insertions(+) create mode 100644 msgreject.go diff --git a/common.go b/common.go index f9582a94..42204ec9 100644 --- a/common.go +++ b/common.go @@ -139,6 +139,15 @@ func readElement(r io.Reader, element interface{}) error { } *e = BloomUpdateType(b[0]) return nil + + case *RejectCode: + b := scratch[0:1] + _, err := io.ReadFull(r, b) + if err != nil { + return err + } + *e = RejectCode(b[0]) + return nil } // Fall back to the slower binary.Read if a fast path was not available @@ -280,6 +289,15 @@ func writeElement(w io.Writer, element interface{}) error { return err } return nil + + case RejectCode: + 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 diff --git a/message.go b/message.go index e007a594..26ec0c2d 100644 --- a/message.go +++ b/message.go @@ -46,6 +46,7 @@ const ( cmdFilterClear = "filterclear" cmdFilterLoad = "filterload" cmdMerkleBlock = "merkleblock" + cmdReject = "reject" ) // Message is an interface that describes a bitcoin message. A type that @@ -124,6 +125,9 @@ func makeEmptyMessage(command string) (Message, error) { case cmdMerkleBlock: msg = &MsgMerkleBlock{} + case cmdReject: + msg = &MsgReject{} + default: return nil, fmt.Errorf("unhandled command [%s]", command) } diff --git a/msgreject.go b/msgreject.go new file mode 100644 index 00000000..14856cfb --- /dev/null +++ b/msgreject.go @@ -0,0 +1,184 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire + +import ( + "fmt" + "io" +) + +// RejectCode represents a numeric value by which a remote peer indicates +// why a message was rejected. +type RejectCode uint8 + +// These constants define the various supported reject codes. +const ( + RejectMalformed RejectCode = 0x01 + RejectInvalid RejectCode = 0x10 + RejectObsolete RejectCode = 0x11 + RejectDuplicate RejectCode = 0x12 + RejectNonstandard RejectCode = 0x40 + RejectDust RejectCode = 0x41 + RejectInsufficientFee RejectCode = 0x42 + RejectCheckpoint RejectCode = 0x43 +) + +// Map of reject codes back strings for pretty printing. +var rejectCodeStrings = map[RejectCode]string{ + RejectMalformed: "REJECT_MALFORMED", + RejectInvalid: "REJECT_INVALID", + RejectObsolete: "REJECT_OBSOLETE", + RejectDuplicate: "REJECT_DUPLICATE", + RejectNonstandard: "REJECT_NONSTANDARD", + RejectDust: "REJECT_DUST", + RejectInsufficientFee: "REJECT_INSUFFICIENTFEE", + RejectCheckpoint: "REJECT_CHECKPOINT", +} + +// String returns the RejectCode in human-readable form. +func (code RejectCode) String() string { + if s, ok := rejectCodeStrings[code]; ok { + return s + } + + return fmt.Sprintf("Unknown RejectCode (%d)", uint8(code)) +} + +// MsgReject implements the Message interface and represents a bitcoin reject +// message. +// +// This message was not added until protocol version RejectVersion. +type MsgReject struct { + // Cmd is the command for the message which was rejected such as + // as cmdBlock or cmdTx. This can be obtained from the Command function + // of a Message. + Cmd string + + // RejectCode is a code indicating why the command was rejected. It + // is encoded as a uint8 on the wire. + Code RejectCode + + // Reason is a human-readable string with specific details (over and + // above the reject code) about why the command was rejected. + Reason string + + // Hash identifies a specific block or transaction that was rejected + // and therefore only applies the MsgBlock and MsgTx messages. + Hash ShaHash +} + +// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. +// This is part of the Message interface implementation. +func (msg *MsgReject) BtcDecode(r io.Reader, pver uint32) error { + if pver < RejectVersion { + str := fmt.Sprintf("reject message invalid for protocol "+ + "version %d", pver) + return messageError("MsgReject.BtcDecode", str) + } + + // Command that was rejected. + cmd, err := readVarString(r, pver) + if err != nil { + return err + } + msg.Cmd = cmd + + // Code indicating why the command was rejected. + err = readElement(r, &msg.Code) + if err != nil { + return err + } + + // Human readable string with specific details (over and above the + // reject code above) about why the command was rejected. + reason, err := readVarString(r, pver) + if err != nil { + return err + } + msg.Reason = reason + + // cmdBlock and cmdTx messages have an additional hash field that + // identifies the specific block or transaction. + if msg.Cmd == cmdBlock || msg.Cmd == cmdTx { + err := readElement(r, &msg.Hash) + if err != nil { + return err + } + } + + return nil +} + +// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. +// This is part of the Message interface implementation. +func (msg *MsgReject) BtcEncode(w io.Writer, pver uint32) error { + if pver < RejectVersion { + str := fmt.Sprintf("reject message invalid for protocol "+ + "version %d", pver) + return messageError("MsgReject.BtcEncode", str) + } + + // Command that was rejected. + err := writeVarString(w, pver, msg.Cmd) + if err != nil { + return err + } + + // Code indicating why the command was rejected. + err = writeElement(w, msg.Code) + if err != nil { + return err + } + + // Human readable string with specific details (over and above the + // reject code above) about why the command was rejected. + err = writeVarString(w, pver, msg.Reason) + if err != nil { + return err + } + + // cmdBlock and cmdTx messages have an additional hash field that + // identifies the specific block or transaction. + if msg.Cmd == cmdBlock || msg.Cmd == cmdTx { + err := writeElement(w, &msg.Hash) + if err != nil { + return err + } + } + + return nil +} + +// Command returns the protocol command string for the message. This is part +// of the Message interface implementation. +func (msg *MsgReject) Command() string { + return cmdReject +} + +// MaxPayloadLength returns the maximum length the payload can be for the +// receiver. This is part of the Message interface implementation. +func (msg *MsgReject) MaxPayloadLength(pver uint32) uint32 { + plen := uint32(0) + // The reject message did not exist before protocol version + // RejectVersion. + if pver >= RejectVersion { + // Unfortunately the bitcoin protocol does not enforce a sane + // limit on the length of the reason, so the max payload is the + // overall maximum message payload. + plen = maxMessagePayload + } + + return plen +} + +// NewMsgReject returns a new bitcoin reject message that conforms to the +// Message interface. See MsgReject for details. +func NewMsgReject(command string, code RejectCode, reason string) *MsgReject { + return &MsgReject{ + Cmd: command, + Code: code, + Reason: reason, + } +} diff --git a/protocol.go b/protocol.go index 7436c0b8..dbab3f23 100644 --- a/protocol.go +++ b/protocol.go @@ -45,6 +45,10 @@ const ( // bloom filtering related messages and extended the version message // with a relay flag (pver >= BIP0037Version). BIP0037Version uint32 = 70001 + + // RejectVersion is the protocol version which added a new reject + // message. + RejectVersion uint32 = 70002 ) // ServiceFlag identifies services supported by a bitcoin peer. From f38e5854c1047e6eb249ba3f9bf3eca8165814bf Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 11 Nov 2013 23:12:23 -0600 Subject: [PATCH 187/219] Bump protocol version to 70002. --- protocol.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol.go b/protocol.go index dbab3f23..1eb4f424 100644 --- a/protocol.go +++ b/protocol.go @@ -23,7 +23,7 @@ const ( RegressionTestPort = "18444" // ProtocolVersion is the latest protocol version this package supports. - ProtocolVersion uint32 = 70001 + ProtocolVersion uint32 = 70002 // MultipleAddressVersion is the protocol version which added multiple // addresses per message (pver >= MultipleAddressVersion). From a4978ba4c8a272c8a0dd710f5ddc797967113dba Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 23 Dec 2013 23:25:17 -0600 Subject: [PATCH 188/219] Add tests for the new MsgReject message. This commit adds a full suite tests for the new reject message added in protocol version 70002 to bring the overall test coverage of btcwire back up to 100%. Closes #9. --- message_test.go | 4 +- msgreject_test.go | 384 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 msgreject_test.go diff --git a/message_test.go b/message_test.go index bfbc8e1e..567533ac 100644 --- a/message_test.go +++ b/message_test.go @@ -71,10 +71,9 @@ func TestMessage(t *testing.T) { msgFilterAdd := btcwire.NewMsgFilterAdd([]byte{0x01}) msgFilterClear := btcwire.NewMsgFilterClear() msgFilterLoad := btcwire.NewMsgFilterLoad([]byte{0x01}, 10, 0, btcwire.BloomUpdateNone) - - // bh := btcwire.NewBlockHeader(&btcwire.ShaHash{}, &btcwire.ShaHash{}, 0, 0) msgMerkleBlock := btcwire.NewMsgMerkleBlock(bh) + msgReject := btcwire.NewMsgReject("block", btcwire.RejectDuplicate, "duplicate block") tests := []struct { in btcwire.Message // Value to encode @@ -103,6 +102,7 @@ func TestMessage(t *testing.T) { {msgFilterClear, msgFilterClear, pver, btcwire.MainNet, 24}, {msgFilterLoad, msgFilterLoad, pver, btcwire.MainNet, 35}, {msgMerkleBlock, msgMerkleBlock, pver, btcwire.MainNet, 110}, + {msgReject, msgReject, pver, btcwire.MainNet, 79}, } t.Logf("Running %d tests", len(tests)) diff --git a/msgreject_test.go b/msgreject_test.go new file mode 100644 index 00000000..33d3165c --- /dev/null +++ b/msgreject_test.go @@ -0,0 +1,384 @@ +// Copyright (c) 2014 Conformal Systems LLC. +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcwire_test + +import ( + "bytes" + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" + "io" + "reflect" + "testing" +) + +// TestRejectCodeStringer tests the stringized output for the reject code type. +func TestRejectCodeStringer(t *testing.T) { + tests := []struct { + in btcwire.RejectCode + want string + }{ + {btcwire.RejectMalformed, "REJECT_MALFORMED"}, + {btcwire.RejectInvalid, "REJECT_INVALID"}, + {btcwire.RejectObsolete, "REJECT_OBSOLETE"}, + {btcwire.RejectDuplicate, "REJECT_DUPLICATE"}, + {btcwire.RejectNonstandard, "REJECT_NONSTANDARD"}, + {btcwire.RejectDust, "REJECT_DUST"}, + {btcwire.RejectInsufficientFee, "REJECT_INSUFFICIENTFEE"}, + {btcwire.RejectCheckpoint, "REJECT_CHECKPOINT"}, + {0xff, "Unknown RejectCode (255)"}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + result := test.in.String() + if result != test.want { + t.Errorf("String #%d\n got: %s want: %s", i, result, + test.want) + continue + } + } + +} + +// TestRejectLatest tests the MsgPong API against the latest protocol version. +func TestRejectLatest(t *testing.T) { + pver := btcwire.ProtocolVersion + + // Create reject message data. + rejCommand := (&btcwire.MsgBlock{}).Command() + rejCode := btcwire.RejectDuplicate + rejReason := "duplicate block" + rejHash := btcwire.GenesisHash + + // Ensure we get the correct data back out. + msg := btcwire.NewMsgReject(rejCommand, rejCode, rejReason) + msg.Hash = rejHash + if msg.Cmd != rejCommand { + t.Errorf("NewMsgReject: wrong rejected command - got %v, "+ + "want %v", msg.Cmd, rejCommand) + } + if msg.Code != rejCode { + t.Errorf("NewMsgReject: wrong rejected code - got %v, "+ + "want %v", msg.Code, rejCode) + } + if msg.Reason != rejReason { + t.Errorf("NewMsgReject: wrong rejected reason - got %v, "+ + "want %v", msg.Reason, rejReason) + } + + // Ensure the command is expected value. + wantCmd := "reject" + if cmd := msg.Command(); cmd != wantCmd { + t.Errorf("NewMsgReject: wrong command - got %v want %v", + cmd, wantCmd) + } + + // Ensure max payload is expected value for latest protocol version. + wantPayload := btcwire.MaxMessagePayload + maxPayload := msg.MaxPayloadLength(pver) + if maxPayload != wantPayload { + t.Errorf("MaxPayloadLength: wrong max payload length for "+ + "protocol version %d - got %v, want %v", pver, + maxPayload, wantPayload) + } + + // Test encode with latest protocol version. + var buf bytes.Buffer + err := msg.BtcEncode(&buf, pver) + if err != nil { + t.Errorf("encode of MsgReject failed %v err <%v>", msg, err) + } + + // Test decode with latest protocol version. + readMsg := btcwire.MsgReject{} + err = readMsg.BtcDecode(&buf, pver) + if err != nil { + t.Errorf("decode of MsgReject failed %v err <%v>", buf.Bytes(), + err) + } + + // Ensure decoded data is the same. + if msg.Cmd != readMsg.Cmd { + t.Errorf("Should get same reject command - got %v, want %v", + readMsg.Cmd, msg.Cmd) + } + if msg.Code != readMsg.Code { + t.Errorf("Should get same reject code - got %v, want %v", + readMsg.Code, msg.Code) + } + if msg.Reason != readMsg.Reason { + t.Errorf("Should get same reject reason - got %v, want %v", + readMsg.Reason, msg.Reason) + } + if msg.Hash != readMsg.Hash { + t.Errorf("Should get same reject hash - got %v, want %v", + readMsg.Hash, msg.Hash) + } +} + +// TestRejectBeforeAdded tests the MsgReject API against a protocol version +// before the version which introduced it (RejectVersion). +func TestRejectBeforeAdded(t *testing.T) { + // Use the protocol version just prior to RejectVersion. + pver := btcwire.RejectVersion - 1 + + // Create reject message data. + rejCommand := (&btcwire.MsgBlock{}).Command() + rejCode := btcwire.RejectDuplicate + rejReason := "duplicate block" + rejHash := btcwire.GenesisHash + + msg := btcwire.NewMsgReject(rejCommand, rejCode, rejReason) + msg.Hash = rejHash + + // Ensure max payload is expected value for old protocol version. + size := msg.MaxPayloadLength(pver) + if size != 0 { + t.Errorf("Max length should be 0 for reject protocol version %d.", + pver) + } + + // Test encode with old protocol version. + var buf bytes.Buffer + err := msg.BtcEncode(&buf, pver) + if err == nil { + t.Errorf("encode of MsgReject succeeded when it shouldn't "+ + "have %v", msg) + } + + // // Test decode with old protocol version. + readMsg := btcwire.MsgReject{} + err = readMsg.BtcDecode(&buf, pver) + if err == nil { + t.Errorf("decode of MsgReject succeeded when it shouldn't "+ + "have %v", spew.Sdump(buf.Bytes())) + } + + // Since this protocol version doesn't support reject, make sure various + // fields didn't get encoded and decoded back out. + if msg.Cmd == readMsg.Cmd { + t.Errorf("Should not get same reject command for protocol "+ + "version %d", pver) + } + if msg.Code == readMsg.Code { + t.Errorf("Should not get same reject code for protocol "+ + "version %d", pver) + } + if msg.Reason == readMsg.Reason { + t.Errorf("Should not get same reject reason for protocol "+ + "version %d", pver) + } + if msg.Hash == readMsg.Hash { + t.Errorf("Should not get same reject hash for protocol "+ + "version %d", pver) + } +} + +// TestRejectCrossProtocol tests the MsgReject API when encoding with the latest +// protocol version and decoded with a version before the version which +// introduced it (RejectVersion). +func TestRejectCrossProtocol(t *testing.T) { + // Create reject message data. + rejCommand := (&btcwire.MsgBlock{}).Command() + rejCode := btcwire.RejectDuplicate + rejReason := "duplicate block" + rejHash := btcwire.GenesisHash + + msg := btcwire.NewMsgReject(rejCommand, rejCode, rejReason) + msg.Hash = rejHash + + // Encode with latest protocol version. + var buf bytes.Buffer + err := msg.BtcEncode(&buf, btcwire.ProtocolVersion) + if err != nil { + t.Errorf("encode of MsgReject failed %v err <%v>", msg, err) + } + + // Decode with old protocol version. + readMsg := btcwire.MsgReject{} + err = readMsg.BtcDecode(&buf, btcwire.RejectVersion-1) + if err == nil { + t.Errorf("encode of MsgReject succeeded when it shouldn't "+ + "have %v", msg) + } + + // Since one of the protocol versions doesn't support the reject + // message, make sure the various fields didn't get encoded and decoded + // back out. + if msg.Cmd == readMsg.Cmd { + t.Errorf("Should not get same reject command for cross protocol") + } + if msg.Code == readMsg.Code { + t.Errorf("Should not get same reject code for cross protocol") + } + if msg.Reason == readMsg.Reason { + t.Errorf("Should not get same reject reason for cross protocol") + } + if msg.Hash == readMsg.Hash { + t.Errorf("Should not get same reject hash for cross protocol") + } +} + +// TestRejectWire tests the MsgReject wire encode and decode for various +// protocol versions. +func TestRejectWire(t *testing.T) { + tests := []struct { + msg btcwire.MsgReject // Message to encode + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + }{ + // Latest protocol version rejected command version (no hash). + { + btcwire.MsgReject{ + Cmd: "version", + Code: btcwire.RejectDuplicate, + Reason: "duplicate version", + }, + []byte{ + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, // "version" + 0x12, // btcwire.RejectDuplicate + 0x11, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, // "duplicate version" + }, + btcwire.ProtocolVersion, + }, + // Latest protocol version rejected command block (has hash). + { + btcwire.MsgReject{ + Cmd: "block", + Code: btcwire.RejectDuplicate, + Reason: "duplicate block", + Hash: btcwire.GenesisHash, + }, + []byte{ + 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, // "block" + 0x12, // btcwire.RejectDuplicate + 0x0f, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, // "duplicate block" + 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, // btcwire.GenesisHash + }, + btcwire.ProtocolVersion, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + // Encode the message to wire format. + var buf bytes.Buffer + err := test.msg.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.MsgReject + 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.msg) { + t.Errorf("BtcDecode #%d\n got: %s want: %s", i, + spew.Sdump(msg), spew.Sdump(test.msg)) + continue + } + } +} + +// TestRejectWireErrors performs negative tests against wire encode and decode +// of MsgReject to confirm error paths work correctly. +func TestRejectWireErrors(t *testing.T) { + pver := btcwire.ProtocolVersion + pverNoReject := btcwire.RejectVersion - 1 + btcwireErr := &btcwire.MessageError{} + + baseReject := btcwire.NewMsgReject("block", btcwire.RejectDuplicate, + "duplicate block") + baseReject.Hash = btcwire.GenesisHash + baseRejectEncoded := []byte{ + 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, // "block" + 0x12, // btcwire.RejectDuplicate + 0x0f, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, // "duplicate block" + 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, // btcwire.GenesisHash + } + + tests := []struct { + in *btcwire.MsgReject // 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 error in reject command. + {baseReject, baseRejectEncoded, pver, 0, io.ErrShortWrite, io.EOF}, + // Force error in reject code. + {baseReject, baseRejectEncoded, pver, 6, io.ErrShortWrite, io.EOF}, + // Force error in reject reason. + {baseReject, baseRejectEncoded, pver, 7, io.ErrShortWrite, io.EOF}, + // Force error in reject hash. + {baseReject, baseRejectEncoded, pver, 23, io.ErrShortWrite, io.EOF}, + // Force error due to unsupported protocol version. + {baseReject, baseRejectEncoded, pverNoReject, 6, 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.MsgReject + 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 + } + } + } +} From dfdd2232237b2a40fd456851506272b110c49053 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 28 May 2014 00:26:47 -0500 Subject: [PATCH 189/219] Move genesis blocks to btcnet package. The genesis blocks are not really part of the wire protocol rather they are part of a network parameters. Thus, this commit moves the all of the gensis blocks and tests to the btcnet package. Also, create variables in the test package for the mainnet genesis hash, merkle root, and coinbase transaction for use throughout the tests since they the exported values are no longer available. --- bench_test.go | 47 ++++++++- blockheader_test.go | 16 ++- common_test.go | 18 ++++ genesis.go | 141 ------------------------- genesis_test.go | 233 ------------------------------------------ msggetblocks_test.go | 4 +- msggetheaders_test.go | 4 +- msgheaders_test.go | 4 +- msgreject_test.go | 14 +-- shahash_test.go | 4 +- 10 files changed, 84 insertions(+), 401 deletions(-) delete mode 100644 genesis.go delete mode 100644 genesis_test.go diff --git a/bench_test.go b/bench_test.go index dda4fb14..45aec7b7 100644 --- a/bench_test.go +++ b/bench_test.go @@ -11,6 +11,50 @@ import ( "testing" ) +// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for +// the main network, regression test network, and test network (version 3). +var genesisCoinbaseTx = btcwire.MsgTx{ + Version: 1, + TxIn: []*btcwire.TxIn{ + { + PreviousOutpoint: btcwire.OutPoint{ + Hash: btcwire.ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ + 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ + 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ + 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ + 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ + 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ + 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ + 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ + 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ + }, + Sequence: 0xffffffff, + }, + }, + TxOut: []*btcwire.TxOut{ + { + Value: 0x12a05f200, + PkScript: []byte{ + 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ + 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ + 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ + 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ + 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ + 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ + 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ + 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ + 0x1d, 0x5f, 0xac, /* |._.| */ + }, + }, + }, + LockTime: 0, +} + // BenchmarkWriteVarInt1 performs a benchmark on how long it takes to write // a single byte variable length integer. func BenchmarkWriteVarInt1(b *testing.B) { @@ -285,8 +329,7 @@ func BenchmarkWriteBlockHeader(b *testing.B) { // BenchmarkTxSha performs a benchmark on how long it takes to hash a // transaction. func BenchmarkTxSha(b *testing.B) { - tx := btcwire.GenesisBlock.Transactions[0] for i := 0; i < b.N; i++ { - tx.TxSha() + genesisCoinbaseTx.TxSha() } } diff --git a/blockheader_test.go b/blockheader_test.go index 903e7c34..d5054a05 100644 --- a/blockheader_test.go +++ b/blockheader_test.go @@ -21,8 +21,8 @@ func TestBlockHeader(t *testing.T) { } nonce := uint32(nonce64) - hash := btcwire.GenesisHash - merkleHash := btcwire.GenesisMerkleRoot + hash := mainNetGenesisHash + merkleHash := mainNetGenesisMerkleRoot bits := uint32(0x1d00ffff) bh := btcwire.NewBlockHeader(&hash, &merkleHash, bits, nonce) @@ -51,13 +51,11 @@ func TestBlockHeaderWire(t *testing.T) { nonce := uint32(123123) // 0x1e0f3 // baseBlockHdr is used in the various tests as a baseline BlockHeader. - hash := btcwire.GenesisHash - merkleHash := btcwire.GenesisMerkleRoot bits := uint32(0x1d00ffff) baseBlockHdr := &btcwire.BlockHeader{ Version: 1, - PrevBlock: hash, - MerkleRoot: merkleHash, + PrevBlock: mainNetGenesisHash, + MerkleRoot: mainNetGenesisMerkleRoot, Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST Bits: bits, Nonce: nonce, @@ -162,13 +160,11 @@ func TestBlockHeaderSerialize(t *testing.T) { nonce := uint32(123123) // 0x1e0f3 // baseBlockHdr is used in the various tests as a baseline BlockHeader. - hash := btcwire.GenesisHash - merkleHash := btcwire.GenesisMerkleRoot bits := uint32(0x1d00ffff) baseBlockHdr := &btcwire.BlockHeader{ Version: 1, - PrevBlock: hash, - MerkleRoot: merkleHash, + PrevBlock: mainNetGenesisHash, + MerkleRoot: mainNetGenesisMerkleRoot, Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST Bits: bits, Nonce: nonce, diff --git a/common_test.go b/common_test.go index b9418974..4e5fe59b 100644 --- a/common_test.go +++ b/common_test.go @@ -15,6 +15,24 @@ import ( "testing" ) +// mainNetGenesisHash is the hash of the first block in the block chain for the +// main network (genesis block). +var mainNetGenesisHash = btcwire.ShaHash{ + 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 = btcwire.ShaHash{ + 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 { diff --git a/genesis.go b/genesis.go deleted file mode 100644 index adbfbb0b..00000000 --- a/genesis.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package btcwire - -import ( - "time" -) - -// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for -// the main network, regression test network, and test network (version 3). -var genesisCoinbaseTx = MsgTx{ - Version: 1, - TxIn: []*TxIn{ - { - PreviousOutpoint: OutPoint{ - Hash: ShaHash{}, - Index: 0xffffffff, - }, - SignatureScript: []byte{ - 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ - 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ - 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ - 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ - 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ - 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ - 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ - 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ - 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ - }, - Sequence: 0xffffffff, - }, - }, - TxOut: []*TxOut{ - { - Value: 0x12a05f200, - PkScript: []byte{ - 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ - 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ - 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ - 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ - 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ - 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ - 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ - 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ - 0x1d, 0x5f, 0xac, /* |._.| */ - }, - }, - }, - LockTime: 0, -} - -// GenesisHash is the hash of the first block in the block chain for the main -// network (genesis block). -var GenesisHash = ShaHash{ - 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, -} - -// GenesisMerkleRoot is the hash of the first transaction in the genesis block -// for the main network. -var GenesisMerkleRoot = ShaHash{ - 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, -} - -// GenesisBlock defines the genesis block of the block chain which serves as the -// public transaction ledger for the main network. -var GenesisBlock = MsgBlock{ - Header: BlockHeader{ - Version: 1, - PrevBlock: ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 - MerkleRoot: GenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b - Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 18:15:05 +0000 UTC - Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] - Nonce: 0x7c2bac1d, // 2083236893 - }, - Transactions: []*MsgTx{&genesisCoinbaseTx}, -} - -// TestNetGenesisHash is the hash of the first block in the block chain for the -// regression test network (genesis block). -var TestNetGenesisHash = ShaHash{ - 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, - 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, - 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, - 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, -} - -// TestNetGenesisMerkleRoot is the hash of the first transaction in the genesis -// block for the regression test network. It is the same as the merkle root for -// the main network. -var TestNetGenesisMerkleRoot = GenesisMerkleRoot - -// TestNetGenesisBlock defines the genesis block of the block chain which serves -// as the public transaction ledger for the regression test network. -var TestNetGenesisBlock = MsgBlock{ - Header: BlockHeader{ - Version: 1, - PrevBlock: ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 - MerkleRoot: TestNetGenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b - Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC - Bits: 0x207fffff, // 545259519 [7fffff0000000000000000000000000000000000000000000000000000000000] - Nonce: 2, - }, - Transactions: []*MsgTx{&genesisCoinbaseTx}, -} - -// TestNet3GenesisHash is the hash of the first block in the block chain for the -// test network (version 3). -var TestNet3GenesisHash = ShaHash{ - 0x43, 0x49, 0x7f, 0xd7, 0xf8, 0x26, 0x95, 0x71, - 0x08, 0xf4, 0xa3, 0x0f, 0xd9, 0xce, 0xc3, 0xae, - 0xba, 0x79, 0x97, 0x20, 0x84, 0xe9, 0x0e, 0xad, - 0x01, 0xea, 0x33, 0x09, 0x00, 0x00, 0x00, 0x00, -} - -// TestNet3GenesisMerkleRoot is the hash of the first transaction in the genesis -// block for the test network (version 3). It is the same as the merkle root -// for the main network. -var TestNet3GenesisMerkleRoot = GenesisMerkleRoot - -// TestNet3GenesisBlock defines the genesis block of the block chain which -// serves as the public transaction ledger for the test network (version 3). -var TestNet3GenesisBlock = MsgBlock{ - Header: BlockHeader{ - Version: 1, - PrevBlock: ShaHash{}, // 0000000000000000000000000000000000000000000000000000000000000000 - MerkleRoot: TestNet3GenesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b - Timestamp: time.Unix(1296688602, 0), // 2011-02-02 23:16:42 +0000 UTC - Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000] - Nonce: 0x18aea41a, // 414098458 - }, - Transactions: []*MsgTx{&genesisCoinbaseTx}, -} diff --git a/genesis_test.go b/genesis_test.go deleted file mode 100644 index 5e0529e0..00000000 --- a/genesis_test.go +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -package btcwire_test - -import ( - "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" - "testing" -) - -// TestGenesisBlock tests the genesis block of the main network for validity by -// checking the encoded bytes and hashes. -func TestGenesisBlock(t *testing.T) { - // Encode the genesis block to raw bytes. - var buf bytes.Buffer - err := btcwire.GenesisBlock.Serialize(&buf) - if err != nil { - t.Errorf("TestGenesisBlock: %v", err) - return - } - - // Ensure the encoded block matches the expected bytes. - if !bytes.Equal(buf.Bytes(), genesisBlockBytes) { - t.Errorf("TestGenesisBlock: Genesis block does not appear valid - "+ - "got %v, want %v", spew.Sdump(buf.Bytes()), - spew.Sdump(genesisBlockBytes)) - return - } - - // Check hash of the block against expected hash. - hash, err := btcwire.GenesisBlock.BlockSha() - if err != nil { - t.Errorf("BlockSha: %v", err) - } - if !btcwire.GenesisHash.IsEqual(&hash) { - t.Errorf("TestGenesisBlock: Genesis block hash does not appear valid - "+ - "got %v, want %v", spew.Sdump(hash), - spew.Sdump(btcwire.GenesisHash)) - return - } -} - -// TestTestNetGenesisBlock tests the genesis block of the regression test -// network for validity by checking the encoded bytes and hashes. -func TestTestNetGenesisBlock(t *testing.T) { - // Encode the genesis block to raw bytes. - var buf bytes.Buffer - err := btcwire.TestNetGenesisBlock.Serialize(&buf) - if err != nil { - t.Errorf("TestTestNetGenesisBlock: %v", err) - return - } - - // Ensure the encoded block matches the expected bytes. - if !bytes.Equal(buf.Bytes(), testNetGenesisBlockBytes) { - t.Errorf("TestTestNetGenesisBlock: Genesis block does not "+ - "appear valid - got %v, want %v", - spew.Sdump(buf.Bytes()), - spew.Sdump(testNetGenesisBlockBytes)) - return - } - - // Check hash of the block against expected hash. - hash, err := btcwire.TestNetGenesisBlock.BlockSha() - if err != nil { - t.Errorf("BlockSha: %v", err) - } - if !btcwire.TestNetGenesisHash.IsEqual(&hash) { - t.Errorf("TestTestNetGenesisBlock: Genesis block hash does "+ - "not appear valid - got %v, want %v", spew.Sdump(hash), - spew.Sdump(btcwire.TestNetGenesisHash)) - return - } -} - -// TestTestNet3GenesisBlock tests the genesis block of the test network (version -// 3) for validity by checking the encoded bytes and hashes. -func TestTestNet3GenesisBlock(t *testing.T) { - // Encode the genesis block to raw bytes. - var buf bytes.Buffer - err := btcwire.TestNet3GenesisBlock.Serialize(&buf) - if err != nil { - t.Errorf("TestTestNet3GenesisBlock: %v", err) - return - } - - // Ensure the encoded block matches the expected bytes. - if !bytes.Equal(buf.Bytes(), testNet3GenesisBlockBytes) { - t.Errorf("TestTestNet3GenesisBlock: Genesis block does not "+ - "appear valid - got %v, want %v", - spew.Sdump(buf.Bytes()), - spew.Sdump(testNet3GenesisBlockBytes)) - return - } - - // Check hash of the block against expected hash. - hash, err := btcwire.TestNet3GenesisBlock.BlockSha() - if err != nil { - t.Errorf("BlockSha: %v", err) - } - if !btcwire.TestNet3GenesisHash.IsEqual(&hash) { - t.Errorf("TestTestNet3GenesisBlock: Genesis block hash does "+ - "not appear valid - got %v, want %v", spew.Sdump(hash), - spew.Sdump(btcwire.TestNet3GenesisHash)) - return - } -} - -// genesisBlockBytes are the wire encoded bytes for the genesis block of the -// main network as of protocol version 60002. -var genesisBlockBytes = []byte{ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */ - 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */ - 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */ - 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */ - 0x4b, 0x1e, 0x5e, 0x4a, 0x29, 0xab, 0x5f, 0x49, /* |K.^J)._I| */ - 0xff, 0xff, 0x00, 0x1d, 0x1d, 0xac, 0x2b, 0x7c, /* |......+|| */ - 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */ - 0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */ - 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */ - 0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */ - 0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */ - 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */ - 0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */ - 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */ - 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */ - 0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */ - 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */ - 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */ - 0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */ - 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */ - 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */ - 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */ - 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */ - 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */ - 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */ - 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */ - 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ - 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ -} - -// testNetGenesisBlockBytes are the wire encoded bytes for the genesis block of -// the regression test network as of protocol version 60002. -var testNetGenesisBlockBytes = []byte{ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */ - 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */ - 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */ - 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */ - 0x4b, 0x1e, 0x5e, 0x4a, 0xda, 0xe5, 0x49, 0x4d, /* |K.^J)._I| */ - 0xff, 0xff, 0x7f, 0x20, 0x02, 0x00, 0x00, 0x00, /* |......+|| */ - 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */ - 0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */ - 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */ - 0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */ - 0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */ - 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */ - 0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */ - 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */ - 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */ - 0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */ - 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */ - 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */ - 0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */ - 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */ - 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */ - 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */ - 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */ - 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */ - 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */ - 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */ - 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ - 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ -} - -// testNet3GenesisBlockBytes are the wire encoded bytes for the genesis block of -// the test network (version 3) as of protocol version 60002. -var testNet3GenesisBlockBytes = []byte{ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x3b, 0xa3, 0xed, 0xfd, /* |....;...| */ - 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, /* |z{..z.,>| */ - 0x67, 0x76, 0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, /* |gv.a....| */ - 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa, /* |..Q2:...| */ - 0x4b, 0x1e, 0x5e, 0x4a, 0xda, 0xe5, 0x49, 0x4d, /* |K.^J)._I| */ - 0xff, 0xff, 0x00, 0x1d, 0x1a, 0xa4, 0xae, 0x18, /* |......+|| */ - 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* |........| */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* |........| */ - 0xff, 0xff, 0x4d, 0x04, 0xff, 0xff, 0x00, 0x1d, /* |..M.....| */ - 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54, /* |..EThe T| */ - 0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, /* |imes 03/| */ - 0x4a, 0x61, 0x6e, 0x2f, 0x32, 0x30, 0x30, 0x39, /* |Jan/2009| */ - 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, /* | Chancel| */ - 0x6c, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, /* |lor on b| */ - 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66, 0x20, /* |rink of | */ - 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, /* |second b| */ - 0x61, 0x69, 0x6c, 0x6f, 0x75, 0x74, 0x20, 0x66, /* |ailout f| */ - 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |or banks| */ - 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0xf2, 0x05, /* |........| */ - 0x2a, 0x01, 0x00, 0x00, 0x00, 0x43, 0x41, 0x04, /* |*....CA.| */ - 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, /* |g....UH'| */ - 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, /* |.g..q0..| */ - 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, /* |\..(.9..| */ - 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, /* |yb...a..| */ - 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, /* |I..?L.8.| */ - 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, /* |.U......| */ - 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, /* |\8M....W| */ - 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, /* |.Lp+k.._|*/ - 0xac, 0x00, 0x00, 0x00, 0x00, /* |.....| */ -} diff --git a/msggetblocks_test.go b/msggetblocks_test.go index 2b8482d8..3fea8c59 100644 --- a/msggetblocks_test.go +++ b/msggetblocks_test.go @@ -316,10 +316,10 @@ func TestGetBlocksWireErrors(t *testing.T) { // block locator hashes. maxGetBlocks := btcwire.NewMsgGetBlocks(hashStop) for i := 0; i < btcwire.MaxBlockLocatorsPerMsg; i++ { - maxGetBlocks.AddBlockLocatorHash(&btcwire.GenesisHash) + maxGetBlocks.AddBlockLocatorHash(&mainNetGenesisHash) } maxGetBlocks.BlockLocatorHashes = append(maxGetBlocks.BlockLocatorHashes, - &btcwire.GenesisHash) + &mainNetGenesisHash) maxGetBlocksEncoded := []byte{ 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 0xfd, 0xf5, 0x01, // Varint for number of block loc hashes (501) diff --git a/msggetheaders_test.go b/msggetheaders_test.go index ca8a2ebc..a5e61edd 100644 --- a/msggetheaders_test.go +++ b/msggetheaders_test.go @@ -307,10 +307,10 @@ func TestGetHeadersWireErrors(t *testing.T) { // block locator hashes. maxGetHeaders := btcwire.NewMsgGetHeaders() for i := 0; i < btcwire.MaxBlockLocatorsPerMsg; i++ { - maxGetHeaders.AddBlockLocatorHash(&btcwire.GenesisHash) + maxGetHeaders.AddBlockLocatorHash(&mainNetGenesisHash) } maxGetHeaders.BlockLocatorHashes = append(maxGetHeaders.BlockLocatorHashes, - &btcwire.GenesisHash) + &mainNetGenesisHash) maxGetHeadersEncoded := []byte{ 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 0xfd, 0xf5, 0x01, // Varint for number of block loc hashes (501) diff --git a/msgheaders_test.go b/msgheaders_test.go index 1eec69e1..99911fbc 100644 --- a/msgheaders_test.go +++ b/msgheaders_test.go @@ -62,7 +62,7 @@ func TestHeaders(t *testing.T) { // TestHeadersWire tests the MsgHeaders wire encode and decode for various // numbers of headers and protocol versions. func TestHeadersWire(t *testing.T) { - hash := btcwire.GenesisHash + hash := mainNetGenesisHash merkleHash := blockOne.Header.MerkleRoot bits := uint32(0x1d00ffff) nonce := uint32(0x9962e301) @@ -219,7 +219,7 @@ func TestHeadersWireErrors(t *testing.T) { pver := btcwire.ProtocolVersion btcwireErr := &btcwire.MessageError{} - hash := btcwire.GenesisHash + hash := mainNetGenesisHash merkleHash := blockOne.Header.MerkleRoot bits := uint32(0x1d00ffff) nonce := uint32(0x9962e301) diff --git a/msgreject_test.go b/msgreject_test.go index 33d3165c..ca425ac1 100644 --- a/msgreject_test.go +++ b/msgreject_test.go @@ -50,7 +50,7 @@ func TestRejectLatest(t *testing.T) { rejCommand := (&btcwire.MsgBlock{}).Command() rejCode := btcwire.RejectDuplicate rejReason := "duplicate block" - rejHash := btcwire.GenesisHash + rejHash := mainNetGenesisHash // Ensure we get the correct data back out. msg := btcwire.NewMsgReject(rejCommand, rejCode, rejReason) @@ -128,7 +128,7 @@ func TestRejectBeforeAdded(t *testing.T) { rejCommand := (&btcwire.MsgBlock{}).Command() rejCode := btcwire.RejectDuplicate rejReason := "duplicate block" - rejHash := btcwire.GenesisHash + rejHash := mainNetGenesisHash msg := btcwire.NewMsgReject(rejCommand, rejCode, rejReason) msg.Hash = rejHash @@ -184,7 +184,7 @@ func TestRejectCrossProtocol(t *testing.T) { rejCommand := (&btcwire.MsgBlock{}).Command() rejCode := btcwire.RejectDuplicate rejReason := "duplicate block" - rejHash := btcwire.GenesisHash + rejHash := mainNetGenesisHash msg := btcwire.NewMsgReject(rejCommand, rejCode, rejReason) msg.Hash = rejHash @@ -251,7 +251,7 @@ func TestRejectWire(t *testing.T) { Cmd: "block", Code: btcwire.RejectDuplicate, Reason: "duplicate block", - Hash: btcwire.GenesisHash, + Hash: mainNetGenesisHash, }, []byte{ 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, // "block" @@ -261,7 +261,7 @@ func TestRejectWire(t *testing.T) { 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, // btcwire.GenesisHash + 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, // mainNetGenesisHash }, btcwire.ProtocolVersion, }, @@ -307,7 +307,7 @@ func TestRejectWireErrors(t *testing.T) { baseReject := btcwire.NewMsgReject("block", btcwire.RejectDuplicate, "duplicate block") - baseReject.Hash = btcwire.GenesisHash + baseReject.Hash = mainNetGenesisHash baseRejectEncoded := []byte{ 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, // "block" 0x12, // btcwire.RejectDuplicate @@ -316,7 +316,7 @@ func TestRejectWireErrors(t *testing.T) { 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, // btcwire.GenesisHash + 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, // mainNetGenesisHash } tests := []struct { diff --git a/shahash_test.go b/shahash_test.go index e13c5849..af6565ef 100644 --- a/shahash_test.go +++ b/shahash_test.go @@ -104,14 +104,14 @@ func TestNewShaHashFromStr(t *testing.T) { // Genesis hash. { "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", - btcwire.GenesisHash, + mainNetGenesisHash, nil, }, // Genesis hash with stripped leading zeros. { "19d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", - btcwire.GenesisHash, + mainNetGenesisHash, nil, }, From c4135db7288579b2503007d1de88936e33d90033 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 29 May 2014 11:59:49 -0500 Subject: [PATCH 190/219] Move default network ports to btcnet package. The default network ports are not really part of the wire protocol rather they are part of a network parameters. Thus, this commit moves them to the btcnet package. --- protocol.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/protocol.go b/protocol.go index 1eb4f424..d5de61cb 100644 --- a/protocol.go +++ b/protocol.go @@ -11,17 +11,6 @@ import ( ) const ( - // MainPort is the port used by default on the main network. - MainPort = "8333" - - // TestNetPort is the port used by default on the test network (version - // 3). - TestNetPort = "18333" - - // RegressionTestPort is the port used by default on the regression test - // network. - RegressionTestPort = "18444" - // ProtocolVersion is the latest protocol version this package supports. ProtocolVersion uint32 = 70002 From 31ee545aa932a360079512ca174980af5687715c Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 28 May 2014 10:28:10 -0500 Subject: [PATCH 191/219] Add bitcoin network type for simulation testing. --- protocol.go | 4 ++++ protocol_test.go | 1 + 2 files changed, 5 insertions(+) diff --git a/protocol.go b/protocol.go index d5de61cb..89f0fcd2 100644 --- a/protocol.go +++ b/protocol.go @@ -94,6 +94,9 @@ const ( // TestNet3 represents the test network (version 3). TestNet3 BitcoinNet = 0x0709110b + + // SimNet represents the simulation test network. + SimNet BitcoinNet = 0x12141c16 ) // bnStrings is a map of bitcoin networks back to their constant names for @@ -102,6 +105,7 @@ var bnStrings = map[BitcoinNet]string{ MainNet: "MainNet", TestNet: "TestNet", TestNet3: "TestNet3", + SimNet: "SimNet", } // String returns the BitcoinNet in human-readable form. diff --git a/protocol_test.go b/protocol_test.go index 3eb79939..61a59aaa 100644 --- a/protocol_test.go +++ b/protocol_test.go @@ -40,6 +40,7 @@ func TestBitcoinNetStringer(t *testing.T) { {btcwire.MainNet, "MainNet"}, {btcwire.TestNet, "TestNet"}, {btcwire.TestNet3, "TestNet3"}, + {btcwire.SimNet, "SimNet"}, {0xffffffff, "Unknown BitcoinNet (4294967295)"}, } From 2054fa7581fb25f3cbb8b798af15cc5208935ec8 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 2 Jun 2014 12:34:23 -0500 Subject: [PATCH 192/219] Update doc.go to reflect reality. This commit updates doc.go to include the new simulation test network magic constant as well as remove the information about BIP0037 not being supported since that is no longer true. --- doc.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/doc.go b/doc.go index f43328f5..e97530a8 100644 --- a/doc.go +++ b/doc.go @@ -86,6 +86,7 @@ the following constants: btcwire.MainNet btcwire.TestNet (Regression test network) btcwire.TestNet3 (Test network version 3) + btcwire.SimNet (Simulation test network) Determining Message Type @@ -154,11 +155,5 @@ This package includes spec changes outlined by the following BIPs: 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 - -The package does not yet implement BIP0037 (https://en.bitcoin.it/wiki/BIP_0037) -and therefore does not recognize filterload, filteradd, filterclear, or -merkleblock messages. */ package btcwire From ee46a0b108acc5eb099ad88fcecddd87c6867700 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 4 Jun 2014 23:39:03 -0500 Subject: [PATCH 193/219] Use bytes.NewReader for deserialize when possible. Rather than using bytes.NewBuffer, which is a read/write entity (io.ReadWriter), use bytes.NewReader which is only a read entitiy (io.Reader) in all cases where it is possible. Benchmarking shows it's slightly faster and it's also technically more accurate since it ensures the data is read-only. There are a few cases where bytes.NewBuffer must still be used since a buffer with a known length is required for those instances. --- bench_test.go | 22 +++++++++++----------- blockheader_test.go | 4 ++-- common_test.go | 12 ++++++------ invvect_test.go | 2 +- message.go | 5 +++-- message_test.go | 4 ++-- msgaddr_test.go | 2 +- msgalert_test.go | 6 +++--- msgblock_test.go | 20 ++++++++++---------- msgfilterclear_test.go | 2 +- msgfilterload_test.go | 3 +-- msggetaddr_test.go | 2 +- msggetblocks_test.go | 2 +- msggetdata_test.go | 2 +- msggetheaders_test.go | 2 +- msgheaders_test.go | 2 +- msginv_test.go | 2 +- msgmerkleblock_test.go | 2 +- msgnotfound_test.go | 2 +- msgping_test.go | 2 +- msgpong_test.go | 2 +- msgreject_test.go | 2 +- msgtx_test.go | 8 ++++---- msgverack_test.go | 2 +- netaddress_test.go | 2 +- 25 files changed, 58 insertions(+), 58 deletions(-) diff --git a/bench_test.go b/bench_test.go index 45aec7b7..10b76f1d 100644 --- a/bench_test.go +++ b/bench_test.go @@ -92,7 +92,7 @@ func BenchmarkWriteVarInt9(b *testing.B) { func BenchmarkReadVarInt1(b *testing.B) { buf := []byte{0x01} for i := 0; i < b.N; i++ { - btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0) + btcwire.TstReadVarInt(bytes.NewReader(buf), 0) } } @@ -101,7 +101,7 @@ func BenchmarkReadVarInt1(b *testing.B) { func BenchmarkReadVarInt3(b *testing.B) { buf := []byte{0x0fd, 0xff, 0xff} for i := 0; i < b.N; i++ { - btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0) + btcwire.TstReadVarInt(bytes.NewReader(buf), 0) } } @@ -110,7 +110,7 @@ func BenchmarkReadVarInt3(b *testing.B) { func BenchmarkReadVarInt5(b *testing.B) { buf := []byte{0xfe, 0xff, 0xff, 0xff, 0xff} for i := 0; i < b.N; i++ { - btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0) + btcwire.TstReadVarInt(bytes.NewReader(buf), 0) } } @@ -119,7 +119,7 @@ func BenchmarkReadVarInt5(b *testing.B) { func BenchmarkReadVarInt9(b *testing.B) { buf := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} for i := 0; i < b.N; i++ { - btcwire.TstReadVarInt(bytes.NewBuffer(buf), 0) + btcwire.TstReadVarInt(bytes.NewReader(buf), 0) } } @@ -128,7 +128,7 @@ func BenchmarkReadVarInt9(b *testing.B) { func BenchmarkReadVarStr4(b *testing.B) { buf := []byte{0x04, 't', 'e', 's', 't'} for i := 0; i < b.N; i++ { - btcwire.TstReadVarString(bytes.NewBuffer(buf), 0) + btcwire.TstReadVarString(bytes.NewReader(buf), 0) } } @@ -137,7 +137,7 @@ func BenchmarkReadVarStr4(b *testing.B) { func BenchmarkReadVarStr10(b *testing.B) { buf := []byte{0x0a, 't', 'e', 's', 't', '0', '1', '2', '3', '4', '5'} for i := 0; i < b.N; i++ { - btcwire.TstReadVarString(bytes.NewBuffer(buf), 0) + btcwire.TstReadVarString(bytes.NewReader(buf), 0) } } @@ -169,7 +169,7 @@ func BenchmarkReadOutPoint(b *testing.B) { } var op btcwire.OutPoint for i := 0; i < b.N; i++ { - btcwire.TstReadOutPoint(bytes.NewBuffer(buf), 0, 0, &op) + btcwire.TstReadOutPoint(bytes.NewReader(buf), 0, 0, &op) } } @@ -205,7 +205,7 @@ func BenchmarkReadTxOut(b *testing.B) { } var txOut btcwire.TxOut for i := 0; i < b.N; i++ { - btcwire.TstReadTxOut(bytes.NewBuffer(buf), 0, 0, &txOut) + btcwire.TstReadTxOut(bytes.NewReader(buf), 0, 0, &txOut) } } @@ -233,7 +233,7 @@ func BenchmarkReadTxIn(b *testing.B) { } var txIn btcwire.TxIn for i := 0; i < b.N; i++ { - btcwire.TstReadTxIn(bytes.NewBuffer(buf), 0, 0, &txIn) + btcwire.TstReadTxIn(bytes.NewReader(buf), 0, 0, &txIn) } } @@ -278,7 +278,7 @@ func BenchmarkDeserializeTx(b *testing.B) { } var tx btcwire.MsgTx for i := 0; i < b.N; i++ { - tx.Deserialize(bytes.NewBuffer(buf)) + tx.Deserialize(bytes.NewReader(buf)) } } @@ -313,7 +313,7 @@ func BenchmarkReadBlockHeader(b *testing.B) { } var header btcwire.BlockHeader for i := 0; i < b.N; i++ { - btcwire.TstReadBlockHeader(bytes.NewBuffer(buf), 0, &header) + btcwire.TstReadBlockHeader(bytes.NewReader(buf), 0, &header) } } diff --git a/blockheader_test.go b/blockheader_test.go index d5054a05..b01a3ecd 100644 --- a/blockheader_test.go +++ b/blockheader_test.go @@ -141,7 +141,7 @@ func TestBlockHeaderWire(t *testing.T) { // Decode the block header from wire format. var bh btcwire.BlockHeader - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = btcwire.TstReadBlockHeader(rbuf, test.pver, &bh) if err != nil { t.Errorf("readBlockHeader #%d error %v", i, err) @@ -215,7 +215,7 @@ func TestBlockHeaderSerialize(t *testing.T) { // Deserialize the block header. var bh btcwire.BlockHeader - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = bh.Deserialize(rbuf) if err != nil { t.Errorf("Deserialize #%d error %v", i, err) diff --git a/common_test.go b/common_test.go index 4e5fe59b..633d5775 100644 --- a/common_test.go +++ b/common_test.go @@ -151,7 +151,7 @@ func TestElementWire(t *testing.T) { } // Read from wire format. - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) val := test.in if reflect.ValueOf(test.in).Kind() != reflect.Ptr { val = reflect.New(reflect.TypeOf(test.in)).Interface() @@ -294,7 +294,7 @@ func TestVarIntWire(t *testing.T) { } // Decode from wire format. - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) val, err := btcwire.TstReadVarInt(rbuf, test.pver) if err != nil { t.Errorf("readVarInt #%d error %v", i, err) @@ -426,7 +426,7 @@ func TestVarStringWire(t *testing.T) { } // Decode from wire format. - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) val, err := btcwire.TstReadVarString(rbuf, test.pver) if err != nil { t.Errorf("readVarString #%d error %v", i, err) @@ -508,7 +508,7 @@ func TestVarStringOverflowErrors(t *testing.T) { t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Decode from wire format. - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) _, err := btcwire.TstReadVarString(rbuf, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("readVarString #%d wrong error got: %v, "+ @@ -556,7 +556,7 @@ func TestVarBytesWire(t *testing.T) { } // Decode from wire format. - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) val, err := btcwire.TstReadVarBytes(rbuf, test.pver, btcwire.MaxMessagePayload, "test payload") if err != nil { @@ -640,7 +640,7 @@ func TestVarBytesOverflowErrors(t *testing.T) { t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Decode from wire format. - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) _, err := btcwire.TstReadVarBytes(rbuf, test.pver, btcwire.MaxMessagePayload, "test payload") if reflect.TypeOf(err) != reflect.TypeOf(test.err) { diff --git a/invvect_test.go b/invvect_test.go index 015fafbb..7d03ff63 100644 --- a/invvect_test.go +++ b/invvect_test.go @@ -253,7 +253,7 @@ func TestInvVectWire(t *testing.T) { // Decode the message from wire format. var iv btcwire.InvVect - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = btcwire.TstReadInvVect(rbuf, test.pver, &iv) if err != nil { t.Errorf("readInvVect #%d error %v", i, err) diff --git a/message.go b/message.go index 26ec0c2d..fafe2155 100644 --- a/message.go +++ b/message.go @@ -153,7 +153,7 @@ func readMessageHeader(r io.Reader) (int, *messageHeader, error) { if err != nil { return n, nil, err } - hr := bytes.NewBuffer(headerBytes[:]) + hr := bytes.NewReader(headerBytes[:]) // Create and populate a messageHeader struct from the raw header bytes. hdr := messageHeader{} @@ -346,7 +346,8 @@ func ReadMessageN(r io.Reader, pver uint32, btcnet BitcoinNet) (int, Message, [] return totalBytes, nil, nil, messageError("ReadMessage", str) } - // Unmarshal message. + // Unmarshal message. NOTE: This must be a *bytes.Buffer since the + // MsgVersion BtcDecode function requires it. pr := bytes.NewBuffer(payload) err = msg.BtcDecode(pr, pver) if err != nil { diff --git a/message_test.go b/message_test.go index 567533ac..5d709c15 100644 --- a/message_test.go +++ b/message_test.go @@ -122,7 +122,7 @@ func TestMessage(t *testing.T) { } // Decode from wire format. - rbuf := bytes.NewBuffer(buf.Bytes()) + rbuf := bytes.NewReader(buf.Bytes()) nr, msg, _, err := btcwire.ReadMessageN(rbuf, test.pver, test.btcnet) if err != nil { t.Errorf("ReadMessage #%d error %v, msg %v", i, err, @@ -155,7 +155,7 @@ func TestMessage(t *testing.T) { } // Decode from wire format. - rbuf := bytes.NewBuffer(buf.Bytes()) + rbuf := bytes.NewReader(buf.Bytes()) msg, _, err := btcwire.ReadMessage(rbuf, test.pver, test.btcnet) if err != nil { t.Errorf("ReadMessage #%d error %v, msg %v", i, err, diff --git a/msgaddr_test.go b/msgaddr_test.go index 21126e99..2f4acdda 100644 --- a/msgaddr_test.go +++ b/msgaddr_test.go @@ -191,7 +191,7 @@ func TestAddrWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgAddr - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msgalert_test.go b/msgalert_test.go index 20f8287e..0102443d 100644 --- a/msgalert_test.go +++ b/msgalert_test.go @@ -157,7 +157,7 @@ func TestMsgAlertWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgAlert - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) @@ -440,7 +440,7 @@ func TestAlertErrors(t *testing.T) { 0x55, 0x52, 0x47, 0x45, 0x4e, 0x54, 0x00, //|URGENT.| } var alert btcwire.Alert - r := bytes.NewBuffer(badAlertEncoded) + r := bytes.NewReader(badAlertEncoded) err := alert.Deserialize(r, pver) if _, ok := err.(*btcwire.MessageError); !ok { t.Errorf("Alert.Deserialize wrong error got: %T, want: %T", @@ -457,7 +457,7 @@ func TestAlertErrors(t *testing.T) { 0x73, 0x68, 0x69, 0x3a, 0x30, 0x2e, 0x37, 0x2e, 0x32, 0x2f, 0x88, 0x13, 0x00, 0x00, 0x00, 0x06, //|shi:0.7.2/......| 0x55, 0x52, 0x47, 0x45, 0x4e, 0x54, 0x00, //|URGENT.| } - r = bytes.NewBuffer(badAlertEncoded) + r = bytes.NewReader(badAlertEncoded) err = alert.Deserialize(r, pver) if _, ok := err.(*btcwire.MessageError); !ok { t.Errorf("Alert.Deserialize wrong error got: %T, want: %T", diff --git a/msgblock_test.go b/msgblock_test.go index c3a441af..a2520cfa 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -183,7 +183,7 @@ func TestBlockWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgBlock - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) @@ -287,7 +287,7 @@ func TestBlockSerialize(t *testing.T) { // Deserialize the block. var block btcwire.MsgBlock - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = block.Deserialize(rbuf) if err != nil { t.Errorf("Deserialize #%d error %v", i, err) @@ -302,8 +302,8 @@ func TestBlockSerialize(t *testing.T) { // Deserialize the block while gathering transaction location // information. var txLocBlock btcwire.MsgBlock - rbuf = bytes.NewBuffer(test.buf) - txLocs, err := txLocBlock.DeserializeTxLoc(rbuf) + br := bytes.NewBuffer(test.buf) + txLocs, err := txLocBlock.DeserializeTxLoc(br) if err != nil { t.Errorf("DeserializeTxLoc #%d error %v", i, err) continue @@ -371,8 +371,8 @@ func TestBlockSerializeErrors(t *testing.T) { } var txLocBlock btcwire.MsgBlock - rbuf := bytes.NewBuffer(test.buf[0:test.max]) - _, err = txLocBlock.DeserializeTxLoc(rbuf) + br := bytes.NewBuffer(test.buf[0:test.max]) + _, err = txLocBlock.DeserializeTxLoc(br) if err != test.readErr { t.Errorf("DeserializeTxLoc #%d wrong error got: %v, want: %v", i, err, test.readErr) @@ -421,7 +421,7 @@ func TestBlockOverflowErrors(t *testing.T) { for i, test := range tests { // Decode from wire format. var msg btcwire.MsgBlock - r := bytes.NewBuffer(test.buf) + 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", @@ -430,7 +430,7 @@ func TestBlockOverflowErrors(t *testing.T) { } // Deserialize from wire format. - r = bytes.NewBuffer(test.buf) + r = bytes.NewReader(test.buf) err = msg.Deserialize(r) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("Deserialize #%d wrong error got: %v, want: %v", @@ -439,8 +439,8 @@ func TestBlockOverflowErrors(t *testing.T) { } // Deserialize with transaction location info from wire format. - r = bytes.NewBuffer(test.buf) - _, err = msg.DeserializeTxLoc(r) + br := bytes.NewBuffer(test.buf) + _, err = msg.DeserializeTxLoc(br) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("DeserializeTxLoc #%d wrong error got: %v, "+ "want: %v", i, err, reflect.TypeOf(test.err)) diff --git a/msgfilterclear_test.go b/msgfilterclear_test.go index 8579342c..06980390 100644 --- a/msgfilterclear_test.go +++ b/msgfilterclear_test.go @@ -113,7 +113,7 @@ func TestFilterClearWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgFilterClear - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msgfilterload_test.go b/msgfilterload_test.go index 4328b7b1..384ecf21 100644 --- a/msgfilterload_test.go +++ b/msgfilterload_test.go @@ -119,8 +119,7 @@ func TestFilterLoadMaxHashFuncsSize(t *testing.T) { 0x00, // update Type } // Decode with latest protocol version. - buf1 := bytes.NewBuffer(newBuf) - readbuf := bytes.NewReader(buf1.Bytes()) + readbuf := bytes.NewReader(newBuf) err = msg.BtcDecode(readbuf, btcwire.ProtocolVersion) if err == nil { t.Errorf("decode of MsgFilterLoad succeeded when it shouldn't have %v", diff --git a/msggetaddr_test.go b/msggetaddr_test.go index 296a6fbb..3c00ed66 100644 --- a/msggetaddr_test.go +++ b/msggetaddr_test.go @@ -107,7 +107,7 @@ func TestGetAddrWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgGetAddr - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msggetblocks_test.go b/msggetblocks_test.go index 3fea8c59..6be3d513 100644 --- a/msggetblocks_test.go +++ b/msggetblocks_test.go @@ -246,7 +246,7 @@ func TestGetBlocksWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgGetBlocks - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msggetdata_test.go b/msggetdata_test.go index ca7e1edf..ffc9c127 100644 --- a/msggetdata_test.go +++ b/msggetdata_test.go @@ -217,7 +217,7 @@ func TestGetDataWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgGetData - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msggetheaders_test.go b/msggetheaders_test.go index a5e61edd..85cd7756 100644 --- a/msggetheaders_test.go +++ b/msggetheaders_test.go @@ -236,7 +236,7 @@ func TestGetHeadersWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgGetHeaders - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msgheaders_test.go b/msgheaders_test.go index 99911fbc..6545047c 100644 --- a/msgheaders_test.go +++ b/msgheaders_test.go @@ -199,7 +199,7 @@ func TestHeadersWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgHeaders - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msginv_test.go b/msginv_test.go index 1ba6e31c..4aaf8411 100644 --- a/msginv_test.go +++ b/msginv_test.go @@ -217,7 +217,7 @@ func TestInvWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgInv - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msgmerkleblock_test.go b/msgmerkleblock_test.go index e4040d05..e63ce30c 100644 --- a/msgmerkleblock_test.go +++ b/msgmerkleblock_test.go @@ -176,7 +176,7 @@ func TestMerkleBlockWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgMerkleBlock - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msgnotfound_test.go b/msgnotfound_test.go index da6bf57d..cce16b39 100644 --- a/msgnotfound_test.go +++ b/msgnotfound_test.go @@ -208,7 +208,7 @@ func TestNotFoundWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgNotFound - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msgping_test.go b/msgping_test.go index c4958af5..1873de81 100644 --- a/msgping_test.go +++ b/msgping_test.go @@ -180,7 +180,7 @@ func TestPingWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgPing - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msgpong_test.go b/msgpong_test.go index f1dc4b1d..9c3e7d83 100644 --- a/msgpong_test.go +++ b/msgpong_test.go @@ -189,7 +189,7 @@ func TestPongWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgPong - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msgreject_test.go b/msgreject_test.go index ca425ac1..19c5317c 100644 --- a/msgreject_test.go +++ b/msgreject_test.go @@ -284,7 +284,7 @@ func TestRejectWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgReject - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/msgtx_test.go b/msgtx_test.go index 5688baa2..9928b436 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -287,7 +287,7 @@ func TestTxWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgTx - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) @@ -416,7 +416,7 @@ func TestTxSerialize(t *testing.T) { // Deserialize the transaction. var tx btcwire.MsgTx - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = tx.Deserialize(rbuf) if err != nil { t.Errorf("Deserialize #%d error %v", i, err) @@ -568,7 +568,7 @@ func TestTxOverflowErrors(t *testing.T) { for i, test := range tests { // Decode from wire format. var msg btcwire.MsgTx - r := bytes.NewBuffer(test.buf) + 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", @@ -577,7 +577,7 @@ func TestTxOverflowErrors(t *testing.T) { } // Decode from wire format. - r = bytes.NewBuffer(test.buf) + r = bytes.NewReader(test.buf) err = msg.Deserialize(r) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("Deserialize #%d wrong error got: %v, want: %v", diff --git a/msgverack_test.go b/msgverack_test.go index e1c09366..230bfebe 100644 --- a/msgverack_test.go +++ b/msgverack_test.go @@ -106,7 +106,7 @@ func TestVerAckWire(t *testing.T) { // Decode the message from wire format. var msg btcwire.MsgVerAck - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) diff --git a/netaddress_test.go b/netaddress_test.go index 27a6825b..47b541d5 100644 --- a/netaddress_test.go +++ b/netaddress_test.go @@ -201,7 +201,7 @@ func TestNetAddressWire(t *testing.T) { // Decode the message from wire format. var na btcwire.NetAddress - rbuf := bytes.NewBuffer(test.buf) + rbuf := bytes.NewReader(test.buf) err = btcwire.TstReadNetAddress(rbuf, test.pver, &na, test.ts) if err != nil { t.Errorf("readNetAddress #%d error %v", i, err) From 7dcb68275f3fdef1dc514cf37ae1688496f6aeaf Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Fri, 6 Jun 2014 22:33:39 -0500 Subject: [PATCH 194/219] Make MaxMessagePayload an exported constant. ok @davecgh --- common.go | 4 ++-- internal_test.go | 4 ---- message.go | 12 ++++++------ message_test.go | 2 +- msgalert.go | 10 +++++----- msgreject.go | 2 +- msgreject_test.go | 2 +- msgtx.go | 8 ++++---- 8 files changed, 20 insertions(+), 24 deletions(-) diff --git a/common.go b/common.go index 42204ec9..8e48152f 100644 --- a/common.go +++ b/common.go @@ -426,9 +426,9 @@ func readVarString(r io.Reader, pver uint32) (string, error) { // Prevent variable length strings that are larger than the maximum // message size. It would be possible to cause memory exhaustion and // panics without a sane upper bound on this count. - if count > maxMessagePayload { + if count > MaxMessagePayload { str := fmt.Sprintf("variable length string is too long "+ - "[count %d, max %d]", count, maxMessagePayload) + "[count %d, max %d]", count, MaxMessagePayload) return "", messageError("readVarString", str) } diff --git a/internal_test.go b/internal_test.go index 7b59992c..14437201 100644 --- a/internal_test.go +++ b/internal_test.go @@ -16,10 +16,6 @@ import ( ) const ( - // MaxMessagePayload makes the internal maxMessagePayload constant - // available to the test package. - MaxMessagePayload uint32 = maxMessagePayload - // MaxTxPerBlock makes the internal maxTxPerBlock constant available to // the test package. MaxTxPerBlock = maxTxPerBlock diff --git a/message.go b/message.go index fafe2155..d5b51ea0 100644 --- a/message.go +++ b/message.go @@ -20,9 +20,9 @@ const MessageHeaderSize = 24 // header. Shorter commands must be zero padded. const commandSize = 12 -// maxMessagePayload is the maximum bytes a message can be regardless of other +// MaxMessagePayload is the maximum bytes a message can be regardless of other // individual limits imposed by messages themselves. -const maxMessagePayload = (1024 * 1024 * 32) // 32MB +const MaxMessagePayload = (1024 * 1024 * 32) // 32MB // Commands used in bitcoin message headers which describe the type of message. const ( @@ -212,10 +212,10 @@ func WriteMessageN(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) (in lenp := len(payload) // Enforce maximum overall message payload. - if lenp > maxMessagePayload { + if lenp > MaxMessagePayload { str := fmt.Sprintf("message payload is too large - encoded "+ "%d bytes, but maximum message payload is %d bytes", - lenp, maxMessagePayload) + lenp, MaxMessagePayload) return totalBytes, messageError("WriteMessage", str) } @@ -285,10 +285,10 @@ func ReadMessageN(r io.Reader, pver uint32, btcnet BitcoinNet) (int, Message, [] totalBytes += n // Enforce maximum message payload. - if hdr.length > maxMessagePayload { + if hdr.length > MaxMessagePayload { str := fmt.Sprintf("message payload is too large - header "+ "indicates %d bytes, but max message payload is %d "+ - "bytes.", hdr.length, maxMessagePayload) + "bytes.", hdr.length, MaxMessagePayload) return totalBytes, nil, nil, messageError("ReadMessage", str) } diff --git a/message_test.go b/message_test.go index 5d709c15..036ff0fa 100644 --- a/message_test.go +++ b/message_test.go @@ -197,7 +197,7 @@ func TestReadMessageWireErrors(t *testing.T) { // Wire encoded bytes for a message that exceeds max overall message // length. - mpl := btcwire.MaxMessagePayload + mpl := uint32(btcwire.MaxMessagePayload) exceedMaxPayloadBytes := makeHeader(btcnet, "getaddr", mpl+1, 0) // Wire encoded bytes for a command which is invalid utf-8. diff --git a/msgalert.go b/msgalert.go index d1026c2a..6b95fb49 100644 --- a/msgalert.go +++ b/msgalert.go @@ -76,8 +76,8 @@ const maxSignatureSize = 72 // maxAlertSize is the maximum size an alert. // // MessagePayload = VarInt(Alert) + Alert + VarInt(Signature) + Signature -// maxMessagePayload = maxAlertSize + max(VarInt) + maxSignatureSize + 1 -const maxAlertSize = maxMessagePayload - maxSignatureSize - MaxVarIntPayload - 1 +// MaxMessagePayload = maxAlertSize + max(VarInt) + maxSignatureSize + 1 +const maxAlertSize = MaxMessagePayload - maxSignatureSize - MaxVarIntPayload - 1 // maxCountSetCancel is the maximum number of cancel IDs that could possibly // fit into a maximum size alert. @@ -343,7 +343,7 @@ type MsgAlert struct { func (msg *MsgAlert) BtcDecode(r io.Reader, pver uint32) error { var err error - msg.SerializedPayload, err = readVarBytes(r, pver, maxMessagePayload, + msg.SerializedPayload, err = readVarBytes(r, pver, MaxMessagePayload, "alert serialized payload") if err != nil { return err @@ -354,7 +354,7 @@ func (msg *MsgAlert) BtcDecode(r io.Reader, pver uint32) error { msg.Payload = nil } - msg.Signature, err = readVarBytes(r, pver, maxMessagePayload, + msg.Signature, err = readVarBytes(r, pver, MaxMessagePayload, "alert signature") if err != nil { return err @@ -408,7 +408,7 @@ func (msg *MsgAlert) Command() string { func (msg *MsgAlert) MaxPayloadLength(pver uint32) uint32 { // Since this can vary depending on the message, make it the max // size allowed. - return maxMessagePayload + return MaxMessagePayload } // NewMsgAlert returns a new bitcoin alert message that conforms to the Message diff --git a/msgreject.go b/msgreject.go index 14856cfb..c8d33fff 100644 --- a/msgreject.go +++ b/msgreject.go @@ -167,7 +167,7 @@ func (msg *MsgReject) MaxPayloadLength(pver uint32) uint32 { // Unfortunately the bitcoin protocol does not enforce a sane // limit on the length of the reason, so the max payload is the // overall maximum message payload. - plen = maxMessagePayload + plen = MaxMessagePayload } return plen diff --git a/msgreject_test.go b/msgreject_test.go index 19c5317c..1efde9c7 100644 --- a/msgreject_test.go +++ b/msgreject_test.go @@ -76,7 +76,7 @@ func TestRejectLatest(t *testing.T) { } // Ensure max payload is expected value for latest protocol version. - wantPayload := btcwire.MaxMessagePayload + wantPayload := uint32(btcwire.MaxMessagePayload) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { t.Errorf("MaxPayloadLength: wrong max payload length for "+ diff --git a/msgtx.go b/msgtx.go index fc93faa4..0d6714e9 100644 --- a/msgtx.go +++ b/msgtx.go @@ -39,7 +39,7 @@ const ( // maxTxInPerMessage is the maximum number of transactions inputs that // a transaction which fits into a message could possibly have. - maxTxInPerMessage = (maxMessagePayload / minTxInPayload) + 1 + maxTxInPerMessage = (MaxMessagePayload / minTxInPayload) + 1 // minTxOutPayload is the minimum payload size for a transaction output. // Value 8 bytes + Varint for PkScript length 1 byte. @@ -47,7 +47,7 @@ const ( // maxTxOutPerMessage is the maximum number of transactions outputs that // a transaction which fits into a message could possibly have. - maxTxOutPerMessage = (maxMessagePayload / minTxOutPayload) + 1 + maxTxOutPerMessage = (MaxMessagePayload / minTxOutPayload) + 1 // minTxPayload is the minimum payload size for a transaction. Note // that any realistically usable transaction must have at least one @@ -470,7 +470,7 @@ func readTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { } ti.PreviousOutpoint = op - ti.SignatureScript, err = readVarBytes(r, pver, maxMessagePayload, + ti.SignatureScript, err = readVarBytes(r, pver, MaxMessagePayload, "transaction input signature script") if err != nil { return err @@ -519,7 +519,7 @@ func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { } to.Value = int64(binary.LittleEndian.Uint64(buf[:])) - to.PkScript, err = readVarBytes(r, pver, maxMessagePayload, + to.PkScript, err = readVarBytes(r, pver, MaxMessagePayload, "transaction output public key script") if err != nil { return err From 843e71515a3bffbd10b46a79627aa44832c6ed72 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 29 Jun 2014 14:40:20 -0500 Subject: [PATCH 195/219] Expose new SerializeSize API for blocks. This commit adds a new function named SerializeSize to the public API for MsgBlock which can be used to determine how many bytes the serialized data would take without having to actually serialize it. In addition, it makes the exported BlockVersion an untyped constant as well as changes the block and tx versions to a signed integer to more closely match the protocol. Finally, this commit also adds tests for the new function. The following benchmark shows the difference between using the new function to get the serialize size for a typical block and serializing into a temporary buffer and taking the length of it: Bufffer: BenchmarkBlockSerializeSizeBuffer 200000 27050 ns/op New: BenchmarkBlockSerializeSizeNew 100000000 34 ns/op Closes #19. --- blockheader.go | 4 ++-- internal_test.go | 12 ++++++------ msgblock.go | 14 ++++++++++++++ msgblock_test.go | 28 ++++++++++++++++++++++++++++ msgtx.go | 18 +++++++++--------- 5 files changed, 59 insertions(+), 17 deletions(-) diff --git a/blockheader.go b/blockheader.go index d9ed680a..519305b9 100644 --- a/blockheader.go +++ b/blockheader.go @@ -11,7 +11,7 @@ import ( ) // BlockVersion is the current latest supported block version. -const BlockVersion uint32 = 2 +const BlockVersion = 2 // Version 4 bytes + Timestamp 4 bytes + Bits 4 bytes + Nonce 4 bytes + // PrevBlock and MerkleRoot hashes. @@ -21,7 +21,7 @@ const MaxBlockHeaderPayload = 16 + (HashSize * 2) // block (MsgBlock) and headers (MsgHeaders) messages. type BlockHeader struct { // Version of the block. This is not the same as the protocol version. - Version uint32 + Version int32 // Hash of the previous block in the block chain. PrevBlock ShaHash diff --git a/internal_test.go b/internal_test.go index 14437201..6f332712 100644 --- a/internal_test.go +++ b/internal_test.go @@ -141,36 +141,36 @@ func TstReadMessageHeader(r io.Reader) (int, *messageHeader, error) { // TstReadOutPoint makes the internal readOutPoint function available to the // test package. -func TstReadOutPoint(r io.Reader, pver uint32, version uint32, op *OutPoint) error { +func TstReadOutPoint(r io.Reader, pver uint32, version int32, op *OutPoint) error { return readOutPoint(r, pver, version, op) } // TstWriteOutPoint makes the internal writeOutPoint function available to the // test package. -func TstWriteOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error { +func TstWriteOutPoint(w io.Writer, pver uint32, version int32, op *OutPoint) error { return writeOutPoint(w, pver, version, op) } // TstReadTxOut makes the internal readTxOut function available to the test // package. -func TstReadTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { +func TstReadTxOut(r io.Reader, pver uint32, version int32, to *TxOut) error { return readTxOut(r, pver, version, to) } // TstWriteTxOut makes the internal writeTxOut function available to the test // package. -func TstWriteTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { +func TstWriteTxOut(w io.Writer, pver uint32, version int32, to *TxOut) error { return writeTxOut(w, pver, version, to) } // TstReadTxIn makes the internal readTxIn function available to the test // package. -func TstReadTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { +func TstReadTxIn(r io.Reader, pver uint32, version int32, ti *TxIn) error { return readTxIn(r, pver, version, ti) } // TstWriteTxIn makes the internal writeTxIn function available to the test // package. -func TstWriteTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { +func TstWriteTxIn(w io.Writer, pver uint32, version int32, ti *TxIn) error { return writeTxIn(w, pver, version, ti) } diff --git a/msgblock.go b/msgblock.go index d03dc539..60f46eb1 100644 --- a/msgblock.go +++ b/msgblock.go @@ -194,6 +194,20 @@ func (msg *MsgBlock) Serialize(w io.Writer) error { return msg.BtcEncode(w, 0) } +// SerializeSize returns the number of bytes it would take to serialize the +// the block. +func (msg *MsgBlock) SerializeSize() int { + // Block header bytes + Serialized varint size for the number of + // transactions. + n := blockHeaderLen + VarIntSerializeSize(uint64(len(msg.Transactions))) + + for _, tx := range msg.Transactions { + n += tx.SerializeSize() + } + + return n +} + // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgBlock) Command() string { diff --git a/msgblock_test.go b/msgblock_test.go index a2520cfa..d8b2280a 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -449,6 +449,34 @@ func TestBlockOverflowErrors(t *testing.T) { } } +// TestBlockSerializeSize performs tests to ensure the serialize size for +// various blocks is accurate. +func TestBlockSerializeSize(t *testing.T) { + // Block with no transactions. + noTxBlock := btcwire.NewMsgBlock(&blockOne.Header) + + tests := []struct { + in *btcwire.MsgBlock // Block to encode + size int // Expected serialized size + }{ + // Block with no transactions. + {noTxBlock, 81}, + + // First block in the mainnet block chain. + {&blockOne, len(blockOneBytes)}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + serializedSize := test.in.SerializeSize() + if serializedSize != test.size { + t.Errorf("MsgBlock.SerializeSize: #%d got: %d, want: "+ + "%d", i, serializedSize, test.size) + continue + } + } +} + var blockOne = btcwire.MsgBlock{ Header: btcwire.BlockHeader{ Version: 1, diff --git a/msgtx.go b/msgtx.go index 0d6714e9..df2426c7 100644 --- a/msgtx.go +++ b/msgtx.go @@ -133,7 +133,7 @@ func NewTxOut(value int64, pkScript []byte) *TxOut { // Use the AddTxIn and AddTxOut functions to build up the list of transaction // inputs and outputs. type MsgTx struct { - Version uint32 + Version int32 TxIn []*TxIn TxOut []*TxOut LockTime uint32 @@ -240,7 +240,7 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { if err != nil { return err } - msg.Version = binary.LittleEndian.Uint32(buf[:]) + msg.Version = int32(binary.LittleEndian.Uint32(buf[:])) count, err := readVarInt(r, pver) if err != nil { @@ -324,7 +324,7 @@ func (msg *MsgTx) Deserialize(r io.Reader) error { // database, as opposed to encoding transactions for the wire. func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32) error { var buf [4]byte - binary.LittleEndian.PutUint32(buf[:], msg.Version) + binary.LittleEndian.PutUint32(buf[:], uint32(msg.Version)) _, err := w.Write(buf[:]) if err != nil { return err @@ -428,7 +428,7 @@ func NewMsgTx() *MsgTx { } // readOutPoint reads the next sequence of bytes from r as an OutPoint. -func readOutPoint(r io.Reader, pver uint32, version uint32, op *OutPoint) error { +func readOutPoint(r io.Reader, pver uint32, version int32, op *OutPoint) error { _, err := io.ReadFull(r, op.Hash[:]) if err != nil { return err @@ -445,7 +445,7 @@ func readOutPoint(r io.Reader, pver uint32, version uint32, op *OutPoint) error // writeOutPoint encodes op to the bitcoin protocol encoding for an OutPoint // to w. -func writeOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error { +func writeOutPoint(w io.Writer, pver uint32, version int32, op *OutPoint) error { _, err := w.Write(op.Hash[:]) if err != nil { return err @@ -462,7 +462,7 @@ func writeOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error // readTxIn reads the next sequence of bytes from r as a transaction input // (TxIn). -func readTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { +func readTxIn(r io.Reader, pver uint32, version int32, ti *TxIn) error { var op OutPoint err := readOutPoint(r, pver, version, &op) if err != nil { @@ -488,7 +488,7 @@ func readTxIn(r io.Reader, pver uint32, version uint32, ti *TxIn) error { // writeTxIn encodes ti to the bitcoin protocol encoding for a transaction // input (TxIn) to w. -func writeTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { +func writeTxIn(w io.Writer, pver uint32, version int32, ti *TxIn) error { err := writeOutPoint(w, pver, version, &ti.PreviousOutpoint) if err != nil { return err @@ -511,7 +511,7 @@ func writeTxIn(w io.Writer, pver uint32, version uint32, ti *TxIn) error { // readTxOut reads the next sequence of bytes from r as a transaction output // (TxOut). -func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { +func readTxOut(r io.Reader, pver uint32, version int32, to *TxOut) error { var buf [8]byte _, err := io.ReadFull(r, buf[:]) if err != nil { @@ -530,7 +530,7 @@ func readTxOut(r io.Reader, pver uint32, version uint32, to *TxOut) error { // writeTxOut encodes to into the bitcoin protocol encoding for a transaction // output (TxOut) to w. -func writeTxOut(w io.Writer, pver uint32, version uint32, to *TxOut) error { +func writeTxOut(w io.Writer, pver uint32, version int32, to *TxOut) error { var buf [8]byte binary.LittleEndian.PutUint64(buf[:], uint64(to.Value)) _, err := w.Write(buf[:]) From 5032b07c6643bd8ea63ccde4f91283da7c389d16 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 29 Jun 2014 17:45:05 -0500 Subject: [PATCH 196/219] Rename blockHashLen to blockHeaderLen. The old name no longer makes sense because the hash length is the same as the header length. --- blockheader.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/blockheader.go b/blockheader.go index 519305b9..e3ad89df 100644 --- a/blockheader.go +++ b/blockheader.go @@ -40,9 +40,9 @@ type BlockHeader struct { Nonce uint32 } -// blockHashLen is a constant that represents how much of the block header is -// used when computing the block sha 0:blockHashLen -const blockHashLen = 80 +// blockHeaderLen is a constant that represents the number of bytes for a block +// header. +const blockHeaderLen = 80 // BlockSha computes the block identifier hash for the given block header. func (h *BlockHeader) BlockSha() (ShaHash, error) { @@ -55,7 +55,7 @@ func (h *BlockHeader) BlockSha() (ShaHash, error) { var buf bytes.Buffer var sha ShaHash _ = writeBlockHeader(&buf, 0, h) - _ = sha.SetBytes(DoubleSha256(buf.Bytes()[0:blockHashLen])) + _ = sha.SetBytes(DoubleSha256(buf.Bytes()[0:blockHeaderLen])) // Even though this function can't currently fail, it still returns // a potential error to help future proof the API should a failure From 3a1009529f3575e44a1d30070c5fdd70770f9208 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 2 Jul 2014 19:43:33 -0500 Subject: [PATCH 197/219] goimports -w . --- bench_test.go | 3 ++- blockheader_test.go | 5 +++-- common.go | 3 ++- common_test.go | 5 +++-- fakemessage_test.go | 3 ++- invvect_test.go | 5 +++-- message_test.go | 5 +++-- msgaddr_test.go | 5 +++-- msgalert_test.go | 5 +++-- msgblock_test.go | 5 +++-- msgfilteradd_test.go | 3 ++- msgfilterclear_test.go | 5 +++-- msgfilterload_test.go | 3 ++- msggetaddr_test.go | 5 +++-- msggetblocks_test.go | 5 +++-- msggetdata_test.go | 5 +++-- msggetheaders_test.go | 5 +++-- msgheaders_test.go | 5 +++-- msginv_test.go | 5 +++-- msgmempool_test.go | 3 ++- msgmerkleblock_test.go | 5 +++-- msgnotfound_test.go | 5 +++-- msgping_test.go | 5 +++-- msgpong_test.go | 5 +++-- msgreject_test.go | 5 +++-- msgtx_test.go | 5 +++-- msgverack_test.go | 5 +++-- msgversion_test.go | 5 +++-- netaddress_test.go | 5 +++-- protocol_test.go | 3 ++- shahash_test.go | 3 ++- 31 files changed, 85 insertions(+), 54 deletions(-) diff --git a/bench_test.go b/bench_test.go index 10b76f1d..a1f31f60 100644 --- a/bench_test.go +++ b/bench_test.go @@ -6,9 +6,10 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" "io/ioutil" "testing" + + "github.com/conformal/btcwire" ) // genesisCoinbaseTx is the coinbase transaction for the genesis blocks for diff --git a/blockheader_test.go b/blockheader_test.go index b01a3ecd..4fe2047c 100644 --- a/blockheader_test.go +++ b/blockheader_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "reflect" "testing" "time" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestBlockHeader tests the BlockHeader API. diff --git a/common.go b/common.go index 8e48152f..1cacfdd8 100644 --- a/common.go +++ b/common.go @@ -8,9 +8,10 @@ import ( "crypto/rand" "encoding/binary" "fmt" - "github.com/conformal/fastsha256" "io" "math" + + "github.com/conformal/fastsha256" ) // Maximum payload size for a variable length integer. diff --git a/common_test.go b/common_test.go index 633d5775..a292127a 100644 --- a/common_test.go +++ b/common_test.go @@ -7,12 +7,13 @@ package btcwire_test import ( "bytes" "fmt" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "strings" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // mainNetGenesisHash is the hash of the first block in the block chain for the diff --git a/fakemessage_test.go b/fakemessage_test.go index d08b4a5b..25541196 100644 --- a/fakemessage_test.go +++ b/fakemessage_test.go @@ -5,8 +5,9 @@ package btcwire_test import ( - "github.com/conformal/btcwire" "io" + + "github.com/conformal/btcwire" ) // fakeMessage implements the btcwire.Message interface and is used to force diff --git a/invvect_test.go b/invvect_test.go index 7d03ff63..351081b6 100644 --- a/invvect_test.go +++ b/invvect_test.go @@ -6,10 +6,11 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestInvVectStringer tests the stringized output for inventory vector types. diff --git a/message_test.go b/message_test.go index 036ff0fa..aeb80284 100644 --- a/message_test.go +++ b/message_test.go @@ -7,13 +7,14 @@ package btcwire_test import ( "bytes" "encoding/binary" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "net" "reflect" "testing" "time" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // makeHeader is a convenience function to make a message header in the form of diff --git a/msgaddr_test.go b/msgaddr_test.go index 2f4acdda..612b1f4b 100644 --- a/msgaddr_test.go +++ b/msgaddr_test.go @@ -6,13 +6,14 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "net" "reflect" "testing" "time" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestAddr tests the MsgAddr API. diff --git a/msgalert_test.go b/msgalert_test.go index 0102443d..ecd993a5 100644 --- a/msgalert_test.go +++ b/msgalert_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestMsgAlert tests the MsgAlert API. diff --git a/msgblock_test.go b/msgblock_test.go index d8b2280a..5965382d 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -6,12 +6,13 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" "time" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestBlock tests the MsgBlock API. diff --git a/msgfilteradd_test.go b/msgfilteradd_test.go index 86429f7c..73d612ee 100644 --- a/msgfilteradd_test.go +++ b/msgfilteradd_test.go @@ -6,10 +6,11 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" "io" "reflect" "testing" + + "github.com/conformal/btcwire" ) // TestFilterAddLatest tests the MsgFilterAdd API against the latest protocol diff --git a/msgfilterclear_test.go b/msgfilterclear_test.go index 06980390..3e368ac3 100644 --- a/msgfilterclear_test.go +++ b/msgfilterclear_test.go @@ -6,10 +6,11 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestFilterCLearLatest tests the MsgFilterClear API against the latest diff --git a/msgfilterload_test.go b/msgfilterload_test.go index 384ecf21..56f5dace 100644 --- a/msgfilterload_test.go +++ b/msgfilterload_test.go @@ -6,10 +6,11 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" "io" "reflect" "testing" + + "github.com/conformal/btcwire" ) // TestFilterCLearLatest tests the MsgFilterLoad API against the latest protocol diff --git a/msggetaddr_test.go b/msggetaddr_test.go index 3c00ed66..86dae99b 100644 --- a/msggetaddr_test.go +++ b/msggetaddr_test.go @@ -6,10 +6,11 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestGetAddr tests the MsgGetAddr API. diff --git a/msggetblocks_test.go b/msggetblocks_test.go index 6be3d513..e8f5e259 100644 --- a/msggetblocks_test.go +++ b/msggetblocks_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestGetBlocks tests the MsgGetBlocks API. diff --git a/msggetdata_test.go b/msggetdata_test.go index ffc9c127..6c4ebf9d 100644 --- a/msggetdata_test.go +++ b/msggetdata_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestGetData tests the MsgGetData API. diff --git a/msggetheaders_test.go b/msggetheaders_test.go index 85cd7756..8c57fcd4 100644 --- a/msggetheaders_test.go +++ b/msggetheaders_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestGetHeaders tests the MsgGetHeader API. diff --git a/msgheaders_test.go b/msgheaders_test.go index 6545047c..cc2060e3 100644 --- a/msgheaders_test.go +++ b/msgheaders_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestHeaders tests the MsgHeaders API. diff --git a/msginv_test.go b/msginv_test.go index 4aaf8411..ae608e99 100644 --- a/msginv_test.go +++ b/msginv_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestInv tests the MsgInv API. diff --git a/msgmempool_test.go b/msgmempool_test.go index af22dbae..3a5a08c9 100644 --- a/msgmempool_test.go +++ b/msgmempool_test.go @@ -6,8 +6,9 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" "testing" + + "github.com/conformal/btcwire" ) func TestMemPool(t *testing.T) { diff --git a/msgmerkleblock_test.go b/msgmerkleblock_test.go index e63ce30c..ffb12d9e 100644 --- a/msgmerkleblock_test.go +++ b/msgmerkleblock_test.go @@ -7,12 +7,13 @@ package btcwire_test import ( "bytes" "crypto/rand" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" "time" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestMerkleBlock tests the MsgMerkleBlock API. diff --git a/msgnotfound_test.go b/msgnotfound_test.go index cce16b39..98a05876 100644 --- a/msgnotfound_test.go +++ b/msgnotfound_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestNotFound tests the MsgNotFound API. diff --git a/msgping_test.go b/msgping_test.go index 1873de81..79db0c1f 100644 --- a/msgping_test.go +++ b/msgping_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestPing tests the MsgPing API against the latest protocol version. diff --git a/msgpong_test.go b/msgpong_test.go index 9c3e7d83..fd99e53b 100644 --- a/msgpong_test.go +++ b/msgpong_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestPongLatest tests the MsgPong API against the latest protocol version. diff --git a/msgreject_test.go b/msgreject_test.go index 1efde9c7..e369492a 100644 --- a/msgreject_test.go +++ b/msgreject_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestRejectCodeStringer tests the stringized output for the reject code type. diff --git a/msgtx_test.go b/msgtx_test.go index 9928b436..bce99f20 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -6,11 +6,12 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestTx tests the MsgTx API. diff --git a/msgverack_test.go b/msgverack_test.go index 230bfebe..b5d616c5 100644 --- a/msgverack_test.go +++ b/msgverack_test.go @@ -6,10 +6,11 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "reflect" "testing" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestVerAck tests the MsgVerAck API. diff --git a/msgversion_test.go b/msgversion_test.go index bd8bd3aa..7f1bced1 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -6,14 +6,15 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "net" "reflect" "strings" "testing" "time" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestVersion tests the MsgVersion API. diff --git a/netaddress_test.go b/netaddress_test.go index 47b541d5..c3649239 100644 --- a/netaddress_test.go +++ b/netaddress_test.go @@ -6,13 +6,14 @@ package btcwire_test import ( "bytes" - "github.com/conformal/btcwire" - "github.com/davecgh/go-spew/spew" "io" "net" "reflect" "testing" "time" + + "github.com/conformal/btcwire" + "github.com/davecgh/go-spew/spew" ) // TestNetAddress tests the NetAddress API. diff --git a/protocol_test.go b/protocol_test.go index 61a59aaa..05d112c7 100644 --- a/protocol_test.go +++ b/protocol_test.go @@ -5,8 +5,9 @@ package btcwire_test import ( - "github.com/conformal/btcwire" "testing" + + "github.com/conformal/btcwire" ) // TestServiceFlagStringer tests the stringized output for service flag types. diff --git a/shahash_test.go b/shahash_test.go index af6565ef..9a70b6d3 100644 --- a/shahash_test.go +++ b/shahash_test.go @@ -7,8 +7,9 @@ package btcwire_test import ( "bytes" "encoding/hex" - "github.com/conformal/btcwire" "testing" + + "github.com/conformal/btcwire" ) // TestShaHash tests the ShaHash API. From dd70618cc1ed08b04a6ce013230154a0df9db879 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 12 Jul 2014 17:32:21 -0500 Subject: [PATCH 198/219] Export CommandSize constant. This commit exports the CommandSize constant to provide callers with the ability to know the size of the command field in a bitcoin message header. --- common.go | 4 ++-- internal_test.go | 4 ---- message.go | 12 ++++++------ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/common.go b/common.go index 1cacfdd8..dd6b61bd 100644 --- a/common.go +++ b/common.go @@ -83,7 +83,7 @@ func readElement(r io.Reader, element interface{}) error { return nil // Message header command. - case *[commandSize]uint8: + case *[CommandSize]uint8: _, err := io.ReadFull(r, e[:]) if err != nil { return err @@ -233,7 +233,7 @@ func writeElement(w io.Writer, element interface{}) error { return nil // Message header command. - case [commandSize]uint8: + case [CommandSize]uint8: _, err := w.Write(e[:]) if err != nil { return err diff --git a/internal_test.go b/internal_test.go index 6f332712..5663e05f 100644 --- a/internal_test.go +++ b/internal_test.go @@ -31,10 +31,6 @@ const ( // 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 diff --git a/message.go b/message.go index d5b51ea0..7d4da72f 100644 --- a/message.go +++ b/message.go @@ -16,9 +16,9 @@ import ( // checksum 4 bytes. const MessageHeaderSize = 24 -// commandSize is the fixed size of all commands in the common bitcoin message +// CommandSize is the fixed size of all commands in the common bitcoin message // header. Shorter commands must be zero padded. -const commandSize = 12 +const CommandSize = 12 // MaxMessagePayload is the maximum bytes a message can be regardless of other // individual limits imposed by messages themselves. @@ -157,7 +157,7 @@ func readMessageHeader(r io.Reader) (int, *messageHeader, error) { // Create and populate a messageHeader struct from the raw header bytes. hdr := messageHeader{} - var command [commandSize]byte + var command [CommandSize]byte readElements(hr, &hdr.magic, &command, &hdr.length, &hdr.checksum) // Strip trailing zeros from command string. @@ -193,11 +193,11 @@ func WriteMessageN(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) (in totalBytes := 0 // Enforce max command size. - var command [commandSize]byte + var command [CommandSize]byte cmd := msg.Command() - if len(cmd) > commandSize { + if len(cmd) > CommandSize { str := fmt.Sprintf("command [%s] is too long [max %v]", - cmd, commandSize) + cmd, CommandSize) return totalBytes, messageError("WriteMessage", str) } copy(command[:], []byte(cmd)) From 7ee3a2220bac1b13b7f9d1d47b28a3a1a2fa3372 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 13 Jul 2014 12:15:50 -0500 Subject: [PATCH 199/219] Use a more specific license adjective. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 74c7dfe9..717519c5 100644 --- a/README.md +++ b/README.md @@ -125,4 +125,5 @@ signature perform the following: ## License -Package btcwire is licensed under the liberal ISC License. +Package btcwire is licensed under the [copyfree](http://copyfree.org) ISC +License. From 4deb922c9d23d6167ec0d51b00e99a9fd020d09a Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 14 Jul 2014 10:38:29 -0500 Subject: [PATCH 200/219] Export command constants. Although it is possible to get the command name for each msg type by creating an instances of the type and calling the Command method against it, it's slightly more efficient to simply allows callers to have direct access to the exported constants. This is currently really useful for the reject message since callers need to be able to examine the command type to determine whether or not the hash field needs to be included. --- message.go | 84 +++++++++++++++++++++++------------------------ msgaddr.go | 2 +- msgalert.go | 2 +- msgblock.go | 2 +- msgfilteradd.go | 2 +- msgfilterclear.go | 2 +- msgfilterload.go | 2 +- msggetaddr.go | 2 +- msggetblocks.go | 2 +- msggetdata.go | 2 +- msggetheaders.go | 2 +- msgheaders.go | 2 +- msginv.go | 2 +- msgmempool.go | 2 +- msgmerkleblock.go | 2 +- msgnotfound.go | 2 +- msgping.go | 2 +- msgpong.go | 2 +- msgreject.go | 12 +++---- msgtx.go | 2 +- msgverack.go | 2 +- msgversion.go | 2 +- 22 files changed, 68 insertions(+), 68 deletions(-) diff --git a/message.go b/message.go index 7d4da72f..1e2b7d3d 100644 --- a/message.go +++ b/message.go @@ -26,27 +26,27 @@ const MaxMessagePayload = (1024 * 1024 * 32) // 32MB // Commands used in bitcoin message headers which describe the type of message. const ( - cmdVersion = "version" - cmdVerAck = "verack" - cmdGetAddr = "getaddr" - cmdAddr = "addr" - cmdGetBlocks = "getblocks" - cmdInv = "inv" - cmdGetData = "getdata" - cmdNotFound = "notfound" - cmdBlock = "block" - cmdTx = "tx" - cmdGetHeaders = "getheaders" - cmdHeaders = "headers" - cmdPing = "ping" - cmdPong = "pong" - cmdAlert = "alert" - cmdMemPool = "mempool" - cmdFilterAdd = "filteradd" - cmdFilterClear = "filterclear" - cmdFilterLoad = "filterload" - cmdMerkleBlock = "merkleblock" - cmdReject = "reject" + CmdVersion = "version" + CmdVerAck = "verack" + CmdGetAddr = "getaddr" + CmdAddr = "addr" + CmdGetBlocks = "getblocks" + CmdInv = "inv" + CmdGetData = "getdata" + CmdNotFound = "notfound" + CmdBlock = "block" + CmdTx = "tx" + CmdGetHeaders = "getheaders" + CmdHeaders = "headers" + CmdPing = "ping" + CmdPong = "pong" + CmdAlert = "alert" + CmdMemPool = "mempool" + CmdFilterAdd = "filteradd" + CmdFilterClear = "filterclear" + CmdFilterLoad = "filterload" + CmdMerkleBlock = "merkleblock" + CmdReject = "reject" ) // Message is an interface that describes a bitcoin message. A type that @@ -65,67 +65,67 @@ type Message interface { func makeEmptyMessage(command string) (Message, error) { var msg Message switch command { - case cmdVersion: + case CmdVersion: msg = &MsgVersion{} - case cmdVerAck: + case CmdVerAck: msg = &MsgVerAck{} - case cmdGetAddr: + case CmdGetAddr: msg = &MsgGetAddr{} - case cmdAddr: + case CmdAddr: msg = &MsgAddr{} - case cmdGetBlocks: + case CmdGetBlocks: msg = &MsgGetBlocks{} - case cmdBlock: + case CmdBlock: msg = &MsgBlock{} - case cmdInv: + case CmdInv: msg = &MsgInv{} - case cmdGetData: + case CmdGetData: msg = &MsgGetData{} - case cmdNotFound: + case CmdNotFound: msg = &MsgNotFound{} - case cmdTx: + case CmdTx: msg = &MsgTx{} - case cmdPing: + case CmdPing: msg = &MsgPing{} - case cmdPong: + case CmdPong: msg = &MsgPong{} - case cmdGetHeaders: + case CmdGetHeaders: msg = &MsgGetHeaders{} - case cmdHeaders: + case CmdHeaders: msg = &MsgHeaders{} - case cmdAlert: + case CmdAlert: msg = &MsgAlert{} - case cmdMemPool: + case CmdMemPool: msg = &MsgMemPool{} - case cmdFilterAdd: + case CmdFilterAdd: msg = &MsgFilterAdd{} - case cmdFilterClear: + case CmdFilterClear: msg = &MsgFilterClear{} - case cmdFilterLoad: + case CmdFilterLoad: msg = &MsgFilterLoad{} - case cmdMerkleBlock: + case CmdMerkleBlock: msg = &MsgMerkleBlock{} - case cmdReject: + case CmdReject: msg = &MsgReject{} default: diff --git a/msgaddr.go b/msgaddr.go index 678de22d..b1767620 100644 --- a/msgaddr.go +++ b/msgaddr.go @@ -118,7 +118,7 @@ func (msg *MsgAddr) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgAddr) Command() string { - return cmdAddr + return CmdAddr } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgalert.go b/msgalert.go index 6b95fb49..4aa186a8 100644 --- a/msgalert.go +++ b/msgalert.go @@ -400,7 +400,7 @@ func (msg *MsgAlert) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgAlert) Command() string { - return cmdAlert + return CmdAlert } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgblock.go b/msgblock.go index 60f46eb1..7d058923 100644 --- a/msgblock.go +++ b/msgblock.go @@ -211,7 +211,7 @@ func (msg *MsgBlock) SerializeSize() int { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgBlock) Command() string { - return cmdBlock + return CmdBlock } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgfilteradd.go b/msgfilteradd.go index 4b19a62e..a04bdcc4 100644 --- a/msgfilteradd.go +++ b/msgfilteradd.go @@ -71,7 +71,7 @@ func (msg *MsgFilterAdd) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgFilterAdd) Command() string { - return cmdFilterAdd + return CmdFilterAdd } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgfilterclear.go b/msgfilterclear.go index 5d736b6e..45580786 100644 --- a/msgfilterclear.go +++ b/msgfilterclear.go @@ -43,7 +43,7 @@ func (msg *MsgFilterClear) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgFilterClear) Command() string { - return cmdFilterClear + return CmdFilterClear } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgfilterload.go b/msgfilterload.go index 35725f19..f0bdbe66 100644 --- a/msgfilterload.go +++ b/msgfilterload.go @@ -117,7 +117,7 @@ func (msg *MsgFilterLoad) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgFilterLoad) Command() string { - return cmdFilterLoad + return CmdFilterLoad } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msggetaddr.go b/msggetaddr.go index 78716806..6ccf767e 100644 --- a/msggetaddr.go +++ b/msggetaddr.go @@ -31,7 +31,7 @@ func (msg *MsgGetAddr) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgGetAddr) Command() string { - return cmdGetAddr + return CmdGetAddr } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msggetblocks.go b/msggetblocks.go index 45ec0d47..e8e5dcfe 100644 --- a/msggetblocks.go +++ b/msggetblocks.go @@ -121,7 +121,7 @@ func (msg *MsgGetBlocks) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgGetBlocks) Command() string { - return cmdGetBlocks + return CmdGetBlocks } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msggetdata.go b/msggetdata.go index 3add4782..63392eee 100644 --- a/msggetdata.go +++ b/msggetdata.go @@ -90,7 +90,7 @@ func (msg *MsgGetData) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgGetData) Command() string { - return cmdGetData + return CmdGetData } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msggetheaders.go b/msggetheaders.go index 607fba49..e407f4d9 100644 --- a/msggetheaders.go +++ b/msggetheaders.go @@ -119,7 +119,7 @@ func (msg *MsgGetHeaders) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgGetHeaders) Command() string { - return cmdGetHeaders + return CmdGetHeaders } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgheaders.go b/msgheaders.go index b4a44426..c895b6a4 100644 --- a/msgheaders.go +++ b/msgheaders.go @@ -113,7 +113,7 @@ func (msg *MsgHeaders) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgHeaders) Command() string { - return cmdHeaders + return CmdHeaders } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msginv.go b/msginv.go index 55ca11ca..1cf9a261 100644 --- a/msginv.go +++ b/msginv.go @@ -98,7 +98,7 @@ func (msg *MsgInv) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgInv) Command() string { - return cmdInv + return CmdInv } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgmempool.go b/msgmempool.go index cb4f5b75..376b8786 100644 --- a/msgmempool.go +++ b/msgmempool.go @@ -44,7 +44,7 @@ func (msg *MsgMemPool) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgMemPool) Command() string { - return cmdMemPool + return CmdMemPool } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgmerkleblock.go b/msgmerkleblock.go index 18b579fb..b5f2ae36 100644 --- a/msgmerkleblock.go +++ b/msgmerkleblock.go @@ -146,7 +146,7 @@ func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgMerkleBlock) Command() string { - return cmdMerkleBlock + return CmdMerkleBlock } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgnotfound.go b/msgnotfound.go index fa439f55..3c18b77d 100644 --- a/msgnotfound.go +++ b/msgnotfound.go @@ -87,7 +87,7 @@ func (msg *MsgNotFound) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgNotFound) Command() string { - return cmdNotFound + return CmdNotFound } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgping.go b/msgping.go index 7a7937aa..58e54f63 100644 --- a/msgping.go +++ b/msgping.go @@ -60,7 +60,7 @@ func (msg *MsgPing) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgPing) Command() string { - return cmdPing + return CmdPing } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgpong.go b/msgpong.go index d8958031..9bd0431a 100644 --- a/msgpong.go +++ b/msgpong.go @@ -61,7 +61,7 @@ func (msg *MsgPong) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgPong) Command() string { - return cmdPong + return CmdPong } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgreject.go b/msgreject.go index c8d33fff..84f21f95 100644 --- a/msgreject.go +++ b/msgreject.go @@ -52,7 +52,7 @@ func (code RejectCode) String() string { // This message was not added until protocol version RejectVersion. type MsgReject struct { // Cmd is the command for the message which was rejected such as - // as cmdBlock or cmdTx. This can be obtained from the Command function + // as CmdBlock or CmdTx. This can be obtained from the Command function // of a Message. Cmd string @@ -99,9 +99,9 @@ func (msg *MsgReject) BtcDecode(r io.Reader, pver uint32) error { } msg.Reason = reason - // cmdBlock and cmdTx messages have an additional hash field that + // CmdBlock and CmdTx messages have an additional hash field that // identifies the specific block or transaction. - if msg.Cmd == cmdBlock || msg.Cmd == cmdTx { + if msg.Cmd == CmdBlock || msg.Cmd == CmdTx { err := readElement(r, &msg.Hash) if err != nil { return err @@ -139,9 +139,9 @@ func (msg *MsgReject) BtcEncode(w io.Writer, pver uint32) error { return err } - // cmdBlock and cmdTx messages have an additional hash field that + // CmdBlock and CmdTx messages have an additional hash field that // identifies the specific block or transaction. - if msg.Cmd == cmdBlock || msg.Cmd == cmdTx { + if msg.Cmd == CmdBlock || msg.Cmd == CmdTx { err := writeElement(w, &msg.Hash) if err != nil { return err @@ -154,7 +154,7 @@ func (msg *MsgReject) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgReject) Command() string { - return cmdReject + return CmdReject } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgtx.go b/msgtx.go index df2426c7..273bc8d1 100644 --- a/msgtx.go +++ b/msgtx.go @@ -405,7 +405,7 @@ func (msg *MsgTx) SerializeSize() int { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgTx) Command() string { - return cmdTx + return CmdTx } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgverack.go b/msgverack.go index 94a27249..a6ccfa67 100644 --- a/msgverack.go +++ b/msgverack.go @@ -30,7 +30,7 @@ func (msg *MsgVerAck) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgVerAck) Command() string { - return cmdVerAck + return CmdVerAck } // MaxPayloadLength returns the maximum length the payload can be for the diff --git a/msgversion.go b/msgversion.go index f4ca826a..daf6da9d 100644 --- a/msgversion.go +++ b/msgversion.go @@ -206,7 +206,7 @@ func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32) error { // Command returns the protocol command string for the message. This is part // of the Message interface implementation. func (msg *MsgVersion) Command() string { - return cmdVersion + return CmdVersion } // MaxPayloadLength returns the maximum length the payload can be for the From 225248d2834ff4f41d1367100f90bb228d55cfc5 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 5 Sep 2014 13:56:31 -0500 Subject: [PATCH 201/219] Use byte literals in tests to make go vet happy. The go vet command complains about untagged struct initializers when defining a ShaHash directly. This seems to be a limitation where go vet does not exclude the warning for types which are a constant size byte array like it does for normal constant size byte array definition. This commit simply modifies the tests to use a constant definition cast to a ShaHash to overcome the limitation of go vet. --- common_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common_test.go b/common_test.go index a292127a..21706ee5 100644 --- a/common_test.go +++ b/common_test.go @@ -18,21 +18,21 @@ import ( // mainNetGenesisHash is the hash of the first block in the block chain for the // main network (genesis block). -var mainNetGenesisHash = btcwire.ShaHash{ +var mainNetGenesisHash = 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, -} +}) // mainNetGenesisMerkleRoot is the hash of the first transaction in the genesis // block for the main network. -var mainNetGenesisMerkleRoot = btcwire.ShaHash{ +var mainNetGenesisMerkleRoot = btcwire.ShaHash([btcwire.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. From 0127b3aafeb23a6031687bf47964dda9e30784c0 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Fri, 12 Sep 2014 08:38:59 -0500 Subject: [PATCH 202/219] Make ErrHashStrSize slightly more descriptive. Add the word 'string' to the error string so if this is printed, it will be clearer that it was a hash string decode that failed (as opposed to other errors creating a ShaHash from a byte slice) and change 'chars' to 'bytes', since the string length is measured in bytes, not UTF-8 code points. ok @davecgh --- shahash.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shahash.go b/shahash.go index b6ac8d11..1e3f8f21 100644 --- a/shahash.go +++ b/shahash.go @@ -18,7 +18,7 @@ const MaxHashStringSize = HashSize * 2 // ErrHashStrSize describes an error that indicates the caller specified a hash // string that has too many characters. -var ErrHashStrSize = fmt.Errorf("max hash length is %v chars", MaxHashStringSize) +var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStringSize) // ShaHash is used in several of the bitcoin messages and common structures. It // typically represents the double sha256 of data. From 8733b9c8df9fd1c6a563cc06cecb301610b87fe5 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 20 Sep 2014 12:44:51 -0500 Subject: [PATCH 203/219] Bump default user agent to 0.2.0. --- msgversion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgversion.go b/msgversion.go index daf6da9d..2e233a56 100644 --- a/msgversion.go +++ b/msgversion.go @@ -18,7 +18,7 @@ import ( const MaxUserAgentLen = 2000 // DefaultUserAgent for btcwire in the stack -const DefaultUserAgent = "/btcwire:0.1.4/" +const DefaultUserAgent = "/btcwire:0.2.0/" // MsgVersion implements the Message interface and represents a bitcoin version // message. It is used for a peer to advertise itself as soon as an outbound From ccee51a0beff285382ea65ee8cddf5eb56c0903b Mon Sep 17 00:00:00 2001 From: Jonathan Gillham Date: Wed, 1 Oct 2014 13:43:37 +0100 Subject: [PATCH 204/219] Changed TxIn.PreviousOutpoint to TxIn.PreviousOutPoint for consistency. --- bench_test.go | 2 +- msgblock_test.go | 2 +- msgtx.go | 12 ++++++------ msgtx_test.go | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bench_test.go b/bench_test.go index a1f31f60..69f97548 100644 --- a/bench_test.go +++ b/bench_test.go @@ -18,7 +18,7 @@ var genesisCoinbaseTx = btcwire.MsgTx{ Version: 1, TxIn: []*btcwire.TxIn{ { - PreviousOutpoint: btcwire.OutPoint{ + PreviousOutPoint: btcwire.OutPoint{ Hash: btcwire.ShaHash{}, Index: 0xffffffff, }, diff --git a/msgblock_test.go b/msgblock_test.go index 5965382d..215c3264 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -503,7 +503,7 @@ var blockOne = btcwire.MsgBlock{ Version: 1, TxIn: []*btcwire.TxIn{ { - PreviousOutpoint: btcwire.OutPoint{ + PreviousOutPoint: btcwire.OutPoint{ Hash: btcwire.ShaHash{}, Index: 0xffffffff, }, diff --git a/msgtx.go b/msgtx.go index 273bc8d1..394fc6ba 100644 --- a/msgtx.go +++ b/msgtx.go @@ -77,7 +77,7 @@ func NewOutPoint(hash *ShaHash, index uint32) *OutPoint { // TxIn defines a bitcoin transaction input. type TxIn struct { - PreviousOutpoint OutPoint + PreviousOutPoint OutPoint SignatureScript []byte Sequence uint32 } @@ -97,7 +97,7 @@ func (t *TxIn) SerializeSize() int { // MaxTxInSequenceNum. func NewTxIn(prevOut *OutPoint, signatureScript []byte) *TxIn { return &TxIn{ - PreviousOutpoint: *prevOut, + PreviousOutPoint: *prevOut, SignatureScript: signatureScript, Sequence: MaxTxInSequenceNum, } @@ -183,7 +183,7 @@ func (msg *MsgTx) Copy() *MsgTx { // Deep copy the old TxIn data. for _, oldTxIn := range msg.TxIn { // Deep copy the old previous outpoint. - oldOutPoint := oldTxIn.PreviousOutpoint + oldOutPoint := oldTxIn.PreviousOutPoint newOutPoint := OutPoint{} newOutPoint.Hash.SetBytes(oldOutPoint.Hash[:]) newOutPoint.Index = oldOutPoint.Index @@ -200,7 +200,7 @@ func (msg *MsgTx) Copy() *MsgTx { // Create new txIn with the deep copied data and append it to // new Tx. newTxIn := TxIn{ - PreviousOutpoint: newOutPoint, + PreviousOutPoint: newOutPoint, SignatureScript: newScript, Sequence: oldTxIn.Sequence, } @@ -468,7 +468,7 @@ func readTxIn(r io.Reader, pver uint32, version int32, ti *TxIn) error { if err != nil { return err } - ti.PreviousOutpoint = op + ti.PreviousOutPoint = op ti.SignatureScript, err = readVarBytes(r, pver, MaxMessagePayload, "transaction input signature script") @@ -489,7 +489,7 @@ func readTxIn(r io.Reader, pver uint32, version int32, ti *TxIn) error { // writeTxIn encodes ti to the bitcoin protocol encoding for a transaction // input (TxIn) to w. func writeTxIn(w io.Writer, pver uint32, version int32, ti *TxIn) error { - err := writeOutPoint(w, pver, version, &ti.PreviousOutpoint) + err := writeOutPoint(w, pver, version, &ti.PreviousOutPoint) if err != nil { return err } diff --git a/msgtx_test.go b/msgtx_test.go index bce99f20..bfaf650e 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -58,9 +58,9 @@ func TestTx(t *testing.T) { // Ensure we get the same transaction input back out. sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62} txIn := btcwire.NewTxIn(prevOut, sigScript) - if !reflect.DeepEqual(&txIn.PreviousOutpoint, prevOut) { + if !reflect.DeepEqual(&txIn.PreviousOutPoint, prevOut) { t.Errorf("NewTxIn: wrong prev outpoint - got %v, want %v", - spew.Sprint(&txIn.PreviousOutpoint), + spew.Sprint(&txIn.PreviousOutPoint), spew.Sprint(prevOut)) } if !bytes.Equal(txIn.SignatureScript, sigScript) { @@ -133,7 +133,7 @@ func TestTxSha(t *testing.T) { // First transaction from block 113875. msgTx := btcwire.NewMsgTx() txIn := btcwire.TxIn{ - PreviousOutpoint: btcwire.OutPoint{ + PreviousOutPoint: btcwire.OutPoint{ Hash: btcwire.ShaHash{}, Index: 0xffffffff, }, @@ -622,7 +622,7 @@ var multiTx = &btcwire.MsgTx{ Version: 1, TxIn: []*btcwire.TxIn{ { - PreviousOutpoint: btcwire.OutPoint{ + PreviousOutPoint: btcwire.OutPoint{ Hash: btcwire.ShaHash{}, Index: 0xffffffff, }, From a0fe3822fc6fc80f4d1d1c971850a652610fd5e3 Mon Sep 17 00:00:00 2001 From: Jonathan Gillham Date: Wed, 1 Oct 2014 18:14:42 +0100 Subject: [PATCH 205/219] Fixed minTxInPayload documentation. --- msgtx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msgtx.go b/msgtx.go index 394fc6ba..d1aed731 100644 --- a/msgtx.go +++ b/msgtx.go @@ -33,7 +33,7 @@ const defaultTxInOutAlloc = 15 const ( // minTxInPayload is the minimum payload size for a transaction input. - // PreviousOutpoint.Hash + PreviousOutpoint.Index 4 bytes + Varint for + // PreviousOutPoint.Hash + PreviousOutPoint.Index 4 bytes + Varint for // SignatureScript length 1 byte + Sequence 4 bytes. minTxInPayload = 9 + HashSize From 4b6cd175615634bbb36c01dcd8f4bafdbb2a05e9 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 14 Nov 2014 12:07:39 -0600 Subject: [PATCH 206/219] Make RandomUint64 block until entropy is available. This commit modifies the RandomUint64 function so that rather than returning an io.ErrShortBuffer when the system does not have enough entropy available, it now blocks until it does have enough. This means that RandomUint64 will now always eventually succeed unless the entropy source is closed (which only really ever happens when the operating system is shutting down). The tests have also been updated for the change in semantics to maintain 100% coverage. Closes #23. --- common.go | 5 +---- common_test.go | 15 ++------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/common.go b/common.go index dd6b61bd..792158ce 100644 --- a/common.go +++ b/common.go @@ -508,10 +508,7 @@ func writeVarBytes(w io.Writer, pver uint32, bytes []byte) error { // can be properly tested by passing a fake reader in the tests. func randomUint64(r io.Reader) (uint64, error) { var b [8]byte - n, err := r.Read(b[:]) - if n != len(b) { - return 0, io.ErrShortBuffer - } + _, err := io.ReadFull(r, b[:]) if err != nil { return 0, err } diff --git a/common_test.go b/common_test.go index 21706ee5..fbafe248 100644 --- a/common_test.go +++ b/common_test.go @@ -691,24 +691,13 @@ func TestRandomUint64(t *testing.T) { // and checks the results accordingly. func TestRandomUint64Errors(t *testing.T) { // Test short reads. - fr := &fakeRandReader{n: 2, err: nil} + fr := &fakeRandReader{n: 2, err: io.EOF} nonce, err := btcwire.TstRandomUint64(fr) - if err != io.ErrShortBuffer { + if err != io.ErrUnexpectedEOF { t.Errorf("TestRandomUint64Fails: Error not expected value of %v [%v]", io.ErrShortBuffer, err) } if nonce != 0 { t.Errorf("TestRandomUint64Fails: nonce is not 0 [%v]", nonce) } - - // Test err with full read. - fr = &fakeRandReader{n: 20, err: io.ErrClosedPipe} - nonce, err = btcwire.TstRandomUint64(fr) - if err != io.ErrClosedPipe { - t.Errorf("TestRandomUint64Fails: Error not expected value of %v [%v]", - io.ErrClosedPipe, err) - } - if nonce != 0 { - t.Errorf("TestRandomUint64Fails: nonce is not 0 [%v]", nonce) - } } From 7a1a260b78b7251fcb53ce6664c370d70d2a11ba Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 14 Nov 2014 21:03:37 -0600 Subject: [PATCH 207/219] Update TravisCI to work with go tip. This commit modifies the .travis.yml to invoke a new script which has also been added that gets the test coverage tool from the new path needed by go tip. --- .travis.yml | 2 +- get_ci_cover.sh | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100755 get_ci_cover.sh diff --git a/.travis.yml b/.travis.yml index 7759ad70..499ef6c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ go: - tip install: - go get -d -t -v ./... - - go get -v code.google.com/p/go.tools/cmd/cover + - ./get_ci_cover.sh script: - go test -v -covermode=count -coverprofile=profile.cov after_success: diff --git a/get_ci_cover.sh b/get_ci_cover.sh new file mode 100755 index 00000000..0aaaba51 --- /dev/null +++ b/get_ci_cover.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +set -x +if [ "$TRAVIS_GO_VERSION" = "tip" ]; then + go get -v golang.org/x/tools/cmd/cover +else + go get -v code.google.com/p/go.tools/cmd/cover +fi From 5a477c332b23f7fadc453af273ba10f9c1dcf655 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 11 Dec 2014 10:40:20 -0600 Subject: [PATCH 208/219] Update TravisCI for Go 1.4 release. Now that Go 1.4 has been released, this commit reverts the recent changes which dealt with allowing TravisCI to work with go tip in between the Go 1.3 and Go 1.4 release cycle and updates the .travis.yml to invoke test coverage tool from the new path in Go 1.4. --- .travis.yml | 2 +- get_ci_cover.sh | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) delete mode 100755 get_ci_cover.sh diff --git a/.travis.yml b/.travis.yml index 499ef6c6..4c038565 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ go: - tip install: - go get -d -t -v ./... - - ./get_ci_cover.sh + - go get -v golang.org/x/tools/cmd/cover script: - go test -v -covermode=count -coverprofile=profile.cov after_success: diff --git a/get_ci_cover.sh b/get_ci_cover.sh deleted file mode 100755 index 0aaaba51..00000000 --- a/get_ci_cover.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env sh - -set -x -if [ "$TRAVIS_GO_VERSION" = "tip" ]; then - go get -v golang.org/x/tools/cmd/cover -else - go get -v code.google.com/p/go.tools/cmd/cover -fi From 90e8b84c8bf289d4a78987c02cdbd3fe4690beb7 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Dec 2014 23:10:16 -0600 Subject: [PATCH 209/219] Update TravisCI to goclean script. - Also update to use the new container-based builds - Modify the tests slightly to make golint happy --- .travis.yml | 13 +++++++++---- internal_test.go | 10 ++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4c038565..7e9d7381 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,12 +2,17 @@ language: go go: - release - tip +sudo: false +before_install: + - gocleandeps=c16c849abae90c23419d + - git clone https://gist.github.com/$gocleandeps.git + - goclean=71d0380287747d956a26 + - git clone https://gist.github.com/$goclean.git install: - go get -d -t -v ./... - - go get -v golang.org/x/tools/cmd/cover + - bash $gocleandeps/gocleandeps.sh script: - - go test -v -covermode=count -coverprofile=profile.cov -after_success: - - go get -v github.com/mattn/goveralls - export PATH=$PATH:$HOME/gopath/bin + - bash $goclean/goclean.sh +after_success: - goveralls -coverprofile=profile.cov -service=travis-ci diff --git a/internal_test.go b/internal_test.go index 5663e05f..c53f1156 100644 --- a/internal_test.go +++ b/internal_test.go @@ -129,10 +129,16 @@ func TstWriteBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { return writeBlockHeader(w, pver, bh) } +// TstMessageHeader is simply a redefinition of the internal messageHeader that +// is used to make golint happy since it rightly complains that it's typically +// not a good idea to return unexported types. +type TstMessageHeader messageHeader + // TstReadMessageHeader makes the internal readMessageHeader function available // to the test package. -func TstReadMessageHeader(r io.Reader) (int, *messageHeader, error) { - return readMessageHeader(r) +func TstReadMessageHeader(r io.Reader) (int, *TstMessageHeader, error) { + n, hdr, err := readMessageHeader(r) + return n, (*TstMessageHeader)(hdr), err } // TstReadOutPoint makes the internal readOutPoint function available to the From a680fb6f25b9c50134b8cb828ea1a56c13108d40 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 22 Dec 2014 23:13:10 -0600 Subject: [PATCH 210/219] Update badges in README.md to SVG. Also add a license badge while here. --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 717519c5..6ab976d7 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ btcwire ======= -[![Build Status](https://travis-ci.org/conformal/btcwire.png?branch=master)] +[![Build Status](http://img.shields.io/travis/conformal/btcwire.svg)] (https://travis-ci.org/conformal/btcwire) [![Coverage Status] -(https://coveralls.io/repos/conformal/btcwire/badge.png?branch=master)] -(https://coveralls.io/r/conformal/btcwire?branch=master) +(https://img.shields.io/coveralls/conformal/btcwire.svg)] +(https://coveralls.io/r/conformal/btcwire?branch=master) [![ISC License] +(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) Package btcwire implements the bitcoin wire protocol. A comprehensive suite of tests with 100% test coverage is provided to ensure proper functionality. @@ -21,7 +22,7 @@ interface with bitcoin peers at the wire protocol level. ## Documentation -[![GoDoc](https://godoc.org/github.com/conformal/btcwire?status.png)] +[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)] (http://godoc.org/github.com/conformal/btcwire) Full `go doc` style documentation for the project can be viewed online without From df3469a79281028b6a7b93bb133e4c32e2fb9aa5 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Mon, 5 Jan 2015 17:12:36 -0500 Subject: [PATCH 211/219] Improve ShaHash.String comment and implementation. The hash is not displayed big endian, but rather as a byte-reversed hash as a hexidecimal string, so document it as such. While here, speed up the function. Some benchmarks: BenchmarkShaHashString 2000000 996 ns/op BenchmarkShaHashStringOld 100000 22701 ns/op --- shahash.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/shahash.go b/shahash.go index 1e3f8f21..3ce1e7b0 100644 --- a/shahash.go +++ b/shahash.go @@ -24,14 +24,13 @@ var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStr // typically represents the double sha256 of data. type ShaHash [HashSize]byte -// String returns the ShaHash in the standard bitcoin big-endian form. +// String returns the ShaHash as the hexidecimal string of the byte-reversed +// hash. func (hash ShaHash) String() string { - hashstr := "" - for i := range hash { - hashstr += fmt.Sprintf("%02x", hash[HashSize-1-i]) + for i := 0; i < HashSize/2; i++ { + hash[i], hash[HashSize-1-i] = hash[HashSize-1-i], hash[i] } - - return hashstr + return hex.EncodeToString(hash[:]) } // Bytes returns the bytes which represent the hash as a byte slice. From a9e05a3030afe9c2e4e5e63250d6c190215aa08e Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Mon, 5 Jan 2015 16:40:43 -0500 Subject: [PATCH 212/219] Implement String for OutPoint. --- msgtx.go | 16 ++++++++++++++++ msgtx_test.go | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/msgtx.go b/msgtx.go index d1aed731..c01ba275 100644 --- a/msgtx.go +++ b/msgtx.go @@ -9,6 +9,7 @@ import ( "encoding/binary" "fmt" "io" + "strconv" ) const ( @@ -75,6 +76,21 @@ func NewOutPoint(hash *ShaHash, index uint32) *OutPoint { } } +// String returns the OutPoint in the human-readable form "hash:index". +func (o OutPoint) String() string { + // Allocate enough for hash string, colon, and 10 digits. Although + // at the time of writing, the number of digits can be no greater than + // the length of the decimal representation of maxTxOutPerMessage, the + // maximum message payload may increase in the future and this + // optimization may go unnoticed, so allocate space for 10 decimal + // digits, which will fit any uint32. + buf := make([]byte, 2*HashSize+1, 2*HashSize+1+10) + copy(buf, o.Hash.String()) + buf[2*HashSize] = ':' + buf = strconv.AppendUint(buf, uint64(o.Index), 10) + return string(buf) +} + // TxIn defines a bitcoin transaction input. type TxIn struct { PreviousOutPoint OutPoint diff --git a/msgtx_test.go b/msgtx_test.go index bfaf650e..36c715a4 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -6,6 +6,7 @@ package btcwire_test import ( "bytes" + "fmt" "io" "reflect" "testing" @@ -44,6 +45,8 @@ func TestTx(t *testing.T) { } // Ensure we get the same transaction output point data back out. + // NOTE: This is a block hash and made up index, but we're only + // testing package functionality. prevOutIndex := uint32(1) prevOut := btcwire.NewOutPoint(hash, prevOutIndex) if !prevOut.Hash.IsEqual(hash) { @@ -54,6 +57,11 @@ func TestTx(t *testing.T) { t.Errorf("NewOutPoint: wrong index - got %v, want %v", prevOut.Index, prevOutIndex) } + prevOutStr := fmt.Sprintf("%s:%d", hash.String(), prevOutIndex) + if s := prevOut.String(); s != prevOutStr { + t.Errorf("OutPoint.String: unexpected result - got %v, "+ + "want %v", s, prevOutStr) + } // Ensure we get the same transaction input back out. sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62} From 0d01bb9cb9a988a39497f4ecef2408d42459eca9 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Mon, 5 Jan 2015 19:46:52 -0500 Subject: [PATCH 213/219] Optimize NewShaHashFromStr. --- shahash.go | 33 ++++++++++++++++----------------- shahash_test.go | 7 +++++++ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/shahash.go b/shahash.go index 3ce1e7b0..de71f294 100644 --- a/shahash.go +++ b/shahash.go @@ -24,7 +24,7 @@ var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStr // typically represents the double sha256 of data. type ShaHash [HashSize]byte -// String returns the ShaHash as the hexidecimal string of the byte-reversed +// String returns the ShaHash as the hexadecimal string of the byte-reversed // hash. func (hash ShaHash) String() string { for i := 0; i < HashSize/2; i++ { @@ -70,8 +70,9 @@ func NewShaHash(newHash []byte) (*ShaHash, error) { return &sh, err } -// NewShaHashFromStr converts a hash string in the standard bitcoin big-endian -// form to a ShaHash (which is little-endian). +// NewShaHashFromStr creates a ShaHash from a hash string. The string should be +// the hexadecimal string of a byte-reversed hash, but any missing characters +// result in zero padding at the end of the ShaHash. func NewShaHashFromStr(hash string) (*ShaHash, error) { // Return error if hash string is too long. if len(hash) > MaxHashStringSize { @@ -89,21 +90,19 @@ func NewShaHashFromStr(hash string) (*ShaHash, error) { return nil, err } - // The string was given in big-endian, so reverse the bytes to little - // endian. + // Un-reverse the decoded bytes, copying into in leading bytes of a + // ShaHash. There is no need to explicitly pad the result as any + // missing (when len(buf) < HashSize) bytes from the decoded hex string + // will remain zeros at the end of the ShaHash. + var ret ShaHash blen := len(buf) - for i := 0; i < blen/2; i++ { - buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i] + mid := blen / 2 + if blen%2 != 0 { + mid++ } - - // Make sure the byte slice is the right length by appending zeros to - // pad it out. - pbuf := buf - if HashSize-blen > 0 { - pbuf = make([]byte, HashSize) - copy(pbuf, buf) + blen-- + for i, b := range buf[:mid] { + ret[i], ret[blen-i] = buf[blen-i], b } - - // Create the sha hash using the byte slice and return it. - return NewShaHash(pbuf) + return &ret, nil } diff --git a/shahash_test.go b/shahash_test.go index 9a70b6d3..5a0172a5 100644 --- a/shahash_test.go +++ b/shahash_test.go @@ -116,6 +116,13 @@ func TestNewShaHashFromStr(t *testing.T) { nil, }, + // Empty string. + { + "", + btcwire.ShaHash{}, + nil, + }, + // Single digit hash. { "1", From 3ae8056fdb0f6823a32613af2fc0336f06bca835 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Wed, 14 Jan 2015 00:09:43 -0600 Subject: [PATCH 214/219] Move the benchmarks into the main btcwire package. The benchmarks are still only compiled when running 'go test' so this has no effect on regular usage. This is being done because benchmarks often need access to internal state. Normal tests are kept in a separate package since they also serve to exercise the public API, and by intentionally making it more difficult to reach into the internals, it helps ensure the public API is sanely usable. Since the benchmarks can now access the internals directly, this commit also removes the functions which exposed the internals to the test package from internal_test.go which were only used by the benchmarks. --- bench_test.go | 128 ++++++++++++++++++++++++++++++++++------------- internal_test.go | 48 ------------------ 2 files changed, 93 insertions(+), 83 deletions(-) diff --git a/bench_test.go b/bench_test.go index 69f97548..8b902ce6 100644 --- a/bench_test.go +++ b/bench_test.go @@ -2,24 +2,23 @@ // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package btcwire import ( "bytes" "io/ioutil" "testing" - - "github.com/conformal/btcwire" + "time" ) // genesisCoinbaseTx is the coinbase transaction for the genesis blocks for // the main network, regression test network, and test network (version 3). -var genesisCoinbaseTx = btcwire.MsgTx{ +var genesisCoinbaseTx = MsgTx{ Version: 1, - TxIn: []*btcwire.TxIn{ + TxIn: []*TxIn{ { - PreviousOutPoint: btcwire.OutPoint{ - Hash: btcwire.ShaHash{}, + PreviousOutPoint: OutPoint{ + Hash: ShaHash{}, Index: 0xffffffff, }, SignatureScript: []byte{ @@ -37,7 +36,7 @@ var genesisCoinbaseTx = btcwire.MsgTx{ Sequence: 0xffffffff, }, }, - TxOut: []*btcwire.TxOut{ + TxOut: []*TxOut{ { Value: 0x12a05f200, PkScript: []byte{ @@ -56,11 +55,70 @@ var genesisCoinbaseTx = btcwire.MsgTx{ LockTime: 0, } +// blockOne is the first block in the mainnet block chain. +var blockOne = MsgBlock{ + Header: BlockHeader{ + Version: 1, + PrevBlock: ShaHash([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: ShaHash([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: []*MsgTx{ + { + Version: 1, + TxIn: []*TxIn{ + { + PreviousOutPoint: OutPoint{ + Hash: ShaHash{}, + Index: 0xffffffff, + }, + SignatureScript: []byte{ + 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, + }, + Sequence: 0xffffffff, + }, + }, + TxOut: []*TxOut{ + { + Value: 0x12a05f200, + PkScript: []byte{ + 0x41, // OP_DATA_65 + 0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c, + 0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16, + 0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c, + 0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c, + 0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4, + 0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6, + 0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e, + 0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58, + 0xee, // 65-byte signature + 0xac, // OP_CHECKSIG + }, + }, + }, + LockTime: 0, + }, + }, +} + // BenchmarkWriteVarInt1 performs a benchmark on how long it takes to write // a single byte variable length integer. func BenchmarkWriteVarInt1(b *testing.B) { for i := 0; i < b.N; i++ { - btcwire.TstWriteVarInt(ioutil.Discard, 0, 1) + writeVarInt(ioutil.Discard, 0, 1) } } @@ -68,7 +126,7 @@ func BenchmarkWriteVarInt1(b *testing.B) { // a three byte variable length integer. func BenchmarkWriteVarInt3(b *testing.B) { for i := 0; i < b.N; i++ { - btcwire.TstWriteVarInt(ioutil.Discard, 0, 65535) + writeVarInt(ioutil.Discard, 0, 65535) } } @@ -76,7 +134,7 @@ func BenchmarkWriteVarInt3(b *testing.B) { // a five byte variable length integer. func BenchmarkWriteVarInt5(b *testing.B) { for i := 0; i < b.N; i++ { - btcwire.TstWriteVarInt(ioutil.Discard, 0, 4294967295) + writeVarInt(ioutil.Discard, 0, 4294967295) } } @@ -84,7 +142,7 @@ func BenchmarkWriteVarInt5(b *testing.B) { // a nine byte variable length integer. func BenchmarkWriteVarInt9(b *testing.B) { for i := 0; i < b.N; i++ { - btcwire.TstWriteVarInt(ioutil.Discard, 0, 18446744073709551615) + writeVarInt(ioutil.Discard, 0, 18446744073709551615) } } @@ -93,7 +151,7 @@ func BenchmarkWriteVarInt9(b *testing.B) { func BenchmarkReadVarInt1(b *testing.B) { buf := []byte{0x01} for i := 0; i < b.N; i++ { - btcwire.TstReadVarInt(bytes.NewReader(buf), 0) + readVarInt(bytes.NewReader(buf), 0) } } @@ -102,7 +160,7 @@ func BenchmarkReadVarInt1(b *testing.B) { func BenchmarkReadVarInt3(b *testing.B) { buf := []byte{0x0fd, 0xff, 0xff} for i := 0; i < b.N; i++ { - btcwire.TstReadVarInt(bytes.NewReader(buf), 0) + readVarInt(bytes.NewReader(buf), 0) } } @@ -111,7 +169,7 @@ func BenchmarkReadVarInt3(b *testing.B) { func BenchmarkReadVarInt5(b *testing.B) { buf := []byte{0xfe, 0xff, 0xff, 0xff, 0xff} for i := 0; i < b.N; i++ { - btcwire.TstReadVarInt(bytes.NewReader(buf), 0) + readVarInt(bytes.NewReader(buf), 0) } } @@ -120,7 +178,7 @@ func BenchmarkReadVarInt5(b *testing.B) { func BenchmarkReadVarInt9(b *testing.B) { buf := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} for i := 0; i < b.N; i++ { - btcwire.TstReadVarInt(bytes.NewReader(buf), 0) + readVarInt(bytes.NewReader(buf), 0) } } @@ -129,7 +187,7 @@ func BenchmarkReadVarInt9(b *testing.B) { func BenchmarkReadVarStr4(b *testing.B) { buf := []byte{0x04, 't', 'e', 's', 't'} for i := 0; i < b.N; i++ { - btcwire.TstReadVarString(bytes.NewReader(buf), 0) + readVarString(bytes.NewReader(buf), 0) } } @@ -138,7 +196,7 @@ func BenchmarkReadVarStr4(b *testing.B) { func BenchmarkReadVarStr10(b *testing.B) { buf := []byte{0x0a, 't', 'e', 's', 't', '0', '1', '2', '3', '4', '5'} for i := 0; i < b.N; i++ { - btcwire.TstReadVarString(bytes.NewReader(buf), 0) + readVarString(bytes.NewReader(buf), 0) } } @@ -146,7 +204,7 @@ func BenchmarkReadVarStr10(b *testing.B) { // four byte variable length string. func BenchmarkWriteVarStr4(b *testing.B) { for i := 0; i < b.N; i++ { - btcwire.TstWriteVarString(ioutil.Discard, 0, "test") + writeVarString(ioutil.Discard, 0, "test") } } @@ -154,7 +212,7 @@ func BenchmarkWriteVarStr4(b *testing.B) { // ten byte variable length string. func BenchmarkWriteVarStr10(b *testing.B) { for i := 0; i < b.N; i++ { - btcwire.TstWriteVarString(ioutil.Discard, 0, "test012345") + writeVarString(ioutil.Discard, 0, "test012345") } } @@ -168,21 +226,21 @@ func BenchmarkReadOutPoint(b *testing.B) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash 0xff, 0xff, 0xff, 0xff, // Previous output index } - var op btcwire.OutPoint + var op OutPoint for i := 0; i < b.N; i++ { - btcwire.TstReadOutPoint(bytes.NewReader(buf), 0, 0, &op) + readOutPoint(bytes.NewReader(buf), 0, 0, &op) } } // BenchmarkWriteOutPoint performs a benchmark on how long it takes to write a // transaction output point. func BenchmarkWriteOutPoint(b *testing.B) { - op := &btcwire.OutPoint{ - Hash: btcwire.ShaHash{}, + op := &OutPoint{ + Hash: ShaHash{}, Index: 0, } for i := 0; i < b.N; i++ { - btcwire.TstWriteOutPoint(ioutil.Discard, 0, 0, op) + writeOutPoint(ioutil.Discard, 0, 0, op) } } @@ -204,9 +262,9 @@ func BenchmarkReadTxOut(b *testing.B) { 0xee, // 65-byte signature 0xac, // OP_CHECKSIG } - var txOut btcwire.TxOut + var txOut TxOut for i := 0; i < b.N; i++ { - btcwire.TstReadTxOut(bytes.NewReader(buf), 0, 0, &txOut) + readTxOut(bytes.NewReader(buf), 0, 0, &txOut) } } @@ -215,7 +273,7 @@ func BenchmarkReadTxOut(b *testing.B) { func BenchmarkWriteTxOut(b *testing.B) { txOut := blockOne.Transactions[0].TxOut[0] for i := 0; i < b.N; i++ { - btcwire.TstWriteTxOut(ioutil.Discard, 0, 0, txOut) + writeTxOut(ioutil.Discard, 0, 0, txOut) } } @@ -232,9 +290,9 @@ func BenchmarkReadTxIn(b *testing.B) { 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script 0xff, 0xff, 0xff, 0xff, // Sequence } - var txIn btcwire.TxIn + var txIn TxIn for i := 0; i < b.N; i++ { - btcwire.TstReadTxIn(bytes.NewReader(buf), 0, 0, &txIn) + readTxIn(bytes.NewReader(buf), 0, 0, &txIn) } } @@ -243,7 +301,7 @@ func BenchmarkReadTxIn(b *testing.B) { func BenchmarkWriteTxIn(b *testing.B) { txIn := blockOne.Transactions[0].TxIn[0] for i := 0; i < b.N; i++ { - btcwire.TstWriteTxIn(ioutil.Discard, 0, 0, txIn) + writeTxIn(ioutil.Discard, 0, 0, txIn) } } @@ -277,7 +335,7 @@ func BenchmarkDeserializeTx(b *testing.B) { 0xac, // OP_CHECKSIG 0x00, 0x00, 0x00, 0x00, // Lock time } - var tx btcwire.MsgTx + var tx MsgTx for i := 0; i < b.N; i++ { tx.Deserialize(bytes.NewReader(buf)) @@ -312,9 +370,9 @@ func BenchmarkReadBlockHeader(b *testing.B) { 0xf3, 0xe0, 0x01, 0x00, // Nonce 0x00, // TxnCount Varint } - var header btcwire.BlockHeader + var header BlockHeader for i := 0; i < b.N; i++ { - btcwire.TstReadBlockHeader(bytes.NewReader(buf), 0, &header) + readBlockHeader(bytes.NewReader(buf), 0, &header) } } @@ -323,7 +381,7 @@ func BenchmarkReadBlockHeader(b *testing.B) { func BenchmarkWriteBlockHeader(b *testing.B) { header := blockOne.Header for i := 0; i < b.N; i++ { - btcwire.TstWriteBlockHeader(ioutil.Discard, 0, &header) + writeBlockHeader(ioutil.Discard, 0, &header) } } diff --git a/internal_test.go b/internal_test.go index c53f1156..cb8ca9ee 100644 --- a/internal_test.go +++ b/internal_test.go @@ -128,51 +128,3 @@ func TstReadBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error { func TstWriteBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error { return writeBlockHeader(w, pver, bh) } - -// TstMessageHeader is simply a redefinition of the internal messageHeader that -// is used to make golint happy since it rightly complains that it's typically -// not a good idea to return unexported types. -type TstMessageHeader messageHeader - -// TstReadMessageHeader makes the internal readMessageHeader function available -// to the test package. -func TstReadMessageHeader(r io.Reader) (int, *TstMessageHeader, error) { - n, hdr, err := readMessageHeader(r) - return n, (*TstMessageHeader)(hdr), err -} - -// TstReadOutPoint makes the internal readOutPoint function available to the -// test package. -func TstReadOutPoint(r io.Reader, pver uint32, version int32, op *OutPoint) error { - return readOutPoint(r, pver, version, op) -} - -// TstWriteOutPoint makes the internal writeOutPoint function available to the -// test package. -func TstWriteOutPoint(w io.Writer, pver uint32, version int32, op *OutPoint) error { - return writeOutPoint(w, pver, version, op) -} - -// TstReadTxOut makes the internal readTxOut function available to the test -// package. -func TstReadTxOut(r io.Reader, pver uint32, version int32, to *TxOut) error { - return readTxOut(r, pver, version, to) -} - -// TstWriteTxOut makes the internal writeTxOut function available to the test -// package. -func TstWriteTxOut(w io.Writer, pver uint32, version int32, to *TxOut) error { - return writeTxOut(w, pver, version, to) -} - -// TstReadTxIn makes the internal readTxIn function available to the test -// package. -func TstReadTxIn(r io.Reader, pver uint32, version int32, ti *TxIn) error { - return readTxIn(r, pver, version, ti) -} - -// TstWriteTxIn makes the internal writeTxIn function available to the test -// package. -func TstWriteTxIn(w io.Writer, pver uint32, version int32, ti *TxIn) error { - return writeTxIn(w, pver, version, ti) -} From a9183f688ff8134c0985c4196eb38aca0da49001 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Tue, 13 Jan 2015 23:59:03 -0600 Subject: [PATCH 215/219] Ensure all serialization is using fast path. The writeElement function provides faster serialization for primitives. This commit modifies all instances that call writeElement with a pointer to a primitive or a byte slice to instead use the primitive / writeVarBytes function so the faster serialization paths are used. --- msgalert.go | 10 +++++----- msgmerkleblock.go | 6 +----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/msgalert.go b/msgalert.go index 4aa186a8..787a01ef 100644 --- a/msgalert.go +++ b/msgalert.go @@ -149,8 +149,8 @@ type Alert struct { // Serialize encodes the alert to w using the alert protocol encoding format. func (alert *Alert) Serialize(w io.Writer, pver uint32) error { - err := writeElements(w, &alert.Version, - &alert.RelayUntil, &alert.Expiration, &alert.ID, &alert.Cancel) + err := writeElements(w, alert.Version, alert.RelayUntil, + alert.Expiration, alert.ID, alert.Cancel) if err != nil { return err } @@ -166,13 +166,13 @@ func (alert *Alert) Serialize(w io.Writer, pver uint32) error { return err } for i := 0; i < int(count); i++ { - err = writeElement(w, &alert.SetCancel[i]) + err = writeElement(w, alert.SetCancel[i]) if err != nil { return err } } - err = writeElements(w, &alert.MinVer, &alert.MaxVer) + err = writeElements(w, alert.MinVer, alert.MaxVer) if err != nil { return err } @@ -194,7 +194,7 @@ func (alert *Alert) Serialize(w io.Writer, pver uint32) error { } } - err = writeElement(w, &alert.Priority) + err = writeElement(w, alert.Priority) if err != nil { return err } diff --git a/msgmerkleblock.go b/msgmerkleblock.go index b5f2ae36..dcdcae99 100644 --- a/msgmerkleblock.go +++ b/msgmerkleblock.go @@ -131,11 +131,7 @@ func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32) error { } } - err = writeVarInt(w, pver, uint64(numFlagBytes)) - if err != nil { - return err - } - err = writeElement(w, msg.Flags) + err = writeVarBytes(w, pver, msg.Flags) if err != nil { return err } From 2c1923897dd73ff227065ba05479f780675121b8 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 16 Jan 2015 09:05:26 -0600 Subject: [PATCH 216/219] Update fastsha256 import paths to new location. --- common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.go b/common.go index 792158ce..a8bdd9dc 100644 --- a/common.go +++ b/common.go @@ -11,7 +11,7 @@ import ( "io" "math" - "github.com/conformal/fastsha256" + "github.com/btcsuite/fastsha256" ) // Maximum payload size for a variable length integer. From d3e2947c059d3ac6c7e33d9547e4d2f9cbd6c71c Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 16 Jan 2015 13:54:11 -0600 Subject: [PATCH 217/219] Update btcwire import paths to new location. --- README.md | 8 ++++---- blockheader_test.go | 2 +- common_test.go | 2 +- fakemessage_test.go | 2 +- invvect_test.go | 2 +- message_test.go | 2 +- msgaddr_test.go | 2 +- msgalert_test.go | 2 +- msgblock_test.go | 2 +- msgfilteradd_test.go | 2 +- msgfilterclear_test.go | 2 +- msgfilterload_test.go | 2 +- msggetaddr_test.go | 2 +- msggetblocks_test.go | 2 +- msggetdata_test.go | 2 +- msggetheaders_test.go | 2 +- msgheaders_test.go | 2 +- msginv_test.go | 2 +- msgmempool_test.go | 2 +- msgmerkleblock_test.go | 2 +- msgnotfound_test.go | 2 +- msgping_test.go | 2 +- msgpong_test.go | 2 +- msgreject_test.go | 2 +- msgtx_test.go | 2 +- msgverack_test.go | 2 +- msgversion_test.go | 2 +- netaddress_test.go | 2 +- protocol_test.go | 2 +- shahash_test.go | 2 +- 30 files changed, 33 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 6ab976d7..f5c9d3d4 100644 --- a/README.md +++ b/README.md @@ -23,20 +23,20 @@ interface with bitcoin peers at the wire protocol level. ## Documentation [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)] -(http://godoc.org/github.com/conformal/btcwire) +(http://godoc.org/github.com/btcsuite/btcwire) Full `go doc` style documentation for the project can be viewed online without installing this package by using the GoDoc site here: -http://godoc.org/github.com/conformal/btcwire +http://godoc.org/github.com/btcsuite/btcwire You can also view the documentation locally once the package is installed with the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to -http://localhost:6060/pkg/github.com/conformal/btcwire +http://localhost:6060/pkg/github.com/btcsuite/btcwire ## Installation ```bash -$ go get github.com/conformal/btcwire +$ go get github.com/btcsuite/btcwire ``` ## Bitcoin Message Overview diff --git a/blockheader_test.go b/blockheader_test.go index 4fe2047c..0c137663 100644 --- a/blockheader_test.go +++ b/blockheader_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/common_test.go b/common_test.go index fbafe248..0ad1f463 100644 --- a/common_test.go +++ b/common_test.go @@ -12,7 +12,7 @@ import ( "strings" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/fakemessage_test.go b/fakemessage_test.go index 25541196..74844527 100644 --- a/fakemessage_test.go +++ b/fakemessage_test.go @@ -7,7 +7,7 @@ package btcwire_test import ( "io" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" ) // fakeMessage implements the btcwire.Message interface and is used to force diff --git a/invvect_test.go b/invvect_test.go index 351081b6..a467a3bd 100644 --- a/invvect_test.go +++ b/invvect_test.go @@ -9,7 +9,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/message_test.go b/message_test.go index aeb80284..9eaaafab 100644 --- a/message_test.go +++ b/message_test.go @@ -13,7 +13,7 @@ import ( "testing" "time" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgaddr_test.go b/msgaddr_test.go index 612b1f4b..30d735e0 100644 --- a/msgaddr_test.go +++ b/msgaddr_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgalert_test.go b/msgalert_test.go index ecd993a5..6805a47c 100644 --- a/msgalert_test.go +++ b/msgalert_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgblock_test.go b/msgblock_test.go index 215c3264..371f084d 100644 --- a/msgblock_test.go +++ b/msgblock_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgfilteradd_test.go b/msgfilteradd_test.go index 73d612ee..1a87bac2 100644 --- a/msgfilteradd_test.go +++ b/msgfilteradd_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" ) // TestFilterAddLatest tests the MsgFilterAdd API against the latest protocol diff --git a/msgfilterclear_test.go b/msgfilterclear_test.go index 3e368ac3..17047aac 100644 --- a/msgfilterclear_test.go +++ b/msgfilterclear_test.go @@ -9,7 +9,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgfilterload_test.go b/msgfilterload_test.go index 56f5dace..c1c25262 100644 --- a/msgfilterload_test.go +++ b/msgfilterload_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" ) // TestFilterCLearLatest tests the MsgFilterLoad API against the latest protocol diff --git a/msggetaddr_test.go b/msggetaddr_test.go index 86dae99b..bd5d5539 100644 --- a/msggetaddr_test.go +++ b/msggetaddr_test.go @@ -9,7 +9,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msggetblocks_test.go b/msggetblocks_test.go index e8f5e259..03733a2b 100644 --- a/msggetblocks_test.go +++ b/msggetblocks_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msggetdata_test.go b/msggetdata_test.go index 6c4ebf9d..4673e58f 100644 --- a/msggetdata_test.go +++ b/msggetdata_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msggetheaders_test.go b/msggetheaders_test.go index 8c57fcd4..01e99493 100644 --- a/msggetheaders_test.go +++ b/msggetheaders_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgheaders_test.go b/msgheaders_test.go index cc2060e3..c7912355 100644 --- a/msgheaders_test.go +++ b/msgheaders_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msginv_test.go b/msginv_test.go index ae608e99..4b8cd4d1 100644 --- a/msginv_test.go +++ b/msginv_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgmempool_test.go b/msgmempool_test.go index 3a5a08c9..64e23317 100644 --- a/msgmempool_test.go +++ b/msgmempool_test.go @@ -8,7 +8,7 @@ import ( "bytes" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" ) func TestMemPool(t *testing.T) { diff --git a/msgmerkleblock_test.go b/msgmerkleblock_test.go index ffb12d9e..5d77af07 100644 --- a/msgmerkleblock_test.go +++ b/msgmerkleblock_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgnotfound_test.go b/msgnotfound_test.go index 98a05876..5dd14e9e 100644 --- a/msgnotfound_test.go +++ b/msgnotfound_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgping_test.go b/msgping_test.go index 79db0c1f..b886a38d 100644 --- a/msgping_test.go +++ b/msgping_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgpong_test.go b/msgpong_test.go index fd99e53b..5d1f6cff 100644 --- a/msgpong_test.go +++ b/msgpong_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgreject_test.go b/msgreject_test.go index e369492a..ff9bebf4 100644 --- a/msgreject_test.go +++ b/msgreject_test.go @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgtx_test.go b/msgtx_test.go index 36c715a4..eefcba80 100644 --- a/msgtx_test.go +++ b/msgtx_test.go @@ -11,7 +11,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgverack_test.go b/msgverack_test.go index b5d616c5..f018d9a8 100644 --- a/msgverack_test.go +++ b/msgverack_test.go @@ -9,7 +9,7 @@ import ( "reflect" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/msgversion_test.go b/msgversion_test.go index 7f1bced1..f4b431e5 100644 --- a/msgversion_test.go +++ b/msgversion_test.go @@ -13,7 +13,7 @@ import ( "testing" "time" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/netaddress_test.go b/netaddress_test.go index c3649239..e683eb01 100644 --- a/netaddress_test.go +++ b/netaddress_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" "github.com/davecgh/go-spew/spew" ) diff --git a/protocol_test.go b/protocol_test.go index 05d112c7..e8e25b84 100644 --- a/protocol_test.go +++ b/protocol_test.go @@ -7,7 +7,7 @@ package btcwire_test import ( "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" ) // TestServiceFlagStringer tests the stringized output for service flag types. diff --git a/shahash_test.go b/shahash_test.go index 5a0172a5..cc527d2e 100644 --- a/shahash_test.go +++ b/shahash_test.go @@ -9,7 +9,7 @@ import ( "encoding/hex" "testing" - "github.com/conformal/btcwire" + "github.com/btcsuite/btcwire" ) // TestShaHash tests the ShaHash API. From cb858fd1071d967dbc6662df55bfd7f3469ecebc Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 16 Jan 2015 23:22:34 -0600 Subject: [PATCH 218/219] Update to new location in README.md too. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f5c9d3d4..1f9d8ce8 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ btcwire ======= -[![Build Status](http://img.shields.io/travis/conformal/btcwire.svg)] -(https://travis-ci.org/conformal/btcwire) [![Coverage Status] -(https://img.shields.io/coveralls/conformal/btcwire.svg)] -(https://coveralls.io/r/conformal/btcwire?branch=master) [![ISC License] +[![Build Status](http://img.shields.io/travis/btcsuite/btcwire.svg)] +(https://travis-ci.org/btcsuite/btcwire) [![Coverage Status] +(https://img.shields.io/coveralls/btcsuite/btcwire.svg)] +(https://coveralls.io/r/btcsuite/btcwire?branch=master) [![ISC License] (http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) Package btcwire implements the bitcoin wire protocol. A comprehensive suite of From 2eef3720a95697bd8d3bd9556a40bdcf338f2488 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 31 Jan 2015 12:32:55 -0600 Subject: [PATCH 219/219] Import btcwire repo into wire directory. This commit contains the entire btcwire repository along with several changes needed to move all of the files into the wire directory in order to prepare it for merging. This does NOT update btcd or any of the other packages to use the new location as that will be done separately. - All import paths in the old btcwire test files have been changed to the new location - All references to btcwire as the package name have been chagned to wire - The coveralls badge has been removed since it unfortunately doesn't support coverage of sub-packages This is ongoing work toward #214. --- .gitignore | 34 --- .travis.yml | 18 -- LICENSE | 13 -- cov_report.sh | 17 -- README.md => wire/README.md | 47 ++--- bench_test.go => wire/bench_test.go | 4 +- blockheader.go => wire/blockheader.go | 4 +- .../blockheader_test.go | 46 ++--- common.go => wire/common.go | 4 +- common_test.go => wire/common_test.go | 102 ++++----- doc.go => wire/doc.go | 30 +-- error.go => wire/error.go | 4 +- fakeconn_test.go => wire/fakeconn_test.go | 4 +- .../fakemessage_test.go | 18 +- fixedIO_test.go => wire/fixedIO_test.go | 4 +- internal_test.go => wire/internal_test.go | 12 +- invvect.go => wire/invvect.go | 4 +- invvect_test.go => wire/invvect_test.go | 80 ++++---- message.go => wire/message.go | 4 +- message_test.go => wire/message_test.go | 194 +++++++++--------- msgaddr.go => wire/msgaddr.go | 4 +- msgaddr_test.go => wire/msgaddr_test.go | 92 ++++----- msgalert.go => wire/msgalert.go | 4 +- msgalert_test.go => wire/msgalert_test.go | 114 +++++----- msgblock.go => wire/msgblock.go | 4 +- msgblock_test.go => wire/msgblock_test.go | 110 +++++----- msgfilteradd.go => wire/msgfilteradd.go | 4 +- .../msgfilteradd_test.go | 58 +++--- msgfilterclear.go => wire/msgfilterclear.go | 4 +- .../msgfilterclear_test.go | 66 +++--- msgfilterload.go => wire/msgfilterload.go | 4 +- .../msgfilterload_test.go | 54 ++--- msggetaddr.go => wire/msggetaddr.go | 4 +- msggetaddr_test.go => wire/msggetaddr_test.go | 32 +-- msggetblocks.go => wire/msggetblocks.go | 4 +- .../msggetblocks_test.go | 94 ++++----- msggetdata.go => wire/msggetdata.go | 4 +- msggetdata_test.go => wire/msggetdata_test.go | 100 ++++----- msggetheaders.go => wire/msggetheaders.go | 4 +- .../msggetheaders_test.go | 92 ++++----- msgheaders.go => wire/msgheaders.go | 4 +- msgheaders_test.go => wire/msgheaders_test.go | 90 ++++---- msginv.go => wire/msginv.go | 4 +- msginv_test.go => wire/msginv_test.go | 100 ++++----- msgmempool.go => wire/msgmempool.go | 4 +- msgmempool_test.go => wire/msgmempool_test.go | 14 +- msgmerkleblock.go => wire/msgmerkleblock.go | 4 +- .../msgmerkleblock_test.go | 96 ++++----- msgnotfound.go => wire/msgnotfound.go | 4 +- .../msgnotfound_test.go | 96 ++++----- msgping.go => wire/msgping.go | 4 +- msgping_test.go => wire/msgping_test.go | 78 +++---- msgpong.go => wire/msgpong.go | 4 +- msgpong_test.go => wire/msgpong_test.go | 86 ++++---- msgreject.go => wire/msgreject.go | 4 +- msgreject_test.go => wire/msgreject_test.go | 116 +++++------ msgtx.go => wire/msgtx.go | 4 +- msgtx_test.go => wire/msgtx_test.go | 124 +++++------ msgverack.go => wire/msgverack.go | 4 +- msgverack_test.go => wire/msgverack_test.go | 32 +-- msgversion.go => wire/msgversion.go | 7 +- msgversion_test.go => wire/msgversion_test.go | 162 +++++++-------- netaddress.go => wire/netaddress.go | 4 +- netaddress_test.go => wire/netaddress_test.go | 92 ++++----- protocol.go => wire/protocol.go | 4 +- protocol_test.go => wire/protocol_test.go | 20 +- shahash.go => wire/shahash.go | 4 +- shahash_test.go => wire/shahash_test.go | 36 ++-- 68 files changed, 1305 insertions(+), 1391 deletions(-) delete mode 100644 .gitignore delete mode 100644 .travis.yml delete mode 100644 LICENSE delete mode 100644 cov_report.sh rename README.md => wire/README.md (71%) rename bench_test.go => wire/bench_test.go (99%) rename blockheader.go => wire/blockheader.go (98%) rename blockheader_test.go => wire/blockheader_test.go (84%) rename common.go => wire/common.go (99%) rename common_test.go => wire/common_test.go (88%) rename doc.go => wire/doc.go (89%) rename error.go => wire/error.go (94%) rename fakeconn_test.go => wire/fakeconn_test.go (95%) rename fakemessage_test.go => wire/fakemessage_test.go (75%) rename fixedIO_test.go => wire/fixedIO_test.go (96%) rename internal_test.go => wire/internal_test.go (91%) rename invvect.go => wire/invvect.go (96%) rename invvect_test.go => wire/invvect_test.go (78%) rename message.go => wire/message.go (99%) rename message_test.go => wire/message_test.go (65%) rename msgaddr.go => wire/msgaddr.go (98%) rename msgaddr_test.go => wire/msgaddr_test.go (80%) rename msgalert.go => wire/msgalert.go (99%) rename msgalert_test.go => wire/msgalert_test.go (85%) rename msgblock.go => wire/msgblock.go (99%) rename msgblock_test.go => wire/msgblock_test.go (86%) rename msgfilteradd.go => wire/msgfilteradd.go (97%) rename msgfilteradd_test.go => wire/msgfilteradd_test.go (75%) rename msgfilterclear.go => wire/msgfilterclear.go (96%) rename msgfilterclear_test.go => wire/msgfilterclear_test.go (71%) rename msgfilterload.go => wire/msgfilterload.go (98%) rename msgfilterload_test.go => wire/msgfilterload_test.go (81%) rename msggetaddr.go => wire/msggetaddr.go (95%) rename msggetaddr_test.go => wire/msggetaddr_test.go (79%) rename msggetblocks.go => wire/msggetblocks.go (98%) rename msggetblocks_test.go => wire/msggetblocks_test.go (81%) rename msggetdata.go => wire/msggetdata.go (98%) rename msggetdata_test.go => wire/msggetdata_test.go (76%) rename msggetheaders.go => wire/msggetheaders.go (98%) rename msggetheaders_test.go => wire/msggetheaders_test.go (82%) rename msgheaders.go => wire/msgheaders.go (98%) rename msgheaders_test.go => wire/msgheaders_test.go (80%) rename msginv.go => wire/msginv.go (98%) rename msginv_test.go => wire/msginv_test.go (77%) rename msgmempool.go => wire/msgmempool.go (96%) rename msgmempool_test.go => wire/msgmempool_test.go (86%) rename msgmerkleblock.go => wire/msgmerkleblock.go (98%) rename msgmerkleblock_test.go => wire/msgmerkleblock_test.go (82%) rename msgnotfound.go => wire/msgnotfound.go (97%) rename msgnotfound_test.go => wire/msgnotfound_test.go (76%) rename msgping.go => wire/msgping.go (97%) rename msgping_test.go => wire/msgping_test.go (76%) rename msgpong.go => wire/msgpong.go (97%) rename msgpong_test.go => wire/msgpong_test.go (76%) rename msgreject.go => wire/msgreject.go (98%) rename msgreject_test.go => wire/msgreject_test.go (78%) rename msgtx.go => wire/msgtx.go (99%) rename msgtx_test.go => wire/msgtx_test.go (89%) rename msgverack.go => wire/msgverack.go (95%) rename msgverack_test.go => wire/msgverack_test.go (78%) rename msgversion.go => wire/msgversion.go (98%) rename msgversion_test.go => wire/msgversion_test.go (81%) rename netaddress.go => wire/netaddress.go (98%) rename netaddress_test.go => wire/netaddress_test.go (77%) rename protocol.go => wire/protocol.go (98%) rename protocol_test.go => wire/protocol_test.go (75%) rename shahash.go => wire/shahash.go (97%) rename shahash_test.go => wire/shahash_test.go (84%) diff --git a/.gitignore b/.gitignore deleted file mode 100644 index c887bc15..00000000 --- a/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -# Temp files -*~ -btcwire.test - -# Databases -btcd.db -*-shm -*-wal - -# Log files -*.log - -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7e9d7381..00000000 --- a/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: go -go: - - release - - tip -sudo: false -before_install: - - gocleandeps=c16c849abae90c23419d - - git clone https://gist.github.com/$gocleandeps.git - - goclean=71d0380287747d956a26 - - git clone https://gist.github.com/$goclean.git -install: - - go get -d -t -v ./... - - bash $gocleandeps/gocleandeps.sh -script: - - export PATH=$PATH:$HOME/gopath/bin - - bash $goclean/goclean.sh -after_success: - - goveralls -coverprofile=profile.cov -service=travis-ci diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 992dd50d..00000000 --- a/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright (c) 2013-2014 Conformal Systems LLC. - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/cov_report.sh b/cov_report.sh deleted file mode 100644 index 307f05b7..00000000 --- a/cov_report.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -# This script uses gocov to generate a test coverage report. -# The gocov tool my be obtained with the following command: -# go get github.com/axw/gocov/gocov -# -# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH. - -# Check for gocov. -type gocov >/dev/null 2>&1 -if [ $? -ne 0 ]; then - echo >&2 "This script requires the gocov tool." - echo >&2 "You may obtain it with the following command:" - echo >&2 "go get github.com/axw/gocov/gocov" - exit 1 -fi -gocov test | gocov report diff --git a/README.md b/wire/README.md similarity index 71% rename from README.md rename to wire/README.md index 1f9d8ce8..94b5be11 100644 --- a/README.md +++ b/wire/README.md @@ -1,42 +1,37 @@ -btcwire -======= +wire +==== -[![Build Status](http://img.shields.io/travis/btcsuite/btcwire.svg)] -(https://travis-ci.org/btcsuite/btcwire) [![Coverage Status] -(https://img.shields.io/coveralls/btcsuite/btcwire.svg)] -(https://coveralls.io/r/btcsuite/btcwire?branch=master) [![ISC License] +[![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)] +(https://travis-ci.org/btcsuite/btcd) [![ISC License] (http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) -Package btcwire implements the bitcoin wire protocol. A comprehensive suite of +Package wire implements the bitcoin wire protocol. A comprehensive suite of tests with 100% test coverage is provided to ensure proper functionality. -Package btcwire is licensed under the liberal ISC license. There is an associated blog post about the release of this package [here](https://blog.conformal.com/btcwire-the-bitcoin-wire-protocol-package-from-btcd/). -This package is one of the core packages from btcd, an alternative full-node -implementation of bitcoin which is under active development by Conformal. -Although it was primarily written for btcd, this package has intentionally been -designed so it can be used as a standalone package for any projects needing to -interface with bitcoin peers at the wire protocol level. +This package has intentionally been designed so it can be used as a standalone +package for any projects needing to interface with bitcoin peers at the wire +protocol level. ## Documentation [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)] -(http://godoc.org/github.com/btcsuite/btcwire) +(http://godoc.org/github.com/btcsuite/btcd/wire) Full `go doc` style documentation for the project can be viewed online without installing this package by using the GoDoc site here: -http://godoc.org/github.com/btcsuite/btcwire +http://godoc.org/github.com/btcsuite/btcd/wire You can also view the documentation locally once the package is installed with the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to -http://localhost:6060/pkg/github.com/btcsuite/btcwire +http://localhost:6060/pkg/github.com/btcsuite/btcd/wire ## Installation ```bash -$ go get github.com/btcsuite/btcwire +$ go get github.com/btcsuite/btcd/wire ``` ## Bitcoin Message Overview @@ -64,14 +59,14 @@ to a remote node running a bitcoin peer. Example syntax is: ```Go // Use the most recent protocol version supported by the package and the // main bitcoin network. - pver := btcwire.ProtocolVersion - btcnet := btcwire.MainNet + pver := wire.ProtocolVersion + btcnet := wire.MainNet // Reads and validates the next bitcoin message from conn using the // protocol version pver and the bitcoin network btcnet. The returns - // are a btcwire.Message, a []byte which contains the unmarshalled + // are a wire.Message, a []byte which contains the unmarshalled // raw payload, and a possible error. - msg, rawPayload, err := btcwire.ReadMessage(conn, pver, btcnet) + msg, rawPayload, err := wire.ReadMessage(conn, pver, btcnet) if err != nil { // Log and handle the error } @@ -89,16 +84,16 @@ from a remote peer is: ```Go // Use the most recent protocol version supported by the package and the // main bitcoin network. - pver := btcwire.ProtocolVersion - btcnet := btcwire.MainNet + pver := wire.ProtocolVersion + btcnet := wire.MainNet // Create a new getaddr bitcoin message. - msg := btcwire.NewMsgGetAddr() + msg := wire.NewMsgGetAddr() // Writes a bitcoin message msg to conn using the protocol version // pver, and the bitcoin network btcnet. The return is a possible // error. - err := btcwire.WriteMessage(conn, msg, pver, btcnet) + err := wire.WriteMessage(conn, msg, pver, btcnet) if err != nil { // Log and handle the error } @@ -126,5 +121,5 @@ signature perform the following: ## License -Package btcwire is licensed under the [copyfree](http://copyfree.org) ISC +Package wire is licensed under the [copyfree](http://copyfree.org) ISC License. diff --git a/bench_test.go b/wire/bench_test.go similarity index 99% rename from bench_test.go rename to wire/bench_test.go index 8b902ce6..3c0350ee 100644 --- a/bench_test.go +++ b/wire/bench_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "bytes" diff --git a/blockheader.go b/wire/blockheader.go similarity index 98% rename from blockheader.go rename to wire/blockheader.go index e3ad89df..8e3f79b0 100644 --- a/blockheader.go +++ b/wire/blockheader.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "bytes" diff --git a/blockheader_test.go b/wire/blockheader_test.go similarity index 84% rename from blockheader_test.go rename to wire/blockheader_test.go index 0c137663..c7ed3b80 100644 --- a/blockheader_test.go +++ b/wire/blockheader_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,13 +10,13 @@ import ( "testing" "time" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestBlockHeader tests the BlockHeader API. func TestBlockHeader(t *testing.T) { - nonce64, err := btcwire.RandomUint64() + nonce64, err := wire.RandomUint64() if err != nil { t.Errorf("RandomUint64: Error generating nonce: %v", err) } @@ -25,7 +25,7 @@ func TestBlockHeader(t *testing.T) { hash := mainNetGenesisHash merkleHash := mainNetGenesisMerkleRoot bits := uint32(0x1d00ffff) - bh := btcwire.NewBlockHeader(&hash, &merkleHash, bits, nonce) + bh := wire.NewBlockHeader(&hash, &merkleHash, bits, nonce) // Ensure we get the same data back out. if !bh.PrevBlock.IsEqual(&hash) { @@ -53,7 +53,7 @@ func TestBlockHeaderWire(t *testing.T) { // baseBlockHdr is used in the various tests as a baseline BlockHeader. bits := uint32(0x1d00ffff) - baseBlockHdr := &btcwire.BlockHeader{ + baseBlockHdr := &wire.BlockHeader{ Version: 1, PrevBlock: mainNetGenesisHash, MerkleRoot: mainNetGenesisMerkleRoot, @@ -79,17 +79,17 @@ func TestBlockHeaderWire(t *testing.T) { } tests := []struct { - in *btcwire.BlockHeader // Data to encode - out *btcwire.BlockHeader // Expected decoded data - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.BlockHeader // Data to encode + out *wire.BlockHeader // Expected decoded data + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { baseBlockHdr, baseBlockHdr, baseBlockHdrEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version. @@ -97,7 +97,7 @@ func TestBlockHeaderWire(t *testing.T) { baseBlockHdr, baseBlockHdr, baseBlockHdrEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version. @@ -105,7 +105,7 @@ func TestBlockHeaderWire(t *testing.T) { baseBlockHdr, baseBlockHdr, baseBlockHdrEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion. @@ -113,7 +113,7 @@ func TestBlockHeaderWire(t *testing.T) { baseBlockHdr, baseBlockHdr, baseBlockHdrEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion. @@ -121,7 +121,7 @@ func TestBlockHeaderWire(t *testing.T) { baseBlockHdr, baseBlockHdr, baseBlockHdrEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -129,7 +129,7 @@ func TestBlockHeaderWire(t *testing.T) { for i, test := range tests { // Encode to wire format. var buf bytes.Buffer - err := btcwire.TstWriteBlockHeader(&buf, test.pver, test.in) + err := wire.TstWriteBlockHeader(&buf, test.pver, test.in) if err != nil { t.Errorf("writeBlockHeader #%d error %v", i, err) continue @@ -141,9 +141,9 @@ func TestBlockHeaderWire(t *testing.T) { } // Decode the block header from wire format. - var bh btcwire.BlockHeader + var bh wire.BlockHeader rbuf := bytes.NewReader(test.buf) - err = btcwire.TstReadBlockHeader(rbuf, test.pver, &bh) + err = wire.TstReadBlockHeader(rbuf, test.pver, &bh) if err != nil { t.Errorf("readBlockHeader #%d error %v", i, err) continue @@ -162,7 +162,7 @@ func TestBlockHeaderSerialize(t *testing.T) { // baseBlockHdr is used in the various tests as a baseline BlockHeader. bits := uint32(0x1d00ffff) - baseBlockHdr := &btcwire.BlockHeader{ + baseBlockHdr := &wire.BlockHeader{ Version: 1, PrevBlock: mainNetGenesisHash, MerkleRoot: mainNetGenesisMerkleRoot, @@ -188,9 +188,9 @@ func TestBlockHeaderSerialize(t *testing.T) { } tests := []struct { - in *btcwire.BlockHeader // Data to encode - out *btcwire.BlockHeader // Expected decoded data - buf []byte // Serialized data + in *wire.BlockHeader // Data to encode + out *wire.BlockHeader // Expected decoded data + buf []byte // Serialized data }{ { baseBlockHdr, @@ -215,7 +215,7 @@ func TestBlockHeaderSerialize(t *testing.T) { } // Deserialize the block header. - var bh btcwire.BlockHeader + var bh wire.BlockHeader rbuf := bytes.NewReader(test.buf) err = bh.Deserialize(rbuf) if err != nil { diff --git a/common.go b/wire/common.go similarity index 99% rename from common.go rename to wire/common.go index a8bdd9dc..bf41d68e 100644 --- a/common.go +++ b/wire/common.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "crypto/rand" diff --git a/common_test.go b/wire/common_test.go similarity index 88% rename from common_test.go rename to wire/common_test.go index 0ad1f463..9bc810d6 100644 --- a/common_test.go +++ b/wire/common_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -12,13 +12,13 @@ import ( "strings" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "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 = btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. +var mainNetGenesisHash = wire.ShaHash([wire.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, @@ -27,7 +27,7 @@ var mainNetGenesisHash = btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet // mainNetGenesisMerkleRoot is the hash of the first transaction in the genesis // block for the main network. -var mainNetGenesisMerkleRoot = btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. +var mainNetGenesisMerkleRoot = wire.ShaHash([wire.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, @@ -84,7 +84,7 @@ func TestElementWire(t *testing.T) { []byte{0x01, 0x02, 0x03, 0x04}, }, { - [btcwire.CommandSize]byte{ + [wire.CommandSize]byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, }, @@ -104,7 +104,7 @@ func TestElementWire(t *testing.T) { }, }, { - (*btcwire.ShaHash)(&[btcwire.HashSize]byte{ // Make go vet happy. + (*wire.ShaHash)(&[wire.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, @@ -118,15 +118,15 @@ func TestElementWire(t *testing.T) { }, }, { - btcwire.ServiceFlag(btcwire.SFNodeNetwork), + wire.ServiceFlag(wire.SFNodeNetwork), []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, }, { - btcwire.InvType(btcwire.InvTypeTx), + wire.InvType(wire.InvTypeTx), []byte{0x01, 0x00, 0x00, 0x00}, }, { - btcwire.BitcoinNet(btcwire.MainNet), + wire.BitcoinNet(wire.MainNet), []byte{0xf9, 0xbe, 0xb4, 0xd9}, }, // Type not supported by the "fast" path and requires reflection. @@ -140,7 +140,7 @@ func TestElementWire(t *testing.T) { for i, test := range tests { // Write to wire format. var buf bytes.Buffer - err := btcwire.TstWriteElement(&buf, test.in) + err := wire.TstWriteElement(&buf, test.in) if err != nil { t.Errorf("writeElement #%d error %v", i, err) continue @@ -157,7 +157,7 @@ func TestElementWire(t *testing.T) { if reflect.ValueOf(test.in).Kind() != reflect.Ptr { val = reflect.New(reflect.TypeOf(test.in)).Interface() } - err = btcwire.TstReadElement(rbuf, val) + err = wire.TstReadElement(rbuf, val) if err != nil { t.Errorf("readElement #%d error %v", i, err) continue @@ -189,7 +189,7 @@ func TestElementWireErrors(t *testing.T) { {true, 0, io.ErrShortWrite, io.EOF}, {[4]byte{0x01, 0x02, 0x03, 0x04}, 0, io.ErrShortWrite, io.EOF}, { - [btcwire.CommandSize]byte{ + [wire.CommandSize]byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, }, @@ -203,7 +203,7 @@ func TestElementWireErrors(t *testing.T) { 0, io.ErrShortWrite, io.EOF, }, { - (*btcwire.ShaHash)(&[btcwire.HashSize]byte{ // Make go vet happy. + (*wire.ShaHash)(&[wire.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, @@ -211,16 +211,16 @@ func TestElementWireErrors(t *testing.T) { }), 0, io.ErrShortWrite, io.EOF, }, - {btcwire.ServiceFlag(btcwire.SFNodeNetwork), 0, io.ErrShortWrite, io.EOF}, - {btcwire.InvType(btcwire.InvTypeTx), 0, io.ErrShortWrite, io.EOF}, - {btcwire.BitcoinNet(btcwire.MainNet), 0, io.ErrShortWrite, io.EOF}, + {wire.ServiceFlag(wire.SFNodeNetwork), 0, io.ErrShortWrite, io.EOF}, + {wire.InvType(wire.InvTypeTx), 0, io.ErrShortWrite, io.EOF}, + {wire.BitcoinNet(wire.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 := btcwire.TstWriteElement(w, test.in) + err := wire.TstWriteElement(w, test.in) if err != test.writeErr { t.Errorf("writeElement #%d wrong error got: %v, want: %v", i, err, test.writeErr) @@ -233,7 +233,7 @@ func TestElementWireErrors(t *testing.T) { if reflect.ValueOf(test.in).Kind() != reflect.Ptr { val = reflect.New(reflect.TypeOf(test.in)).Interface() } - err = btcwire.TstReadElement(r, val) + err = wire.TstReadElement(r, val) if err != test.readErr { t.Errorf("readElement #%d wrong error got: %v, want: %v", i, err, test.readErr) @@ -244,7 +244,7 @@ func TestElementWireErrors(t *testing.T) { // TestVarIntWire tests wire encode and decode for variable length integers. func TestVarIntWire(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion tests := []struct { in uint64 // Value to encode @@ -283,7 +283,7 @@ func TestVarIntWire(t *testing.T) { for i, test := range tests { // Encode to wire format. var buf bytes.Buffer - err := btcwire.TstWriteVarInt(&buf, test.pver, test.in) + err := wire.TstWriteVarInt(&buf, test.pver, test.in) if err != nil { t.Errorf("writeVarInt #%d error %v", i, err) continue @@ -296,7 +296,7 @@ func TestVarIntWire(t *testing.T) { // Decode from wire format. rbuf := bytes.NewReader(test.buf) - val, err := btcwire.TstReadVarInt(rbuf, test.pver) + val, err := wire.TstReadVarInt(rbuf, test.pver) if err != nil { t.Errorf("readVarInt #%d error %v", i, err) continue @@ -312,7 +312,7 @@ func TestVarIntWire(t *testing.T) { // 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 := btcwire.ProtocolVersion + pver := wire.ProtocolVersion tests := []struct { in uint64 // Value to encode @@ -336,7 +336,7 @@ func TestVarIntWireErrors(t *testing.T) { for i, test := range tests { // Encode to wire format. w := newFixedWriter(test.max) - err := btcwire.TstWriteVarInt(w, test.pver, test.in) + err := wire.TstWriteVarInt(w, test.pver, test.in) if err != test.writeErr { t.Errorf("writeVarInt #%d wrong error got: %v, want: %v", i, err, test.writeErr) @@ -345,7 +345,7 @@ func TestVarIntWireErrors(t *testing.T) { // Decode from wire format. r := newFixedReader(test.max, test.buf) - _, err = btcwire.TstReadVarInt(r, test.pver) + _, err = wire.TstReadVarInt(r, test.pver) if err != test.readErr { t.Errorf("readVarInt #%d wrong error got: %v, want: %v", i, err, test.readErr) @@ -380,7 +380,7 @@ func TestVarIntSerializeSize(t *testing.T) { t.Logf("Running %d tests", len(tests)) for i, test := range tests { - serializedSize := btcwire.VarIntSerializeSize(test.val) + serializedSize := wire.VarIntSerializeSize(test.val) if serializedSize != test.size { t.Errorf("VarIntSerializeSize #%d got: %d, want: %d", i, serializedSize, test.size) @@ -391,7 +391,7 @@ func TestVarIntSerializeSize(t *testing.T) { // TestVarStringWire tests wire encode and decode for variable length strings. func TestVarStringWire(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // str256 is a string that takes a 2-byte varint to encode. str256 := strings.Repeat("test", 64) @@ -415,7 +415,7 @@ func TestVarStringWire(t *testing.T) { for i, test := range tests { // Encode to wire format. var buf bytes.Buffer - err := btcwire.TstWriteVarString(&buf, test.pver, test.in) + err := wire.TstWriteVarString(&buf, test.pver, test.in) if err != nil { t.Errorf("writeVarString #%d error %v", i, err) continue @@ -428,7 +428,7 @@ func TestVarStringWire(t *testing.T) { // Decode from wire format. rbuf := bytes.NewReader(test.buf) - val, err := btcwire.TstReadVarString(rbuf, test.pver) + val, err := wire.TstReadVarString(rbuf, test.pver) if err != nil { t.Errorf("readVarString #%d error %v", i, err) continue @@ -444,7 +444,7 @@ func TestVarStringWire(t *testing.T) { // 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 := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // str256 is a string that takes a 2-byte varint to encode. str256 := strings.Repeat("test", 64) @@ -470,7 +470,7 @@ func TestVarStringWireErrors(t *testing.T) { for i, test := range tests { // Encode to wire format. w := newFixedWriter(test.max) - err := btcwire.TstWriteVarString(w, test.pver, test.in) + err := wire.TstWriteVarString(w, test.pver, test.in) if err != test.writeErr { t.Errorf("writeVarString #%d wrong error got: %v, want: %v", i, err, test.writeErr) @@ -479,7 +479,7 @@ func TestVarStringWireErrors(t *testing.T) { // Decode from wire format. r := newFixedReader(test.max, test.buf) - _, err = btcwire.TstReadVarString(r, test.pver) + _, err = wire.TstReadVarString(r, test.pver) if err != test.readErr { t.Errorf("readVarString #%d wrong error got: %v, want: %v", i, err, test.readErr) @@ -493,7 +493,7 @@ func TestVarStringWireErrors(t *testing.T) { // length are handled properly. This could otherwise potentially be used as an // attack vector. func TestVarStringOverflowErrors(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion tests := []struct { buf []byte // Wire encoding @@ -501,16 +501,16 @@ func TestVarStringOverflowErrors(t *testing.T) { err error // Expected error }{ {[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - pver, &btcwire.MessageError{}}, + pver, &wire.MessageError{}}, {[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - pver, &btcwire.MessageError{}}, + pver, &wire.MessageError{}}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Decode from wire format. rbuf := bytes.NewReader(test.buf) - _, err := btcwire.TstReadVarString(rbuf, test.pver) + _, err := wire.TstReadVarString(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)) @@ -522,7 +522,7 @@ func TestVarStringOverflowErrors(t *testing.T) { // TestVarBytesWire tests wire encode and decode for variable length byte array. func TestVarBytesWire(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // bytes256 is a byte array that takes a 2-byte varint to encode. bytes256 := bytes.Repeat([]byte{0x01}, 256) @@ -545,7 +545,7 @@ func TestVarBytesWire(t *testing.T) { for i, test := range tests { // Encode to wire format. var buf bytes.Buffer - err := btcwire.TstWriteVarBytes(&buf, test.pver, test.in) + err := wire.TstWriteVarBytes(&buf, test.pver, test.in) if err != nil { t.Errorf("writeVarBytes #%d error %v", i, err) continue @@ -558,8 +558,8 @@ func TestVarBytesWire(t *testing.T) { // Decode from wire format. rbuf := bytes.NewReader(test.buf) - val, err := btcwire.TstReadVarBytes(rbuf, test.pver, - btcwire.MaxMessagePayload, "test payload") + val, err := wire.TstReadVarBytes(rbuf, test.pver, + wire.MaxMessagePayload, "test payload") if err != nil { t.Errorf("readVarBytes #%d error %v", i, err) continue @@ -575,7 +575,7 @@ func TestVarBytesWire(t *testing.T) { // 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 := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // bytes256 is a byte array that takes a 2-byte varint to encode. bytes256 := bytes.Repeat([]byte{0x01}, 256) @@ -601,7 +601,7 @@ func TestVarBytesWireErrors(t *testing.T) { for i, test := range tests { // Encode to wire format. w := newFixedWriter(test.max) - err := btcwire.TstWriteVarBytes(w, test.pver, test.in) + err := wire.TstWriteVarBytes(w, test.pver, test.in) if err != test.writeErr { t.Errorf("writeVarBytes #%d wrong error got: %v, want: %v", i, err, test.writeErr) @@ -610,8 +610,8 @@ func TestVarBytesWireErrors(t *testing.T) { // Decode from wire format. r := newFixedReader(test.max, test.buf) - _, err = btcwire.TstReadVarBytes(r, test.pver, - btcwire.MaxMessagePayload, "test payload") + _, err = wire.TstReadVarBytes(r, test.pver, + wire.MaxMessagePayload, "test payload") if err != test.readErr { t.Errorf("readVarBytes #%d wrong error got: %v, want: %v", i, err, test.readErr) @@ -625,7 +625,7 @@ func TestVarBytesWireErrors(t *testing.T) { // length are handled properly. This could otherwise potentially be used as an // attack vector. func TestVarBytesOverflowErrors(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion tests := []struct { buf []byte // Wire encoding @@ -633,17 +633,17 @@ func TestVarBytesOverflowErrors(t *testing.T) { err error // Expected error }{ {[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - pver, &btcwire.MessageError{}}, + pver, &wire.MessageError{}}, {[]byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - pver, &btcwire.MessageError{}}, + pver, &wire.MessageError{}}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Decode from wire format. rbuf := bytes.NewReader(test.buf) - _, err := btcwire.TstReadVarBytes(rbuf, test.pver, - btcwire.MaxMessagePayload, "test payload") + _, err := wire.TstReadVarBytes(rbuf, test.pver, + wire.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)) @@ -669,7 +669,7 @@ func TestRandomUint64(t *testing.T) { numHits := 0 for i := 0; i < tries; i++ { - nonce, err := btcwire.RandomUint64() + nonce, err := wire.RandomUint64() if err != nil { t.Errorf("RandomUint64 iteration %d failed - err %v", i, err) @@ -692,7 +692,7 @@ func TestRandomUint64(t *testing.T) { func TestRandomUint64Errors(t *testing.T) { // Test short reads. fr := &fakeRandReader{n: 2, err: io.EOF} - nonce, err := btcwire.TstRandomUint64(fr) + nonce, err := wire.TstRandomUint64(fr) if err != io.ErrUnexpectedEOF { t.Errorf("TestRandomUint64Fails: Error not expected value of %v [%v]", io.ErrShortBuffer, err) diff --git a/doc.go b/wire/doc.go similarity index 89% rename from doc.go rename to wire/doc.go index e97530a8..2e20ad78 100644 --- a/doc.go +++ b/wire/doc.go @@ -1,9 +1,9 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. /* -Package btcwire implements the bitcoin wire protocol. +Package wire implements the bitcoin wire protocol. For the complete details of the bitcoin protocol, see the official wiki entry at https://en.bitcoin.it/wiki/Protocol_specification. The following only serves @@ -72,7 +72,7 @@ Protocol Version The protocol version should be negotiated with the remote peer at a higher level than this package via the version (MsgVersion) message exchange, however, -this package provides the btcwire.ProtocolVersion constant which indicates the +this package provides the wire.ProtocolVersion constant which indicates the latest protocol version this package supports and is typically the value to use for all outbound connections before a potentially lower protocol version is negotiated. @@ -83,10 +83,10 @@ The bitcoin network is a magic number which is used to identify the start of a message and which bitcoin network the message applies to. This package provides the following constants: - btcwire.MainNet - btcwire.TestNet (Regression test network) - btcwire.TestNet3 (Test network version 3) - btcwire.SimNet (Simulation test network) + wire.MainNet + wire.TestNet (Regression test network) + wire.TestNet3 (Test network version 3) + wire.SimNet (Simulation test network) Determining Message Type @@ -98,10 +98,10 @@ switch or type assertion. An example of a type switch follows: // Assumes msg is already a valid concrete message such as one created // via NewMsgVersion or read via ReadMessage. switch msg := msg.(type) { - case *btcwire.MsgVersion: + case *wire.MsgVersion: // The message is a pointer to a MsgVersion struct. fmt.Printf("Protocol version: %v", msg.ProtocolVersion) - case *btcwire.MsgBlock: + case *wire.MsgBlock: // The message is a pointer to a MsgBlock struct. fmt.Printf("Number of tx in block: %v", msg.Header.TxnCount) } @@ -114,9 +114,9 @@ a remote node running a bitcoin peer. Example syntax is: // Reads and validates the next bitcoin message from conn using the // protocol version pver and the bitcoin network btcnet. The returns - // are a btcwire.Message, a []byte which contains the unmarshalled + // are a wire.Message, a []byte which contains the unmarshalled // raw payload, and a possible error. - msg, rawPayload, err := btcwire.ReadMessage(conn, pver, btcnet) + msg, rawPayload, err := wire.ReadMessage(conn, pver, btcnet) if err != nil { // Log and handle the error } @@ -129,12 +129,12 @@ a remote node running a bitcoin peer. Example syntax to request addresses from a remote peer is: // Create a new getaddr bitcoin message. - msg := btcwire.NewMsgGetAddr() + msg := wire.NewMsgGetAddr() // Writes a bitcoin message msg to conn using the protocol version // pver, and the bitcoin network btcnet. The return is a possible // error. - err := btcwire.WriteMessage(conn, msg, pver, btcnet) + err := wire.WriteMessage(conn, msg, pver, btcnet) if err != nil { // Log and handle the error } @@ -143,7 +143,7 @@ Errors Errors returned by this package are either the raw errors provided by underlying calls to read/write from streams such as io.EOF, io.ErrUnexpectedEOF, and -io.ErrShortWrite, or of type btcwire.MessageError. This allows the caller to +io.ErrShortWrite, or of type wire.MessageError. This allows the caller to differentiate between general IO errors and malformed messages through type assertions. @@ -156,4 +156,4 @@ This package includes spec changes outlined by the following BIPs: BIP0035 (https://en.bitcoin.it/wiki/BIP_0035) BIP0037 (https://en.bitcoin.it/wiki/BIP_0037) */ -package btcwire +package wire diff --git a/error.go b/wire/error.go similarity index 94% rename from error.go rename to wire/error.go index 43282a47..99a194a4 100644 --- a/error.go +++ b/wire/error.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/fakeconn_test.go b/wire/fakeconn_test.go similarity index 95% rename from fakeconn_test.go rename to wire/fakeconn_test.go index 51b7d03d..a28b2996 100644 --- a/fakeconn_test.go +++ b/wire/fakeconn_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "net" diff --git a/fakemessage_test.go b/wire/fakemessage_test.go similarity index 75% rename from fakemessage_test.go rename to wire/fakemessage_test.go index 74844527..f64e4f83 100644 --- a/fakemessage_test.go +++ b/wire/fakemessage_test.go @@ -1,16 +1,16 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "io" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" ) -// fakeMessage implements the btcwire.Message interface and is used to force +// fakeMessage implements the wire.Message interface and is used to force // encode errors in messages. type fakeMessage struct { command string @@ -19,7 +19,7 @@ type fakeMessage struct { forceLenErr bool } -// BtcDecode doesn't do anything. It just satisfies the btcwire.Message +// BtcDecode doesn't do anything. It just satisfies the wire.Message // interface. func (msg *fakeMessage) BtcDecode(r io.Reader, pver uint32) error { return nil @@ -27,10 +27,10 @@ func (msg *fakeMessage) BtcDecode(r io.Reader, pver uint32) error { // BtcEncode writes the payload field of the fake message or forces an error // if the forceEncodeErr flag of the fake message is set. It also satisfies the -// btcwire.Message interface. +// wire.Message interface. func (msg *fakeMessage) BtcEncode(w io.Writer, pver uint32) error { if msg.forceEncodeErr { - err := &btcwire.MessageError{ + err := &wire.MessageError{ Func: "fakeMessage.BtcEncode", Description: "intentional error", } @@ -42,14 +42,14 @@ func (msg *fakeMessage) BtcEncode(w io.Writer, pver uint32) error { } // Command returns the command field of the fake message and satisfies the -// btcwire.Message interface. +// wire.Message interface. func (msg *fakeMessage) Command() string { return msg.command } // MaxPayloadLength returns the length of the payload field of fake message // or a smaller value if the forceLenErr flag of the fake message is set. It -// satisfies the btcwire.Message interface. +// satisfies the wire.Message interface. func (msg *fakeMessage) MaxPayloadLength(pver uint32) uint32 { lenp := uint32(len(msg.payload)) if msg.forceLenErr { diff --git a/fixedIO_test.go b/wire/fixedIO_test.go similarity index 96% rename from fixedIO_test.go rename to wire/fixedIO_test.go index 3bb834bb..806790a2 100644 --- a/fixedIO_test.go +++ b/wire/fixedIO_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" diff --git a/internal_test.go b/wire/internal_test.go similarity index 91% rename from internal_test.go rename to wire/internal_test.go index cb8ca9ee..9b7b0e3c 100644 --- a/internal_test.go +++ b/wire/internal_test.go @@ -1,15 +1,15 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. /* -This test file is part of the btcwire package rather than than the -btcwire_test package so it can bridge access to the internals to properly test -cases which are either not possible or can't reliably be tested via the public -interface. The functions are only exported while the tests are being run. +This test file is part of the wire package rather than than the wire_test +package so it can bridge access to the internals to properly test cases which +are either not possible or can't reliably be tested via the public interface. +The functions are only exported while the tests are being run. */ -package btcwire +package wire import ( "io" diff --git a/invvect.go b/wire/invvect.go similarity index 96% rename from invvect.go rename to wire/invvect.go index e9b74dcb..7df74dac 100644 --- a/invvect.go +++ b/wire/invvect.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/invvect_test.go b/wire/invvect_test.go similarity index 78% rename from invvect_test.go rename to wire/invvect_test.go index a467a3bd..3982390b 100644 --- a/invvect_test.go +++ b/wire/invvect_test.go @@ -1,27 +1,27 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestInvVectStringer tests the stringized output for inventory vector types. func TestInvTypeStringer(t *testing.T) { tests := []struct { - in btcwire.InvType + in wire.InvType want string }{ - {btcwire.InvTypeError, "ERROR"}, - {btcwire.InvTypeTx, "MSG_TX"}, - {btcwire.InvTypeBlock, "MSG_BLOCK"}, + {wire.InvTypeError, "ERROR"}, + {wire.InvTypeTx, "MSG_TX"}, + {wire.InvTypeBlock, "MSG_BLOCK"}, {0xffffffff, "Unknown InvType (4294967295)"}, } @@ -39,11 +39,11 @@ func TestInvTypeStringer(t *testing.T) { // TestInvVect tests the InvVect API. func TestInvVect(t *testing.T) { - ivType := btcwire.InvTypeBlock - hash := btcwire.ShaHash{} + ivType := wire.InvTypeBlock + hash := wire.ShaHash{} // Ensure we get the same payload and signature back out. - iv := btcwire.NewInvVect(ivType, &hash) + iv := wire.NewInvVect(ivType, &hash) if iv.Type != ivType { t.Errorf("NewInvVect: wrong type - got %v, want %v", iv.Type, ivType) @@ -60,15 +60,15 @@ func TestInvVect(t *testing.T) { func TestInvVectWire(t *testing.T) { // Block 203707 hash. hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" - baseHash, err := btcwire.NewShaHashFromStr(hashStr) + baseHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // errInvVect is an inventory vector with an error. - errInvVect := btcwire.InvVect{ - Type: btcwire.InvTypeError, - Hash: btcwire.ShaHash{}, + errInvVect := wire.InvVect{ + Type: wire.InvTypeError, + Hash: wire.ShaHash{}, } // errInvVectEncoded is the wire encoded bytes of errInvVect. @@ -81,8 +81,8 @@ func TestInvVectWire(t *testing.T) { } // txInvVect is an inventory vector representing a transaction. - txInvVect := btcwire.InvVect{ - Type: btcwire.InvTypeTx, + txInvVect := wire.InvVect{ + Type: wire.InvTypeTx, Hash: *baseHash, } @@ -96,8 +96,8 @@ func TestInvVectWire(t *testing.T) { } // blockInvVect is an inventory vector representing a block. - blockInvVect := btcwire.InvVect{ - Type: btcwire.InvTypeBlock, + blockInvVect := wire.InvVect{ + Type: wire.InvTypeBlock, Hash: *baseHash, } @@ -111,17 +111,17 @@ func TestInvVectWire(t *testing.T) { } tests := []struct { - in btcwire.InvVect // NetAddress to encode - out btcwire.InvVect // Expected decoded NetAddress - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in wire.InvVect // NetAddress to encode + out wire.InvVect // Expected decoded NetAddress + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version error inventory vector. { errInvVect, errInvVect, errInvVectEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version tx inventory vector. @@ -129,7 +129,7 @@ func TestInvVectWire(t *testing.T) { txInvVect, txInvVect, txInvVectEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version block inventory vector. @@ -137,7 +137,7 @@ func TestInvVectWire(t *testing.T) { blockInvVect, blockInvVect, blockInvVectEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version error inventory vector. @@ -145,7 +145,7 @@ func TestInvVectWire(t *testing.T) { errInvVect, errInvVect, errInvVectEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0035Version tx inventory vector. @@ -153,7 +153,7 @@ func TestInvVectWire(t *testing.T) { txInvVect, txInvVect, txInvVectEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0035Version block inventory vector. @@ -161,7 +161,7 @@ func TestInvVectWire(t *testing.T) { blockInvVect, blockInvVect, blockInvVectEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version error inventory vector. @@ -169,7 +169,7 @@ func TestInvVectWire(t *testing.T) { errInvVect, errInvVect, errInvVectEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version BIP0031Version tx inventory vector. @@ -177,7 +177,7 @@ func TestInvVectWire(t *testing.T) { txInvVect, txInvVect, txInvVectEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version BIP0031Version block inventory vector. @@ -185,7 +185,7 @@ func TestInvVectWire(t *testing.T) { blockInvVect, blockInvVect, blockInvVectEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion error inventory vector. @@ -193,7 +193,7 @@ func TestInvVectWire(t *testing.T) { errInvVect, errInvVect, errInvVectEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion tx inventory vector. @@ -201,7 +201,7 @@ func TestInvVectWire(t *testing.T) { txInvVect, txInvVect, txInvVectEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion block inventory vector. @@ -209,7 +209,7 @@ func TestInvVectWire(t *testing.T) { blockInvVect, blockInvVect, blockInvVectEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion error inventory vector. @@ -217,7 +217,7 @@ func TestInvVectWire(t *testing.T) { errInvVect, errInvVect, errInvVectEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion tx inventory vector. @@ -225,7 +225,7 @@ func TestInvVectWire(t *testing.T) { txInvVect, txInvVect, txInvVectEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion block inventory vector. @@ -233,7 +233,7 @@ func TestInvVectWire(t *testing.T) { blockInvVect, blockInvVect, blockInvVectEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -241,7 +241,7 @@ func TestInvVectWire(t *testing.T) { for i, test := range tests { // Encode to wire format. var buf bytes.Buffer - err := btcwire.TstWriteInvVect(&buf, test.pver, &test.in) + err := wire.TstWriteInvVect(&buf, test.pver, &test.in) if err != nil { t.Errorf("writeInvVect #%d error %v", i, err) continue @@ -253,9 +253,9 @@ func TestInvVectWire(t *testing.T) { } // Decode the message from wire format. - var iv btcwire.InvVect + var iv wire.InvVect rbuf := bytes.NewReader(test.buf) - err = btcwire.TstReadInvVect(rbuf, test.pver, &iv) + err = wire.TstReadInvVect(rbuf, test.pver, &iv) if err != nil { t.Errorf("readInvVect #%d error %v", i, err) continue diff --git a/message.go b/wire/message.go similarity index 99% rename from message.go rename to wire/message.go index 1e2b7d3d..f9d03375 100644 --- a/message.go +++ b/wire/message.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "bytes" diff --git a/message_test.go b/wire/message_test.go similarity index 65% rename from message_test.go rename to wire/message_test.go index 9eaaafab..8bb24c1b 100644 --- a/message_test.go +++ b/wire/message_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -13,13 +13,13 @@ import ( "testing" "time" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // makeHeader is a convenience function to make a message header in the form of // a byte slice. It is used to force errors when reading messages. -func makeHeader(btcnet btcwire.BitcoinNet, command string, +func makeHeader(btcnet wire.BitcoinNet, command string, payloadLen uint32, checksum uint32) []byte { // The length of a bitcoin message header is 24 bytes. @@ -35,82 +35,82 @@ func makeHeader(btcnet btcwire.BitcoinNet, command string, // TestMessage tests the Read/WriteMessage and Read/WriteMessageN API. func TestMessage(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Create the various types of messages to test. // MsgVersion. addrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333} - you, err := btcwire.NewNetAddress(addrYou, btcwire.SFNodeNetwork) + you, err := wire.NewNetAddress(addrYou, wire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } you.Timestamp = time.Time{} // Version message has zero value timestamp. addrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} - me, err := btcwire.NewNetAddress(addrMe, btcwire.SFNodeNetwork) + me, err := wire.NewNetAddress(addrMe, wire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } me.Timestamp = time.Time{} // Version message has zero value timestamp. - msgVersion := btcwire.NewMsgVersion(me, you, 123123, 0) + msgVersion := wire.NewMsgVersion(me, you, 123123, 0) - msgVerack := btcwire.NewMsgVerAck() - msgGetAddr := btcwire.NewMsgGetAddr() - msgAddr := btcwire.NewMsgAddr() - msgGetBlocks := btcwire.NewMsgGetBlocks(&btcwire.ShaHash{}) + msgVerack := wire.NewMsgVerAck() + msgGetAddr := wire.NewMsgGetAddr() + msgAddr := wire.NewMsgAddr() + msgGetBlocks := wire.NewMsgGetBlocks(&wire.ShaHash{}) msgBlock := &blockOne - msgInv := btcwire.NewMsgInv() - msgGetData := btcwire.NewMsgGetData() - msgNotFound := btcwire.NewMsgNotFound() - msgTx := btcwire.NewMsgTx() - msgPing := btcwire.NewMsgPing(123123) - msgPong := btcwire.NewMsgPong(123123) - msgGetHeaders := btcwire.NewMsgGetHeaders() - msgHeaders := btcwire.NewMsgHeaders() - msgAlert := btcwire.NewMsgAlert([]byte("payload"), []byte("signature")) - msgMemPool := btcwire.NewMsgMemPool() - msgFilterAdd := btcwire.NewMsgFilterAdd([]byte{0x01}) - msgFilterClear := btcwire.NewMsgFilterClear() - msgFilterLoad := btcwire.NewMsgFilterLoad([]byte{0x01}, 10, 0, btcwire.BloomUpdateNone) - bh := btcwire.NewBlockHeader(&btcwire.ShaHash{}, &btcwire.ShaHash{}, 0, 0) - msgMerkleBlock := btcwire.NewMsgMerkleBlock(bh) - msgReject := btcwire.NewMsgReject("block", btcwire.RejectDuplicate, "duplicate block") + msgInv := wire.NewMsgInv() + msgGetData := wire.NewMsgGetData() + msgNotFound := wire.NewMsgNotFound() + msgTx := wire.NewMsgTx() + msgPing := wire.NewMsgPing(123123) + msgPong := wire.NewMsgPong(123123) + msgGetHeaders := wire.NewMsgGetHeaders() + msgHeaders := wire.NewMsgHeaders() + msgAlert := wire.NewMsgAlert([]byte("payload"), []byte("signature")) + msgMemPool := wire.NewMsgMemPool() + msgFilterAdd := wire.NewMsgFilterAdd([]byte{0x01}) + msgFilterClear := wire.NewMsgFilterClear() + msgFilterLoad := wire.NewMsgFilterLoad([]byte{0x01}, 10, 0, wire.BloomUpdateNone) + bh := wire.NewBlockHeader(&wire.ShaHash{}, &wire.ShaHash{}, 0, 0) + msgMerkleBlock := wire.NewMsgMerkleBlock(bh) + msgReject := wire.NewMsgReject("block", wire.RejectDuplicate, "duplicate block") tests := []struct { - in btcwire.Message // Value to encode - out btcwire.Message // Expected decoded value - pver uint32 // Protocol version for wire encoding - btcnet btcwire.BitcoinNet // Network to use for wire encoding - bytes int // Expected num bytes read/written + in wire.Message // Value to encode + out wire.Message // Expected decoded value + pver uint32 // Protocol version for wire encoding + btcnet wire.BitcoinNet // Network to use for wire encoding + bytes int // Expected num bytes read/written }{ - {msgVersion, msgVersion, pver, btcwire.MainNet, 125}, - {msgVerack, msgVerack, pver, btcwire.MainNet, 24}, - {msgGetAddr, msgGetAddr, pver, btcwire.MainNet, 24}, - {msgAddr, msgAddr, pver, btcwire.MainNet, 25}, - {msgGetBlocks, msgGetBlocks, pver, btcwire.MainNet, 61}, - {msgBlock, msgBlock, pver, btcwire.MainNet, 239}, - {msgInv, msgInv, pver, btcwire.MainNet, 25}, - {msgGetData, msgGetData, pver, btcwire.MainNet, 25}, - {msgNotFound, msgNotFound, pver, btcwire.MainNet, 25}, - {msgTx, msgTx, pver, btcwire.MainNet, 34}, - {msgPing, msgPing, pver, btcwire.MainNet, 32}, - {msgPong, msgPong, pver, btcwire.MainNet, 32}, - {msgGetHeaders, msgGetHeaders, pver, btcwire.MainNet, 61}, - {msgHeaders, msgHeaders, pver, btcwire.MainNet, 25}, - {msgAlert, msgAlert, pver, btcwire.MainNet, 42}, - {msgMemPool, msgMemPool, pver, btcwire.MainNet, 24}, - {msgFilterAdd, msgFilterAdd, pver, btcwire.MainNet, 26}, - {msgFilterClear, msgFilterClear, pver, btcwire.MainNet, 24}, - {msgFilterLoad, msgFilterLoad, pver, btcwire.MainNet, 35}, - {msgMerkleBlock, msgMerkleBlock, pver, btcwire.MainNet, 110}, - {msgReject, msgReject, pver, btcwire.MainNet, 79}, + {msgVersion, msgVersion, pver, wire.MainNet, 125}, + {msgVerack, msgVerack, pver, wire.MainNet, 24}, + {msgGetAddr, msgGetAddr, pver, wire.MainNet, 24}, + {msgAddr, msgAddr, pver, wire.MainNet, 25}, + {msgGetBlocks, msgGetBlocks, pver, wire.MainNet, 61}, + {msgBlock, msgBlock, pver, wire.MainNet, 239}, + {msgInv, msgInv, pver, wire.MainNet, 25}, + {msgGetData, msgGetData, pver, wire.MainNet, 25}, + {msgNotFound, msgNotFound, pver, wire.MainNet, 25}, + {msgTx, msgTx, pver, wire.MainNet, 34}, + {msgPing, msgPing, pver, wire.MainNet, 32}, + {msgPong, msgPong, pver, wire.MainNet, 32}, + {msgGetHeaders, msgGetHeaders, pver, wire.MainNet, 61}, + {msgHeaders, msgHeaders, pver, wire.MainNet, 25}, + {msgAlert, msgAlert, pver, wire.MainNet, 42}, + {msgMemPool, msgMemPool, pver, wire.MainNet, 24}, + {msgFilterAdd, msgFilterAdd, pver, wire.MainNet, 26}, + {msgFilterClear, msgFilterClear, pver, wire.MainNet, 24}, + {msgFilterLoad, msgFilterLoad, pver, wire.MainNet, 35}, + {msgMerkleBlock, msgMerkleBlock, pver, wire.MainNet, 110}, + {msgReject, msgReject, pver, wire.MainNet, 79}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Encode to wire format. var buf bytes.Buffer - nw, err := btcwire.WriteMessageN(&buf, test.in, test.pver, test.btcnet) + nw, err := wire.WriteMessageN(&buf, test.in, test.pver, test.btcnet) if err != nil { t.Errorf("WriteMessage #%d error %v", i, err) continue @@ -124,7 +124,7 @@ func TestMessage(t *testing.T) { // Decode from wire format. rbuf := bytes.NewReader(buf.Bytes()) - nr, msg, _, err := btcwire.ReadMessageN(rbuf, test.pver, test.btcnet) + nr, msg, _, err := wire.ReadMessageN(rbuf, test.pver, test.btcnet) if err != nil { t.Errorf("ReadMessage #%d error %v, msg %v", i, err, spew.Sdump(msg)) @@ -149,7 +149,7 @@ func TestMessage(t *testing.T) { for i, test := range tests { // Encode to wire format. var buf bytes.Buffer - err := btcwire.WriteMessage(&buf, test.in, test.pver, test.btcnet) + err := wire.WriteMessage(&buf, test.in, test.pver, test.btcnet) if err != nil { t.Errorf("WriteMessage #%d error %v", i, err) continue @@ -157,7 +157,7 @@ func TestMessage(t *testing.T) { // Decode from wire format. rbuf := bytes.NewReader(buf.Bytes()) - msg, _, err := btcwire.ReadMessage(rbuf, test.pver, test.btcnet) + msg, _, err := wire.ReadMessage(rbuf, test.pver, test.btcnet) if err != nil { t.Errorf("ReadMessage #%d error %v, msg %v", i, err, spew.Sdump(msg)) @@ -174,12 +174,12 @@ func TestMessage(t *testing.T) { // TestReadMessageWireErrors performs negative tests against wire decoding into // concrete messages to confirm error paths work correctly. func TestReadMessageWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - btcnet := btcwire.MainNet + pver := wire.ProtocolVersion + btcnet := wire.MainNet // Ensure message errors are as expected with no function specified. wantErr := "something bad happened" - testErr := btcwire.MessageError{Description: wantErr} + testErr := wire.MessageError{Description: wantErr} if testErr.Error() != wantErr { t.Errorf("MessageError: wrong error - got %v, want %v", testErr.Error(), wantErr) @@ -187,18 +187,18 @@ func TestReadMessageWireErrors(t *testing.T) { // Ensure message errors are as expected with a function specified. wantFunc := "foo" - testErr = btcwire.MessageError{Func: wantFunc, Description: wantErr} + testErr = wire.MessageError{Func: wantFunc, Description: wantErr} if testErr.Error() != wantFunc+": "+wantErr { t.Errorf("MessageError: wrong error - got %v, want %v", testErr.Error(), wantErr) } // Wire encoded bytes for main and testnet3 networks magic identifiers. - testNet3Bytes := makeHeader(btcwire.TestNet3, "", 0, 0) + testNet3Bytes := makeHeader(wire.TestNet3, "", 0, 0) // Wire encoded bytes for a message that exceeds max overall message // length. - mpl := uint32(btcwire.MaxMessagePayload) + mpl := uint32(wire.MaxMessagePayload) exceedMaxPayloadBytes := makeHeader(btcnet, "getaddr", mpl+1, 0) // Wire encoded bytes for a command which is invalid utf-8. @@ -233,12 +233,12 @@ func TestReadMessageWireErrors(t *testing.T) { discardBytes := makeHeader(btcnet, "bogus", 15*1024, 0) tests := []struct { - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding - btcnet btcwire.BitcoinNet // Bitcoin network for wire encoding - max int // Max size of fixed buffer to induce errors - readErr error // Expected read error - bytes int // Expected num bytes read + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + btcnet wire.BitcoinNet // Bitcoin network for wire encoding + max int // Max size of fixed buffer to induce errors + readErr error // Expected read error + bytes int // Expected num bytes read }{ // Latest protocol version with intentional read errors. @@ -258,7 +258,7 @@ func TestReadMessageWireErrors(t *testing.T) { pver, btcnet, len(testNet3Bytes), - &btcwire.MessageError{}, + &wire.MessageError{}, 24, }, @@ -268,7 +268,7 @@ func TestReadMessageWireErrors(t *testing.T) { pver, btcnet, len(exceedMaxPayloadBytes), - &btcwire.MessageError{}, + &wire.MessageError{}, 24, }, @@ -278,7 +278,7 @@ func TestReadMessageWireErrors(t *testing.T) { pver, btcnet, len(badCommandBytes), - &btcwire.MessageError{}, + &wire.MessageError{}, 24, }, @@ -288,7 +288,7 @@ func TestReadMessageWireErrors(t *testing.T) { pver, btcnet, len(unsupportedCommandBytes), - &btcwire.MessageError{}, + &wire.MessageError{}, 24, }, @@ -298,7 +298,7 @@ func TestReadMessageWireErrors(t *testing.T) { pver, btcnet, len(exceedTypePayloadBytes), - &btcwire.MessageError{}, + &wire.MessageError{}, 24, }, @@ -318,7 +318,7 @@ func TestReadMessageWireErrors(t *testing.T) { pver, btcnet, len(badChecksumBytes), - &btcwire.MessageError{}, + &wire.MessageError{}, 26, }, @@ -338,7 +338,7 @@ func TestReadMessageWireErrors(t *testing.T) { pver, btcnet, len(discardBytes), - &btcwire.MessageError{}, + &wire.MessageError{}, 24, }, } @@ -347,7 +347,7 @@ func TestReadMessageWireErrors(t *testing.T) { for i, test := range tests { // Decode from wire format. r := newFixedReader(test.max, test.buf) - nr, _, _, err := btcwire.ReadMessageN(r, test.pver, test.btcnet) + nr, _, _, err := wire.ReadMessageN(r, test.pver, test.btcnet) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { t.Errorf("ReadMessage #%d wrong error got: %v <%T>, "+ "want: %T", i, err, err, test.readErr) @@ -360,9 +360,9 @@ func TestReadMessageWireErrors(t *testing.T) { "got %d, want %d", i, nr, test.bytes) } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("ReadMessage #%d wrong error got: %v <%T>, "+ "want: %v <%T>", i, err, err, @@ -376,9 +376,9 @@ func TestReadMessageWireErrors(t *testing.T) { // TestWriteMessageWireErrors performs negative tests against wire encoding from // concrete messages to confirm error paths work correctly. func TestWriteMessageWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - btcnet := btcwire.MainNet - btcwireErr := &btcwire.MessageError{} + pver := wire.ProtocolVersion + btcnet := wire.MainNet + wireErr := &wire.MessageError{} // Fake message with a command that is too long. badCommandMsg := &fakeMessage{command: "somethingtoolong"} @@ -387,7 +387,7 @@ func TestWriteMessageWireErrors(t *testing.T) { encodeErrMsg := &fakeMessage{forceEncodeErr: true} // Fake message that has payload which exceeds max overall message size. - exceedOverallPayload := make([]byte, btcwire.MaxMessagePayload+1) + exceedOverallPayload := make([]byte, wire.MaxMessagePayload+1) exceedOverallPayloadErrMsg := &fakeMessage{payload: exceedOverallPayload} // Fake message that has payload which exceeds max allowed per message. @@ -400,21 +400,21 @@ func TestWriteMessageWireErrors(t *testing.T) { bogusMsg := &fakeMessage{command: "bogus", payload: bogusPayload} tests := []struct { - msg btcwire.Message // Message to encode - pver uint32 // Protocol version for wire encoding - btcnet btcwire.BitcoinNet // Bitcoin network for wire encoding - max int // Max size of fixed buffer to induce errors - err error // Expected error - bytes int // Expected num bytes written + msg wire.Message // Message to encode + pver uint32 // Protocol version for wire encoding + btcnet wire.BitcoinNet // Bitcoin network for wire encoding + max int // Max size of fixed buffer to induce errors + err error // Expected error + bytes int // Expected num bytes written }{ // Command too long. - {badCommandMsg, pver, btcnet, 0, btcwireErr, 0}, + {badCommandMsg, pver, btcnet, 0, wireErr, 0}, // Force error in payload encode. - {encodeErrMsg, pver, btcnet, 0, btcwireErr, 0}, + {encodeErrMsg, pver, btcnet, 0, wireErr, 0}, // Force error due to exceeding max overall message payload size. - {exceedOverallPayloadErrMsg, pver, btcnet, 0, btcwireErr, 0}, + {exceedOverallPayloadErrMsg, pver, btcnet, 0, wireErr, 0}, // Force error due to exceeding max payload for message type. - {exceedPayloadErrMsg, pver, btcnet, 0, btcwireErr, 0}, + {exceedPayloadErrMsg, pver, btcnet, 0, wireErr, 0}, // Force error in header write. {bogusMsg, pver, btcnet, 0, io.ErrShortWrite, 0}, // Force error in payload write. @@ -425,7 +425,7 @@ func TestWriteMessageWireErrors(t *testing.T) { for i, test := range tests { // Encode wire format. w := newFixedWriter(test.max) - nw, err := btcwire.WriteMessageN(w, test.msg, test.pver, test.btcnet) + nw, err := wire.WriteMessageN(w, test.msg, test.pver, test.btcnet) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("WriteMessage #%d wrong error got: %v <%T>, "+ "want: %T", i, err, err, test.err) @@ -438,9 +438,9 @@ func TestWriteMessageWireErrors(t *testing.T) { "written - got %d, want %d", i, nw, test.bytes) } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.err { t.Errorf("ReadMessage #%d wrong error got: %v <%T>, "+ "want: %v <%T>", i, err, err, diff --git a/msgaddr.go b/wire/msgaddr.go similarity index 98% rename from msgaddr.go rename to wire/msgaddr.go index b1767620..f0faedcd 100644 --- a/msgaddr.go +++ b/wire/msgaddr.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msgaddr_test.go b/wire/msgaddr_test.go similarity index 80% rename from msgaddr_test.go rename to wire/msgaddr_test.go index 30d735e0..fae1ad41 100644 --- a/msgaddr_test.go +++ b/wire/msgaddr_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -12,17 +12,17 @@ import ( "testing" "time" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestAddr tests the MsgAddr API. func TestAddr(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Ensure the command is expected value. wantCmd := "addr" - msg := btcwire.NewMsgAddr() + msg := wire.NewMsgAddr() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgAddr: wrong command - got %v want %v", cmd, wantCmd) @@ -40,7 +40,7 @@ func TestAddr(t *testing.T) { // Ensure NetAddresses are added properly. tcpAddr := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} - na, err := btcwire.NewNetAddress(tcpAddr, btcwire.SFNodeNetwork) + na, err := wire.NewNetAddress(tcpAddr, wire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } @@ -63,7 +63,7 @@ func TestAddr(t *testing.T) { // Ensure adding more than the max allowed addresses per message returns // error. - for i := 0; i < btcwire.MaxAddrPerMsg+1; i++ { + for i := 0; i < wire.MaxAddrPerMsg+1; i++ { err = msg.AddAddress(na) } if err == nil { @@ -79,7 +79,7 @@ func TestAddr(t *testing.T) { // Ensure max payload is expected value for protocol versions before // timestamp was added to NetAddress. // Num addresses (varInt) + max allowed addresses. - pver = btcwire.NetAddressTimeVersion - 1 + pver = wire.NetAddressTimeVersion - 1 wantPayload = uint32(26009) maxPayload = msg.MaxPayloadLength(pver) if maxPayload != wantPayload { @@ -91,7 +91,7 @@ func TestAddr(t *testing.T) { // Ensure max payload is expected value for protocol versions before // multiple addresses were allowed. // Num addresses (varInt) + a single net addresses. - pver = btcwire.MultipleAddressVersion - 1 + pver = wire.MultipleAddressVersion - 1 wantPayload = uint32(35) maxPayload = msg.MaxPayloadLength(pver) if maxPayload != wantPayload { @@ -107,27 +107,27 @@ func TestAddr(t *testing.T) { // of addreses and protocol versions. func TestAddrWire(t *testing.T) { // A couple of NetAddresses to use for testing. - na := &btcwire.NetAddress{ + na := &wire.NetAddress{ Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("127.0.0.1"), Port: 8333, } - na2 := &btcwire.NetAddress{ + na2 := &wire.NetAddress{ Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("192.168.0.1"), Port: 8334, } // Empty address message. - noAddr := btcwire.NewMsgAddr() + noAddr := wire.NewMsgAddr() noAddrEncoded := []byte{ 0x00, // Varint for number of addresses } // Address message with multiple addresses. - multiAddr := btcwire.NewMsgAddr() + multiAddr := wire.NewMsgAddr() multiAddr.AddAddresses(na, na2) multiAddrEncoded := []byte{ 0x02, // Varint for number of addresses @@ -145,17 +145,17 @@ func TestAddrWire(t *testing.T) { } tests := []struct { - in *btcwire.MsgAddr // Message to encode - out *btcwire.MsgAddr // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgAddr // Message to encode + out *wire.MsgAddr // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version with no addresses. { noAddr, noAddr, noAddrEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version with multiple addresses. @@ -163,7 +163,7 @@ func TestAddrWire(t *testing.T) { multiAddr, multiAddr, multiAddrEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version MultipleAddressVersion-1 with no addresses. @@ -171,7 +171,7 @@ func TestAddrWire(t *testing.T) { noAddr, noAddr, noAddrEncoded, - btcwire.MultipleAddressVersion - 1, + wire.MultipleAddressVersion - 1, }, } @@ -191,7 +191,7 @@ func TestAddrWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgAddr + var msg wire.MsgAddr rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -209,26 +209,26 @@ func TestAddrWire(t *testing.T) { // TestAddrWireErrors performs negative tests against wire encode and decode // of MsgAddr to confirm error paths work correctly. func TestAddrWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - pverMA := btcwire.MultipleAddressVersion - btcwireErr := &btcwire.MessageError{} + pver := wire.ProtocolVersion + pverMA := wire.MultipleAddressVersion + wireErr := &wire.MessageError{} // A couple of NetAddresses to use for testing. - na := &btcwire.NetAddress{ + na := &wire.NetAddress{ Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("127.0.0.1"), Port: 8333, } - na2 := &btcwire.NetAddress{ + na2 := &wire.NetAddress{ Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("192.168.0.1"), Port: 8334, } // Address message with multiple addresses. - baseAddr := btcwire.NewMsgAddr() + baseAddr := wire.NewMsgAddr() baseAddr.AddAddresses(na, na2) baseAddrEncoded := []byte{ 0x02, // Varint for number of addresses @@ -247,8 +247,8 @@ func TestAddrWireErrors(t *testing.T) { // Message that forces an error by having more than the max allowed // addresses. - maxAddr := btcwire.NewMsgAddr() - for i := 0; i < btcwire.MaxAddrPerMsg; i++ { + maxAddr := wire.NewMsgAddr() + for i := 0; i < wire.MaxAddrPerMsg; i++ { maxAddr.AddAddress(na) } maxAddr.AddrList = append(maxAddr.AddrList, na) @@ -257,12 +257,12 @@ func TestAddrWireErrors(t *testing.T) { } tests := []struct { - in *btcwire.MsgAddr // 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 + in *wire.MsgAddr // 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 error in addresses count @@ -270,10 +270,10 @@ func TestAddrWireErrors(t *testing.T) { // Force error in address list. {baseAddr, baseAddrEncoded, pver, 1, io.ErrShortWrite, io.EOF}, // Force error with greater than max inventory vectors. - {maxAddr, maxAddrEncoded, pver, 3, btcwireErr, btcwireErr}, + {maxAddr, maxAddrEncoded, pver, 3, wireErr, wireErr}, // Force error with greater than max inventory vectors for // protocol versions before multiple addresses were allowed. - {maxAddr, maxAddrEncoded, pverMA - 1, 3, btcwireErr, btcwireErr}, + {maxAddr, maxAddrEncoded, pverMA - 1, 3, wireErr, wireErr}, } t.Logf("Running %d tests", len(tests)) @@ -287,9 +287,9 @@ func TestAddrWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -298,7 +298,7 @@ func TestAddrWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgAddr + var msg wire.MsgAddr r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -307,9 +307,9 @@ func TestAddrWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msgalert.go b/wire/msgalert.go similarity index 99% rename from msgalert.go rename to wire/msgalert.go index 787a01ef..ec906e19 100644 --- a/msgalert.go +++ b/wire/msgalert.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "bytes" diff --git a/msgalert_test.go b/wire/msgalert_test.go similarity index 85% rename from msgalert_test.go rename to wire/msgalert_test.go index 6805a47c..deecd27b 100644 --- a/msgalert_test.go +++ b/wire/msgalert_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,18 +10,18 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestMsgAlert tests the MsgAlert API. func TestMsgAlert(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion serializedpayload := []byte("some message") signature := []byte("some sig") // Ensure we get the same payload and signature back out. - msg := btcwire.NewMsgAlert(serializedpayload, signature) + msg := wire.NewMsgAlert(serializedpayload, signature) if !reflect.DeepEqual(msg.SerializedPayload, serializedpayload) { t.Errorf("NewMsgAlert: wrong serializedpayload - got %v, want %v", msg.SerializedPayload, serializedpayload) @@ -64,7 +64,7 @@ func TestMsgAlert(t *testing.T) { // Test BtcEncode with Payload != nil // note: Payload is an empty Alert but not nil - msg.Payload = new(btcwire.Alert) + msg.Payload = new(wire.Alert) buf = *new(bytes.Buffer) err = msg.BtcEncode(&buf, pver) if err != nil { @@ -85,7 +85,7 @@ func TestMsgAlert(t *testing.T) { // TestMsgAlertWire tests the MsgAlert wire encode and decode for various protocol // versions. func TestMsgAlertWire(t *testing.T) { - baseMsgAlert := btcwire.NewMsgAlert([]byte("some payload"), []byte("somesig")) + baseMsgAlert := wire.NewMsgAlert([]byte("some payload"), []byte("somesig")) baseMsgAlertEncoded := []byte{ 0x0c, // Varint for payload length 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x61, 0x79, @@ -95,17 +95,17 @@ func TestMsgAlertWire(t *testing.T) { } tests := []struct { - in *btcwire.MsgAlert // Message to encode - out *btcwire.MsgAlert // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgAlert // Message to encode + out *wire.MsgAlert // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { baseMsgAlert, baseMsgAlert, baseMsgAlertEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version. @@ -113,7 +113,7 @@ func TestMsgAlertWire(t *testing.T) { baseMsgAlert, baseMsgAlert, baseMsgAlertEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version. @@ -121,7 +121,7 @@ func TestMsgAlertWire(t *testing.T) { baseMsgAlert, baseMsgAlert, baseMsgAlertEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion. @@ -129,7 +129,7 @@ func TestMsgAlertWire(t *testing.T) { baseMsgAlert, baseMsgAlert, baseMsgAlertEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion. @@ -137,7 +137,7 @@ func TestMsgAlertWire(t *testing.T) { baseMsgAlert, baseMsgAlert, baseMsgAlertEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -157,7 +157,7 @@ func TestMsgAlertWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgAlert + var msg wire.MsgAlert rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -175,9 +175,9 @@ func TestMsgAlertWire(t *testing.T) { // TestMsgAlertWireErrors performs negative tests against wire encode and decode // of MsgAlert to confirm error paths work correctly. func TestMsgAlertWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion - baseMsgAlert := btcwire.NewMsgAlert([]byte("some payload"), []byte("somesig")) + baseMsgAlert := wire.NewMsgAlert([]byte("some payload"), []byte("somesig")) baseMsgAlertEncoded := []byte{ 0x0c, // Varint for payload length 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x61, 0x79, @@ -187,12 +187,12 @@ func TestMsgAlertWireErrors(t *testing.T) { } tests := []struct { - in *btcwire.MsgAlert // 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 + in *wire.MsgAlert // 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 payload length. {baseMsgAlert, baseMsgAlertEncoded, pver, 0, io.ErrShortWrite, io.EOF}, @@ -215,9 +215,9 @@ func TestMsgAlertWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -226,7 +226,7 @@ func TestMsgAlertWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgAlert + var msg wire.MsgAlert r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -235,9 +235,9 @@ func TestMsgAlertWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) @@ -250,38 +250,38 @@ func TestMsgAlertWireErrors(t *testing.T) { baseMsgAlert.SerializedPayload = []byte{} w := new(bytes.Buffer) err := baseMsgAlert.BtcEncode(w, pver) - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { t.Errorf("MsgAlert.BtcEncode wrong error got: %T, want: %T", - err, btcwire.MessageError{}) + err, wire.MessageError{}) } // Test Payload Serialize error // overflow the max number of elements in SetCancel - baseMsgAlert.Payload = new(btcwire.Alert) - baseMsgAlert.Payload.SetCancel = make([]int32, btcwire.MaxCountSetCancel+1) + baseMsgAlert.Payload = new(wire.Alert) + baseMsgAlert.Payload.SetCancel = make([]int32, wire.MaxCountSetCancel+1) buf := *new(bytes.Buffer) err = baseMsgAlert.BtcEncode(&buf, pver) - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { t.Errorf("MsgAlert.BtcEncode wrong error got: %T, want: %T", - err, btcwire.MessageError{}) + err, wire.MessageError{}) } // overflow the max number of elements in SetSubVer - baseMsgAlert.Payload = new(btcwire.Alert) - baseMsgAlert.Payload.SetSubVer = make([]string, btcwire.MaxCountSetSubVer+1) + baseMsgAlert.Payload = new(wire.Alert) + baseMsgAlert.Payload.SetSubVer = make([]string, wire.MaxCountSetSubVer+1) buf = *new(bytes.Buffer) err = baseMsgAlert.BtcEncode(&buf, pver) - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { t.Errorf("MsgAlert.BtcEncode wrong error got: %T, want: %T", - err, btcwire.MessageError{}) + err, wire.MessageError{}) } } // TestAlert tests serialization and deserialization // of the payload to Alert func TestAlert(t *testing.T) { - pver := btcwire.ProtocolVersion - alert := btcwire.NewAlert( + pver := wire.ProtocolVersion + alert := wire.NewAlert( 1, 1337093712, 1368628812, 1015, 1013, []int32{1014}, 0, 40599, []string{"/Satoshi:0.7.2/"}, 5000, "", "URGENT: upgrade required, see http://bitcoin.org/dos for details", @@ -292,7 +292,7 @@ func TestAlert(t *testing.T) { t.Error(err.Error()) } serializedpayload := w.Bytes() - newAlert, err := btcwire.NewAlertFromPayload(serializedpayload, pver) + newAlert, err := wire.NewAlertFromPayload(serializedpayload, pver) if err != nil { t.Error(err.Error()) } @@ -366,9 +366,9 @@ func TestAlert(t *testing.T) { // TestAlertErrors performs negative tests against payload serialization, // deserialization of Alert to confirm error paths work correctly. func TestAlertErrors(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion - baseAlert := btcwire.NewAlert( + baseAlert := wire.NewAlert( 1, 1337093712, 1368628812, 1015, 1013, []int32{1014}, 0, 40599, []string{"/Satoshi:0.7.2/"}, 5000, "", "URGENT", @@ -381,12 +381,12 @@ func TestAlertErrors(t *testing.T) { 0x55, 0x52, 0x47, 0x45, 0x4e, 0x54, 0x00, //|URGENT.| } tests := []struct { - in *btcwire.Alert // 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 + in *wire.Alert // 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 {baseAlert, baseAlertEncoded, pver, 0, io.ErrShortWrite, io.EOF}, @@ -420,7 +420,7 @@ func TestAlertErrors(t *testing.T) { continue } - var alert btcwire.Alert + var alert wire.Alert r := newFixedReader(test.max, test.buf) err = alert.Deserialize(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -440,12 +440,12 @@ func TestAlertErrors(t *testing.T) { 0x73, 0x68, 0x69, 0x3a, 0x30, 0x2e, 0x37, 0x2e, 0x32, 0x2f, 0x88, 0x13, 0x00, 0x00, 0x00, 0x06, //|shi:0.7.2/......| 0x55, 0x52, 0x47, 0x45, 0x4e, 0x54, 0x00, //|URGENT.| } - var alert btcwire.Alert + var alert wire.Alert r := bytes.NewReader(badAlertEncoded) err := alert.Deserialize(r, pver) - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { t.Errorf("Alert.Deserialize wrong error got: %T, want: %T", - err, btcwire.MessageError{}) + err, wire.MessageError{}) } // overflow the max number of elements in SetSubVer @@ -460,8 +460,8 @@ func TestAlertErrors(t *testing.T) { } r = bytes.NewReader(badAlertEncoded) err = alert.Deserialize(r, pver) - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { t.Errorf("Alert.Deserialize wrong error got: %T, want: %T", - err, btcwire.MessageError{}) + err, wire.MessageError{}) } } diff --git a/msgblock.go b/wire/msgblock.go similarity index 99% rename from msgblock.go rename to wire/msgblock.go index 7d058923..812e7bf7 100644 --- a/msgblock.go +++ b/wire/msgblock.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "bytes" diff --git a/msgblock_test.go b/wire/msgblock_test.go similarity index 86% rename from msgblock_test.go rename to wire/msgblock_test.go index 371f084d..1db70626 100644 --- a/msgblock_test.go +++ b/wire/msgblock_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -11,24 +11,24 @@ import ( "testing" "time" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestBlock tests the MsgBlock API. func TestBlock(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // 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) + bh := wire.NewBlockHeader(prevHash, merkleHash, bits, nonce) // Ensure the command is expected value. wantCmd := "block" - msg := btcwire.NewMsgBlock(bh) + msg := wire.NewMsgBlock(bh) if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgBlock: wrong command - got %v want %v", cmd, wantCmd) @@ -74,13 +74,13 @@ func TestBlock(t *testing.T) { func TestBlockTxShas(t *testing.T) { // Block 1, transaction 1 hash. hashStr := "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098" - wantHash, err := btcwire.NewShaHashFromStr(hashStr) + wantHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) return } - wantShas := []btcwire.ShaHash{*wantHash} + wantShas := []wire.ShaHash{*wantHash} shas, err := blockOne.TxShas() if err != nil { t.Errorf("TxShas: %v", err) @@ -95,7 +95,7 @@ func TestBlockTxShas(t *testing.T) { func TestBlockSha(t *testing.T) { // Block 1 hash. hashStr := "839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048" - wantHash, err := btcwire.NewShaHashFromStr(hashStr) + wantHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } @@ -115,11 +115,11 @@ func TestBlockSha(t *testing.T) { // of transaction inputs and outputs and protocol versions. func TestBlockWire(t *testing.T) { tests := []struct { - in *btcwire.MsgBlock // Message to encode - out *btcwire.MsgBlock // Expected decoded message - buf []byte // Wire encoding - txLocs []btcwire.TxLoc // Expected transaction locations - pver uint32 // Protocol version for wire encoding + in *wire.MsgBlock // Message to encode + out *wire.MsgBlock // Expected decoded message + buf []byte // Wire encoding + txLocs []wire.TxLoc // Expected transaction locations + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { @@ -127,7 +127,7 @@ func TestBlockWire(t *testing.T) { &blockOne, blockOneBytes, blockOneTxLocs, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version. @@ -136,7 +136,7 @@ func TestBlockWire(t *testing.T) { &blockOne, blockOneBytes, blockOneTxLocs, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version. @@ -145,7 +145,7 @@ func TestBlockWire(t *testing.T) { &blockOne, blockOneBytes, blockOneTxLocs, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion. @@ -154,7 +154,7 @@ func TestBlockWire(t *testing.T) { &blockOne, blockOneBytes, blockOneTxLocs, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion. @@ -163,7 +163,7 @@ func TestBlockWire(t *testing.T) { &blockOne, blockOneBytes, blockOneTxLocs, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -183,7 +183,7 @@ func TestBlockWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgBlock + var msg wire.MsgBlock rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -207,12 +207,12 @@ func TestBlockWireErrors(t *testing.T) { pver := uint32(60002) tests := []struct { - in *btcwire.MsgBlock // 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 + in *wire.MsgBlock // 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. {&blockOne, blockOneBytes, pver, 0, io.ErrShortWrite, io.EOF}, @@ -244,7 +244,7 @@ func TestBlockWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgBlock + var msg wire.MsgBlock r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if err != test.readErr { @@ -258,10 +258,10 @@ func TestBlockWireErrors(t *testing.T) { // TestBlockSerialize tests MsgBlock serialize and deserialize. func TestBlockSerialize(t *testing.T) { tests := []struct { - in *btcwire.MsgBlock // Message to encode - out *btcwire.MsgBlock // Expected decoded message - buf []byte // Serialized data - txLocs []btcwire.TxLoc // Expected transaction locations + in *wire.MsgBlock // Message to encode + out *wire.MsgBlock // Expected decoded message + buf []byte // Serialized data + txLocs []wire.TxLoc // Expected transaction locations }{ { &blockOne, @@ -287,7 +287,7 @@ func TestBlockSerialize(t *testing.T) { } // Deserialize the block. - var block btcwire.MsgBlock + var block wire.MsgBlock rbuf := bytes.NewReader(test.buf) err = block.Deserialize(rbuf) if err != nil { @@ -302,7 +302,7 @@ func TestBlockSerialize(t *testing.T) { // Deserialize the block while gathering transaction location // information. - var txLocBlock btcwire.MsgBlock + var txLocBlock wire.MsgBlock br := bytes.NewBuffer(test.buf) txLocs, err := txLocBlock.DeserializeTxLoc(br) if err != nil { @@ -326,11 +326,11 @@ func TestBlockSerialize(t *testing.T) { // decode of MsgBlock to confirm error paths work correctly. func TestBlockSerializeErrors(t *testing.T) { tests := []struct { - in *btcwire.MsgBlock // Value to encode - buf []byte // Serialized data - max int // Max size of fixed buffer to induce errors - writeErr error // Expected write error - readErr error // Expected read error + in *wire.MsgBlock // Value to encode + buf []byte // Serialized data + max int // Max size of fixed buffer to induce errors + writeErr error // Expected write error + readErr error // Expected read error }{ // Force error in version. {&blockOne, blockOneBytes, 0, io.ErrShortWrite, io.EOF}, @@ -362,7 +362,7 @@ func TestBlockSerializeErrors(t *testing.T) { } // Deserialize the block. - var block btcwire.MsgBlock + var block wire.MsgBlock r := newFixedReader(test.max, test.buf) err = block.Deserialize(r) if err != test.readErr { @@ -371,7 +371,7 @@ func TestBlockSerializeErrors(t *testing.T) { continue } - var txLocBlock btcwire.MsgBlock + var txLocBlock wire.MsgBlock br := bytes.NewBuffer(test.buf[0:test.max]) _, err = txLocBlock.DeserializeTxLoc(br) if err != test.readErr { @@ -414,14 +414,14 @@ func TestBlockOverflowErrors(t *testing.T) { 0x01, 0xe3, 0x62, 0x99, // Nonce 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // TxnCount - }, pver, &btcwire.MessageError{}, + }, pver, &wire.MessageError{}, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Decode from wire format. - var msg btcwire.MsgBlock + var msg wire.MsgBlock r := bytes.NewReader(test.buf) err := msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { @@ -454,11 +454,11 @@ func TestBlockOverflowErrors(t *testing.T) { // various blocks is accurate. func TestBlockSerializeSize(t *testing.T) { // Block with no transactions. - noTxBlock := btcwire.NewMsgBlock(&blockOne.Header) + noTxBlock := wire.NewMsgBlock(&blockOne.Header) tests := []struct { - in *btcwire.MsgBlock // Block to encode - size int // Expected serialized size + in *wire.MsgBlock // Block to encode + size int // Expected serialized size }{ // Block with no transactions. {noTxBlock, 81}, @@ -478,16 +478,16 @@ func TestBlockSerializeSize(t *testing.T) { } } -var blockOne = btcwire.MsgBlock{ - Header: btcwire.BlockHeader{ +var blockOne = wire.MsgBlock{ + Header: wire.BlockHeader{ Version: 1, - PrevBlock: btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. + PrevBlock: wire.ShaHash([wire.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. + MerkleRoot: wire.ShaHash([wire.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, @@ -498,13 +498,13 @@ var blockOne = btcwire.MsgBlock{ Bits: 0x1d00ffff, // 486604799 Nonce: 0x9962e301, // 2573394689 }, - Transactions: []*btcwire.MsgTx{ + Transactions: []*wire.MsgTx{ { Version: 1, - TxIn: []*btcwire.TxIn{ + TxIn: []*wire.TxIn{ { - PreviousOutPoint: btcwire.OutPoint{ - Hash: btcwire.ShaHash{}, + PreviousOutPoint: wire.OutPoint{ + Hash: wire.ShaHash{}, Index: 0xffffffff, }, SignatureScript: []byte{ @@ -513,7 +513,7 @@ var blockOne = btcwire.MsgBlock{ Sequence: 0xffffffff, }, }, - TxOut: []*btcwire.TxOut{ + TxOut: []*wire.TxOut{ { Value: 0x12a05f200, PkScript: []byte{ @@ -579,6 +579,6 @@ var blockOneBytes = []byte{ } // Transaction location information for block one transactions. -var blockOneTxLocs = []btcwire.TxLoc{ +var blockOneTxLocs = []wire.TxLoc{ {TxStart: 81, TxLen: 134}, } diff --git a/msgfilteradd.go b/wire/msgfilteradd.go similarity index 97% rename from msgfilteradd.go rename to wire/msgfilteradd.go index a04bdcc4..84162efa 100644 --- a/msgfilteradd.go +++ b/wire/msgfilteradd.go @@ -1,8 +1,8 @@ -// Copyright (c) 2014 Conformal Systems LLC. +// Copyright (c) 2014-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msgfilteradd_test.go b/wire/msgfilteradd_test.go similarity index 75% rename from msgfilteradd_test.go rename to wire/msgfilteradd_test.go index 1a87bac2..6b501c57 100644 --- a/msgfilteradd_test.go +++ b/wire/msgfilteradd_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2014 Conformal Systems LLC. +// Copyright (c) 2014-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,16 +10,16 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" ) // TestFilterAddLatest tests the MsgFilterAdd API against the latest protocol // version. func TestFilterAddLatest(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion data := []byte{0x01, 0x02} - msg := btcwire.NewMsgFilterAdd(data) + msg := wire.NewMsgFilterAdd(data) // Ensure the command is expected value. wantCmd := "filteradd" @@ -45,7 +45,7 @@ func TestFilterAddLatest(t *testing.T) { } // Test decode with latest protocol version. - var readmsg btcwire.MsgFilterAdd + var readmsg wire.MsgFilterAdd err = readmsg.BtcDecode(&buf, pver) if err != nil { t.Errorf("decode of MsgFilterAdd failed [%v] err <%v>", buf, err) @@ -58,21 +58,21 @@ func TestFilterAddLatest(t *testing.T) { // latest protocol version and decoding with BIP0031Version. func TestFilterAddCrossProtocol(t *testing.T) { data := []byte{0x01, 0x02} - msg := btcwire.NewMsgFilterAdd(data) + msg := wire.NewMsgFilterAdd(data) if !bytes.Equal(msg.Data, data) { t.Errorf("should get same data back out") } // Encode with latest protocol version. var buf bytes.Buffer - err := msg.BtcEncode(&buf, btcwire.ProtocolVersion) + err := msg.BtcEncode(&buf, wire.ProtocolVersion) if err != nil { t.Errorf("encode of MsgFilterAdd failed %v err <%v>", msg, err) } // Decode with old protocol version. - var readmsg btcwire.MsgFilterAdd - err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version) + var readmsg wire.MsgFilterAdd + err = readmsg.BtcDecode(&buf, wire.BIP0031Version) if err == nil { t.Errorf("decode of MsgFilterAdd succeeded when it shouldn't "+ "have %v", msg) @@ -89,11 +89,11 @@ func TestFilterAddCrossProtocol(t *testing.T) { // TestFilterAddMaxDataSize tests the MsgFilterAdd API maximum data size. func TestFilterAddMaxDataSize(t *testing.T) { data := bytes.Repeat([]byte{0xff}, 521) - msg := btcwire.NewMsgFilterAdd(data) + msg := wire.NewMsgFilterAdd(data) // Encode with latest protocol version. var buf bytes.Buffer - err := msg.BtcEncode(&buf, btcwire.ProtocolVersion) + err := msg.BtcEncode(&buf, wire.ProtocolVersion) if err == nil { t.Errorf("encode of MsgFilterAdd succeeded when it shouldn't "+ "have %v", msg) @@ -101,7 +101,7 @@ func TestFilterAddMaxDataSize(t *testing.T) { // Decode with latest protocol version. readbuf := bytes.NewReader(data) - err = msg.BtcDecode(readbuf, btcwire.ProtocolVersion) + err = msg.BtcDecode(readbuf, wire.ProtocolVersion) if err == nil { t.Errorf("decode of MsgFilterAdd succeeded when it shouldn't "+ "have %v", msg) @@ -111,21 +111,21 @@ func TestFilterAddMaxDataSize(t *testing.T) { // TestFilterAddWireErrors performs negative tests against wire encode and decode // of MsgFilterAdd to confirm error paths work correctly. func TestFilterAddWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - pverNoFilterAdd := btcwire.BIP0037Version - 1 - btcwireErr := &btcwire.MessageError{} + pver := wire.ProtocolVersion + pverNoFilterAdd := wire.BIP0037Version - 1 + wireErr := &wire.MessageError{} baseData := []byte{0x01, 0x02, 0x03, 0x04} - baseFilterAdd := btcwire.NewMsgFilterAdd(baseData) + baseFilterAdd := wire.NewMsgFilterAdd(baseData) baseFilterAddEncoded := append([]byte{0x04}, baseData...) tests := []struct { - in *btcwire.MsgFilterAdd // 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 + in *wire.MsgFilterAdd // 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 error in data size. @@ -141,7 +141,7 @@ func TestFilterAddWireErrors(t *testing.T) { // Force error due to unsupported protocol version. { baseFilterAdd, baseFilterAddEncoded, pverNoFilterAdd, 5, - btcwireErr, btcwireErr, + wireErr, wireErr, }, } @@ -156,9 +156,9 @@ func TestFilterAddWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -167,7 +167,7 @@ func TestFilterAddWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgFilterAdd + var msg wire.MsgFilterAdd r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -176,9 +176,9 @@ func TestFilterAddWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msgfilterclear.go b/wire/msgfilterclear.go similarity index 96% rename from msgfilterclear.go rename to wire/msgfilterclear.go index 45580786..37da436f 100644 --- a/msgfilterclear.go +++ b/wire/msgfilterclear.go @@ -1,8 +1,8 @@ -// Copyright (c) 2014 Conformal Systems LLC. +// Copyright (c) 2014-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msgfilterclear_test.go b/wire/msgfilterclear_test.go similarity index 71% rename from msgfilterclear_test.go rename to wire/msgfilterclear_test.go index 17047aac..73740f98 100644 --- a/msgfilterclear_test.go +++ b/wire/msgfilterclear_test.go @@ -1,24 +1,24 @@ -// Copyright (c) 2014 Conformal Systems LLC. +// Copyright (c) 2014-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestFilterCLearLatest tests the MsgFilterClear API against the latest // protocol version. func TestFilterClearLatest(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion - msg := btcwire.NewMsgFilterClear() + msg := wire.NewMsgFilterClear() // Ensure the command is expected value. wantCmd := "filterclear" @@ -42,18 +42,18 @@ func TestFilterClearLatest(t *testing.T) { // TestFilterClearCrossProtocol tests the MsgFilterClear API when encoding with // the latest protocol version and decoding with BIP0031Version. func TestFilterClearCrossProtocol(t *testing.T) { - msg := btcwire.NewMsgFilterClear() + msg := wire.NewMsgFilterClear() // Encode with latest protocol version. var buf bytes.Buffer - err := msg.BtcEncode(&buf, btcwire.ProtocolVersion) + err := msg.BtcEncode(&buf, wire.ProtocolVersion) if err != nil { t.Errorf("encode of MsgFilterClear failed %v err <%v>", msg, err) } // Decode with old protocol version. - var readmsg btcwire.MsgFilterClear - err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version) + var readmsg wire.MsgFilterClear + err = readmsg.BtcDecode(&buf, wire.BIP0031Version) if err == nil { t.Errorf("decode of MsgFilterClear succeeded when it "+ "shouldn't have %v", msg) @@ -63,21 +63,21 @@ func TestFilterClearCrossProtocol(t *testing.T) { // TestFilterClearWire tests the MsgFilterClear wire encode and decode for // various protocol versions. func TestFilterClearWire(t *testing.T) { - msgFilterClear := btcwire.NewMsgFilterClear() + msgFilterClear := wire.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 + in *wire.MsgFilterClear // Message to encode + out *wire.MsgFilterClear // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { msgFilterClear, msgFilterClear, msgFilterClearEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0037Version + 1. @@ -85,7 +85,7 @@ func TestFilterClearWire(t *testing.T) { msgFilterClear, msgFilterClear, msgFilterClearEncoded, - btcwire.BIP0037Version + 1, + wire.BIP0037Version + 1, }, // Protocol version BIP0037Version. @@ -93,7 +93,7 @@ func TestFilterClearWire(t *testing.T) { msgFilterClear, msgFilterClear, msgFilterClearEncoded, - btcwire.BIP0037Version, + wire.BIP0037Version, }, } @@ -113,7 +113,7 @@ func TestFilterClearWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgFilterClear + var msg wire.MsgFilterClear rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -131,24 +131,24 @@ func TestFilterClearWire(t *testing.T) { // 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{} + pverNoFilterClear := wire.BIP0037Version - 1 + wireErr := &wire.MessageError{} - baseFilterClear := btcwire.NewMsgFilterClear() + baseFilterClear := wire.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 + in *wire.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, + pverNoFilterClear, 4, wireErr, wireErr, }, } @@ -163,9 +163,9 @@ func TestFilterClearWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -174,7 +174,7 @@ func TestFilterClearWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgFilterClear + var msg wire.MsgFilterClear r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -183,9 +183,9 @@ func TestFilterClearWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msgfilterload.go b/wire/msgfilterload.go similarity index 98% rename from msgfilterload.go rename to wire/msgfilterload.go index f0bdbe66..7523834d 100644 --- a/msgfilterload.go +++ b/wire/msgfilterload.go @@ -1,8 +1,8 @@ -// Copyright (c) 2014 Conformal Systems LLC. +// Copyright (c) 2014-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msgfilterload_test.go b/wire/msgfilterload_test.go similarity index 81% rename from msgfilterload_test.go rename to wire/msgfilterload_test.go index c1c25262..a6306491 100644 --- a/msgfilterload_test.go +++ b/wire/msgfilterload_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,16 +10,16 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" ) // TestFilterCLearLatest tests the MsgFilterLoad API against the latest protocol // version. func TestFilterLoadLatest(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion data := []byte{0x01, 0x02} - msg := btcwire.NewMsgFilterLoad(data, 10, 0, 0) + msg := wire.NewMsgFilterLoad(data, 10, 0, 0) // Ensure the command is expected value. wantCmd := "filterload" @@ -45,7 +45,7 @@ func TestFilterLoadLatest(t *testing.T) { } // Test decode with latest protocol version. - readmsg := btcwire.MsgFilterLoad{} + readmsg := wire.MsgFilterLoad{} err = readmsg.BtcDecode(&buf, pver) if err != nil { t.Errorf("decode of MsgFilterLoad failed [%v] err <%v>", buf, err) @@ -58,19 +58,19 @@ func TestFilterLoadLatest(t *testing.T) { // the latest protocol version and decoding with BIP0031Version. func TestFilterLoadCrossProtocol(t *testing.T) { data := []byte{0x01, 0x02} - msg := btcwire.NewMsgFilterLoad(data, 10, 0, 0) + msg := wire.NewMsgFilterLoad(data, 10, 0, 0) // Encode with latest protocol version. var buf bytes.Buffer - err := msg.BtcEncode(&buf, btcwire.ProtocolVersion) + err := msg.BtcEncode(&buf, wire.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) + var readmsg wire.MsgFilterLoad + err = readmsg.BtcDecode(&buf, wire.BIP0031Version) if err == nil { t.Errorf("decode of MsgFilterLoad succeeded when it shouldn't have %v", msg) @@ -80,11 +80,11 @@ func TestFilterLoadCrossProtocol(t *testing.T) { // TestFilterLoadMaxFilterSize tests the MsgFilterLoad API maximum filter size. func TestFilterLoadMaxFilterSize(t *testing.T) { data := bytes.Repeat([]byte{0xff}, 36001) - msg := btcwire.NewMsgFilterLoad(data, 10, 0, 0) + msg := wire.NewMsgFilterLoad(data, 10, 0, 0) // Encode with latest protocol version. var buf bytes.Buffer - err := msg.BtcEncode(&buf, btcwire.ProtocolVersion) + err := msg.BtcEncode(&buf, wire.ProtocolVersion) if err == nil { t.Errorf("encode of MsgFilterLoad succeeded when it shouldn't "+ "have %v", msg) @@ -92,7 +92,7 @@ func TestFilterLoadMaxFilterSize(t *testing.T) { // Decode with latest protocol version. readbuf := bytes.NewReader(data) - err = msg.BtcDecode(readbuf, btcwire.ProtocolVersion) + err = msg.BtcDecode(readbuf, wire.ProtocolVersion) if err == nil { t.Errorf("decode of MsgFilterLoad succeeded when it shouldn't "+ "have %v", msg) @@ -102,11 +102,11 @@ func TestFilterLoadMaxFilterSize(t *testing.T) { // TestFilterLoadMaxHashFuncsSize tests the MsgFilterLoad API maximum hash functions. func TestFilterLoadMaxHashFuncsSize(t *testing.T) { data := bytes.Repeat([]byte{0xff}, 10) - msg := btcwire.NewMsgFilterLoad(data, 61, 0, 0) + msg := wire.NewMsgFilterLoad(data, 61, 0, 0) // Encode with latest protocol version. var buf bytes.Buffer - err := msg.BtcEncode(&buf, btcwire.ProtocolVersion) + err := msg.BtcEncode(&buf, wire.ProtocolVersion) if err == nil { t.Errorf("encode of MsgFilterLoad succeeded when it shouldn't have %v", msg) @@ -121,7 +121,7 @@ func TestFilterLoadMaxHashFuncsSize(t *testing.T) { } // Decode with latest protocol version. readbuf := bytes.NewReader(newBuf) - err = msg.BtcDecode(readbuf, btcwire.ProtocolVersion) + err = msg.BtcDecode(readbuf, wire.ProtocolVersion) if err == nil { t.Errorf("decode of MsgFilterLoad succeeded when it shouldn't have %v", msg) @@ -131,13 +131,13 @@ func TestFilterLoadMaxHashFuncsSize(t *testing.T) { // TestFilterLoadWireErrors performs negative tests against wire encode and decode // of MsgFilterLoad to confirm error paths work correctly. func TestFilterLoadWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - pverNoFilterLoad := btcwire.BIP0037Version - 1 - btcwireErr := &btcwire.MessageError{} + pver := wire.ProtocolVersion + pverNoFilterLoad := wire.BIP0037Version - 1 + wireErr := &wire.MessageError{} baseFilter := []byte{0x01, 0x02, 0x03, 0x04} - baseFilterLoad := btcwire.NewMsgFilterLoad(baseFilter, 10, 0, - btcwire.BloomUpdateNone) + baseFilterLoad := wire.NewMsgFilterLoad(baseFilter, 10, 0, + wire.BloomUpdateNone) baseFilterLoadEncoded := append([]byte{0x04}, baseFilter...) baseFilterLoadEncoded = append(baseFilterLoadEncoded, 0x00, 0x00, 0x00, 0x0a, // HashFuncs @@ -145,7 +145,7 @@ func TestFilterLoadWireErrors(t *testing.T) { 0x00) // Flags tests := []struct { - in *btcwire.MsgFilterLoad // Value to encode + in *wire.MsgFilterLoad // Value to encode buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding max int // Max size of fixed buffer to induce errors @@ -181,7 +181,7 @@ func TestFilterLoadWireErrors(t *testing.T) { // Force error due to unsupported protocol version. { baseFilterLoad, baseFilterLoadEncoded, pverNoFilterLoad, - 10, btcwireErr, btcwireErr, + 10, wireErr, wireErr, }, } @@ -196,9 +196,9 @@ func TestFilterLoadWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -207,7 +207,7 @@ func TestFilterLoadWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgFilterLoad + var msg wire.MsgFilterLoad r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -216,9 +216,9 @@ func TestFilterLoadWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msggetaddr.go b/wire/msggetaddr.go similarity index 95% rename from msggetaddr.go rename to wire/msggetaddr.go index 6ccf767e..70589fe2 100644 --- a/msggetaddr.go +++ b/wire/msggetaddr.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "io" diff --git a/msggetaddr_test.go b/wire/msggetaddr_test.go similarity index 79% rename from msggetaddr_test.go rename to wire/msggetaddr_test.go index bd5d5539..d49928ac 100644 --- a/msggetaddr_test.go +++ b/wire/msggetaddr_test.go @@ -1,25 +1,25 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestGetAddr tests the MsgGetAddr API. func TestGetAddr(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Ensure the command is expected value. wantCmd := "getaddr" - msg := btcwire.NewMsgGetAddr() + msg := wire.NewMsgGetAddr() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgGetAddr: wrong command - got %v want %v", cmd, wantCmd) @@ -41,21 +41,21 @@ func TestGetAddr(t *testing.T) { // TestGetAddrWire tests the MsgGetAddr wire encode and decode for various // protocol versions. func TestGetAddrWire(t *testing.T) { - msgGetAddr := btcwire.NewMsgGetAddr() + msgGetAddr := wire.NewMsgGetAddr() msgGetAddrEncoded := []byte{} tests := []struct { - in *btcwire.MsgGetAddr // Message to encode - out *btcwire.MsgGetAddr // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgGetAddr // Message to encode + out *wire.MsgGetAddr // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { msgGetAddr, msgGetAddr, msgGetAddrEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version. @@ -63,7 +63,7 @@ func TestGetAddrWire(t *testing.T) { msgGetAddr, msgGetAddr, msgGetAddrEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version. @@ -71,7 +71,7 @@ func TestGetAddrWire(t *testing.T) { msgGetAddr, msgGetAddr, msgGetAddrEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion. @@ -79,7 +79,7 @@ func TestGetAddrWire(t *testing.T) { msgGetAddr, msgGetAddr, msgGetAddrEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion. @@ -87,7 +87,7 @@ func TestGetAddrWire(t *testing.T) { msgGetAddr, msgGetAddr, msgGetAddrEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -107,7 +107,7 @@ func TestGetAddrWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgGetAddr + var msg wire.MsgGetAddr rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { diff --git a/msggetblocks.go b/wire/msggetblocks.go similarity index 98% rename from msggetblocks.go rename to wire/msggetblocks.go index e8e5dcfe..3dbecf5d 100644 --- a/msggetblocks.go +++ b/wire/msggetblocks.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msggetblocks_test.go b/wire/msggetblocks_test.go similarity index 81% rename from msggetblocks_test.go rename to wire/msggetblocks_test.go index 03733a2b..50234c20 100644 --- a/msggetblocks_test.go +++ b/wire/msggetblocks_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,30 +10,30 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestGetBlocks tests the MsgGetBlocks API. func TestGetBlocks(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Block 99500 hash. hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" - locatorHash, err := btcwire.NewShaHashFromStr(hashStr) + locatorHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Block 100000 hash. hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" - hashStop, err := btcwire.NewShaHashFromStr(hashStr) + hashStop, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Ensure we get the same data back out. - msg := btcwire.NewMsgGetBlocks(hashStop) + msg := wire.NewMsgGetBlocks(hashStop) if !msg.HashStop.IsEqual(hashStop) { t.Errorf("NewMsgGetBlocks: wrong stop hash - got %v, want %v", msg.HashStop, hashStop) @@ -71,7 +71,7 @@ func TestGetBlocks(t *testing.T) { // Ensure adding more than the max allowed block locator hashes per // message returns an error. - for i := 0; i < btcwire.MaxBlockLocatorsPerMsg; i++ { + for i := 0; i < wire.MaxBlockLocatorsPerMsg; i++ { err = msg.AddBlockLocatorHash(locatorHash) } if err == nil { @@ -90,27 +90,27 @@ func TestGetBlocksWire(t *testing.T) { // Block 99499 hash. hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535" - hashLocator, err := btcwire.NewShaHashFromStr(hashStr) + hashLocator, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Block 99500 hash. hashStr = "2e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" - hashLocator2, err := btcwire.NewShaHashFromStr(hashStr) + hashLocator2, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Block 100000 hash. hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" - hashStop, err := btcwire.NewShaHashFromStr(hashStr) + hashStop, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // MsgGetBlocks message with no block locators or stop hash. - noLocators := btcwire.NewMsgGetBlocks(&btcwire.ShaHash{}) + noLocators := wire.NewMsgGetBlocks(&wire.ShaHash{}) noLocators.ProtocolVersion = pver noLocatorsEncoded := []byte{ 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 @@ -122,7 +122,7 @@ func TestGetBlocksWire(t *testing.T) { } // MsgGetBlocks message with multiple block locators and a stop hash. - multiLocators := btcwire.NewMsgGetBlocks(hashStop) + multiLocators := wire.NewMsgGetBlocks(hashStop) multiLocators.AddBlockLocatorHash(hashLocator2) multiLocators.AddBlockLocatorHash(hashLocator) multiLocators.ProtocolVersion = pver @@ -144,17 +144,17 @@ func TestGetBlocksWire(t *testing.T) { } tests := []struct { - in *btcwire.MsgGetBlocks // Message to encode - out *btcwire.MsgGetBlocks // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgGetBlocks // Message to encode + out *wire.MsgGetBlocks // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version with no block locators. { noLocators, noLocators, noLocatorsEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version with multiple block locators. @@ -162,7 +162,7 @@ func TestGetBlocksWire(t *testing.T) { multiLocators, multiLocators, multiLocatorsEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version with no block locators. @@ -170,7 +170,7 @@ func TestGetBlocksWire(t *testing.T) { noLocators, noLocators, noLocatorsEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0035Version with multiple block locators. @@ -178,7 +178,7 @@ func TestGetBlocksWire(t *testing.T) { multiLocators, multiLocators, multiLocatorsEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version with no block locators. @@ -186,7 +186,7 @@ func TestGetBlocksWire(t *testing.T) { noLocators, noLocators, noLocatorsEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version BIP0031Versionwith multiple block locators. @@ -194,7 +194,7 @@ func TestGetBlocksWire(t *testing.T) { multiLocators, multiLocators, multiLocatorsEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion with no block locators. @@ -202,7 +202,7 @@ func TestGetBlocksWire(t *testing.T) { noLocators, noLocators, noLocatorsEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion multiple block locators. @@ -210,7 +210,7 @@ func TestGetBlocksWire(t *testing.T) { multiLocators, multiLocators, multiLocatorsEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion with no block locators. @@ -218,7 +218,7 @@ func TestGetBlocksWire(t *testing.T) { noLocators, noLocators, noLocatorsEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion multiple block locators. @@ -226,7 +226,7 @@ func TestGetBlocksWire(t *testing.T) { multiLocators, multiLocators, multiLocatorsEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -246,7 +246,7 @@ func TestGetBlocksWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgGetBlocks + var msg wire.MsgGetBlocks rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -268,31 +268,31 @@ func TestGetBlocksWireErrors(t *testing.T) { // specifically here instead of the latest because the test data is // using bytes encoded with that protocol version. pver := uint32(60002) - btcwireErr := &btcwire.MessageError{} + wireErr := &wire.MessageError{} // Block 99499 hash. hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535" - hashLocator, err := btcwire.NewShaHashFromStr(hashStr) + hashLocator, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Block 99500 hash. hashStr = "2e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" - hashLocator2, err := btcwire.NewShaHashFromStr(hashStr) + hashLocator2, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Block 100000 hash. hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" - hashStop, err := btcwire.NewShaHashFromStr(hashStr) + hashStop, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // MsgGetBlocks message with multiple block locators and a stop hash. - baseGetBlocks := btcwire.NewMsgGetBlocks(hashStop) + baseGetBlocks := wire.NewMsgGetBlocks(hashStop) baseGetBlocks.ProtocolVersion = pver baseGetBlocks.AddBlockLocatorHash(hashLocator2) baseGetBlocks.AddBlockLocatorHash(hashLocator) @@ -315,8 +315,8 @@ func TestGetBlocksWireErrors(t *testing.T) { // Message that forces an error by having more than the max allowed // block locator hashes. - maxGetBlocks := btcwire.NewMsgGetBlocks(hashStop) - for i := 0; i < btcwire.MaxBlockLocatorsPerMsg; i++ { + maxGetBlocks := wire.NewMsgGetBlocks(hashStop) + for i := 0; i < wire.MaxBlockLocatorsPerMsg; i++ { maxGetBlocks.AddBlockLocatorHash(&mainNetGenesisHash) } maxGetBlocks.BlockLocatorHashes = append(maxGetBlocks.BlockLocatorHashes, @@ -327,12 +327,12 @@ func TestGetBlocksWireErrors(t *testing.T) { } tests := []struct { - in *btcwire.MsgGetBlocks // 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 + in *wire.MsgGetBlocks // 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 protocol version. {baseGetBlocks, baseGetBlocksEncoded, pver, 0, io.ErrShortWrite, io.EOF}, @@ -343,7 +343,7 @@ func TestGetBlocksWireErrors(t *testing.T) { // Force error in stop hash. {baseGetBlocks, baseGetBlocksEncoded, pver, 69, io.ErrShortWrite, io.EOF}, // Force error with greater than max block locator hashes. - {maxGetBlocks, maxGetBlocksEncoded, pver, 7, btcwireErr, btcwireErr}, + {maxGetBlocks, maxGetBlocksEncoded, pver, 7, wireErr, wireErr}, } t.Logf("Running %d tests", len(tests)) @@ -357,9 +357,9 @@ func TestGetBlocksWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -368,7 +368,7 @@ func TestGetBlocksWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgGetBlocks + var msg wire.MsgGetBlocks r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -377,9 +377,9 @@ func TestGetBlocksWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msggetdata.go b/wire/msggetdata.go similarity index 98% rename from msggetdata.go rename to wire/msggetdata.go index 63392eee..661d3234 100644 --- a/msggetdata.go +++ b/wire/msggetdata.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msggetdata_test.go b/wire/msggetdata_test.go similarity index 76% rename from msggetdata_test.go rename to wire/msggetdata_test.go index 4673e58f..e8d38815 100644 --- a/msggetdata_test.go +++ b/wire/msggetdata_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,17 +10,17 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestGetData tests the MsgGetData API. func TestGetData(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Ensure the command is expected value. wantCmd := "getdata" - msg := btcwire.NewMsgGetData() + msg := wire.NewMsgGetData() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgGetData: wrong command - got %v want %v", cmd, wantCmd) @@ -37,8 +37,8 @@ func TestGetData(t *testing.T) { } // Ensure inventory vectors are added properly. - hash := btcwire.ShaHash{} - iv := btcwire.NewInvVect(btcwire.InvTypeBlock, &hash) + hash := wire.ShaHash{} + iv := wire.NewInvVect(wire.InvTypeBlock, &hash) err := msg.AddInvVect(iv) if err != nil { t.Errorf("AddInvVect: %v", err) @@ -50,7 +50,7 @@ func TestGetData(t *testing.T) { // Ensure adding more than the max allowed inventory vectors per // message returns an error. - for i := 0; i < btcwire.MaxInvPerMsg; i++ { + for i := 0; i < wire.MaxInvPerMsg; i++ { err = msg.AddInvVect(iv) } if err == nil { @@ -60,8 +60,8 @@ func TestGetData(t *testing.T) { // Ensure creating the message with a size hint larger than the max // works as expected. - msg = btcwire.NewMsgGetDataSizeHint(btcwire.MaxInvPerMsg + 1) - wantCap := btcwire.MaxInvPerMsg + msg = wire.NewMsgGetDataSizeHint(wire.MaxInvPerMsg + 1) + wantCap := wire.MaxInvPerMsg if cap(msg.InvList) != wantCap { t.Errorf("NewMsgGetDataSizeHint: wrong cap for size hint - "+ "got %v, want %v", cap(msg.InvList), wantCap) @@ -75,29 +75,29 @@ func TestGetData(t *testing.T) { func TestGetDataWire(t *testing.T) { // Block 203707 hash. hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" - blockHash, err := btcwire.NewShaHashFromStr(hashStr) + blockHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Transation 1 of Block 203707 hash. hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0" - txHash, err := btcwire.NewShaHashFromStr(hashStr) + txHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) - iv2 := btcwire.NewInvVect(btcwire.InvTypeTx, txHash) + iv := wire.NewInvVect(wire.InvTypeBlock, blockHash) + iv2 := wire.NewInvVect(wire.InvTypeTx, txHash) // Empty MsgGetData message. - NoInv := btcwire.NewMsgGetData() + NoInv := wire.NewMsgGetData() NoInvEncoded := []byte{ 0x00, // Varint for number of inventory vectors } // MsgGetData message with multiple inventory vectors. - MultiInv := btcwire.NewMsgGetData() + MultiInv := wire.NewMsgGetData() MultiInv.AddInvVect(iv) MultiInv.AddInvVect(iv2) MultiInvEncoded := []byte{ @@ -115,17 +115,17 @@ func TestGetDataWire(t *testing.T) { } tests := []struct { - in *btcwire.MsgGetData // Message to encode - out *btcwire.MsgGetData // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgGetData // Message to encode + out *wire.MsgGetData // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version with no inv vectors. { NoInv, NoInv, NoInvEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version with multiple inv vectors. @@ -133,7 +133,7 @@ func TestGetDataWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version no inv vectors. @@ -141,7 +141,7 @@ func TestGetDataWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0035Version with multiple inv vectors. @@ -149,7 +149,7 @@ func TestGetDataWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version no inv vectors. @@ -157,7 +157,7 @@ func TestGetDataWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version BIP0031Version with multiple inv vectors. @@ -165,7 +165,7 @@ func TestGetDataWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion no inv vectors. @@ -173,7 +173,7 @@ func TestGetDataWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion with multiple inv vectors. @@ -181,7 +181,7 @@ func TestGetDataWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion no inv vectors. @@ -189,7 +189,7 @@ func TestGetDataWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion with multiple inv vectors. @@ -197,7 +197,7 @@ func TestGetDataWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -217,7 +217,7 @@ func TestGetDataWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgGetData + var msg wire.MsgGetData rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -235,20 +235,20 @@ func TestGetDataWire(t *testing.T) { // TestGetDataWireErrors performs negative tests against wire encode and decode // of MsgGetData to confirm error paths work correctly. func TestGetDataWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - btcwireErr := &btcwire.MessageError{} + pver := wire.ProtocolVersion + wireErr := &wire.MessageError{} // Block 203707 hash. hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" - blockHash, err := btcwire.NewShaHashFromStr(hashStr) + blockHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) + iv := wire.NewInvVect(wire.InvTypeBlock, blockHash) // Base message used to induce errors. - baseGetData := btcwire.NewMsgGetData() + baseGetData := wire.NewMsgGetData() baseGetData.AddInvVect(iv) baseGetDataEncoded := []byte{ 0x02, // Varint for number of inv vectors @@ -261,8 +261,8 @@ func TestGetDataWireErrors(t *testing.T) { // Message that forces an error by having more than the max allowed inv // vectors. - maxGetData := btcwire.NewMsgGetData() - for i := 0; i < btcwire.MaxInvPerMsg; i++ { + maxGetData := wire.NewMsgGetData() + for i := 0; i < wire.MaxInvPerMsg; i++ { maxGetData.AddInvVect(iv) } maxGetData.InvList = append(maxGetData.InvList, iv) @@ -271,12 +271,12 @@ func TestGetDataWireErrors(t *testing.T) { } tests := []struct { - in *btcwire.MsgGetData // 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 + in *wire.MsgGetData // 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 error in inventory vector count @@ -284,7 +284,7 @@ func TestGetDataWireErrors(t *testing.T) { // Force error in inventory list. {baseGetData, baseGetDataEncoded, pver, 1, io.ErrShortWrite, io.EOF}, // Force error with greater than max inventory vectors. - {maxGetData, maxGetDataEncoded, pver, 3, btcwireErr, btcwireErr}, + {maxGetData, maxGetDataEncoded, pver, 3, wireErr, wireErr}, } t.Logf("Running %d tests", len(tests)) @@ -298,9 +298,9 @@ func TestGetDataWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -309,7 +309,7 @@ func TestGetDataWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgGetData + var msg wire.MsgGetData r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -318,9 +318,9 @@ func TestGetDataWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msggetheaders.go b/wire/msggetheaders.go similarity index 98% rename from msggetheaders.go rename to wire/msggetheaders.go index e407f4d9..4b407072 100644 --- a/msggetheaders.go +++ b/wire/msggetheaders.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msggetheaders_test.go b/wire/msggetheaders_test.go similarity index 82% rename from msggetheaders_test.go rename to wire/msggetheaders_test.go index 01e99493..3747aa9d 100644 --- a/msggetheaders_test.go +++ b/wire/msggetheaders_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,24 +10,24 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestGetHeaders tests the MsgGetHeader API. func TestGetHeaders(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Block 99500 hash. hashStr := "000000000002e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" - locatorHash, err := btcwire.NewShaHashFromStr(hashStr) + locatorHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Ensure the command is expected value. wantCmd := "getheaders" - msg := btcwire.NewMsgGetHeaders() + msg := wire.NewMsgGetHeaders() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgGetHeaders: wrong command - got %v want %v", cmd, wantCmd) @@ -58,7 +58,7 @@ func TestGetHeaders(t *testing.T) { // Ensure adding more than the max allowed block locator hashes per // message returns an error. - for i := 0; i < btcwire.MaxBlockLocatorsPerMsg; i++ { + for i := 0; i < wire.MaxBlockLocatorsPerMsg; i++ { err = msg.AddBlockLocatorHash(locatorHash) } if err == nil { @@ -79,27 +79,27 @@ func TestGetHeadersWire(t *testing.T) { // Block 99499 hash. hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535" - hashLocator, err := btcwire.NewShaHashFromStr(hashStr) + hashLocator, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Block 99500 hash. hashStr = "2e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" - hashLocator2, err := btcwire.NewShaHashFromStr(hashStr) + hashLocator2, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Block 100000 hash. hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" - hashStop, err := btcwire.NewShaHashFromStr(hashStr) + hashStop, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // MsgGetHeaders message with no block locators or stop hash. - noLocators := btcwire.NewMsgGetHeaders() + noLocators := wire.NewMsgGetHeaders() noLocators.ProtocolVersion = pver noLocatorsEncoded := []byte{ 0x62, 0xea, 0x00, 0x00, // Protocol version 60002 @@ -111,7 +111,7 @@ func TestGetHeadersWire(t *testing.T) { } // MsgGetHeaders message with multiple block locators and a stop hash. - multiLocators := btcwire.NewMsgGetHeaders() + multiLocators := wire.NewMsgGetHeaders() multiLocators.ProtocolVersion = pver multiLocators.HashStop = *hashStop multiLocators.AddBlockLocatorHash(hashLocator2) @@ -134,17 +134,17 @@ func TestGetHeadersWire(t *testing.T) { } tests := []struct { - in *btcwire.MsgGetHeaders // Message to encode - out *btcwire.MsgGetHeaders // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgGetHeaders // Message to encode + out *wire.MsgGetHeaders // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version with no block locators. { noLocators, noLocators, noLocatorsEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version with multiple block locators. @@ -152,7 +152,7 @@ func TestGetHeadersWire(t *testing.T) { multiLocators, multiLocators, multiLocatorsEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version with no block locators. @@ -160,7 +160,7 @@ func TestGetHeadersWire(t *testing.T) { noLocators, noLocators, noLocatorsEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0035Version with multiple block locators. @@ -168,7 +168,7 @@ func TestGetHeadersWire(t *testing.T) { multiLocators, multiLocators, multiLocatorsEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version with no block locators. @@ -176,7 +176,7 @@ func TestGetHeadersWire(t *testing.T) { noLocators, noLocators, noLocatorsEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version BIP0031Versionwith multiple block locators. @@ -184,7 +184,7 @@ func TestGetHeadersWire(t *testing.T) { multiLocators, multiLocators, multiLocatorsEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion with no block locators. @@ -192,7 +192,7 @@ func TestGetHeadersWire(t *testing.T) { noLocators, noLocators, noLocatorsEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion multiple block locators. @@ -200,7 +200,7 @@ func TestGetHeadersWire(t *testing.T) { multiLocators, multiLocators, multiLocatorsEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion with no block locators. @@ -208,7 +208,7 @@ func TestGetHeadersWire(t *testing.T) { noLocators, noLocators, noLocatorsEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion multiple block locators. @@ -216,7 +216,7 @@ func TestGetHeadersWire(t *testing.T) { multiLocators, multiLocators, multiLocatorsEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -236,7 +236,7 @@ func TestGetHeadersWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgGetHeaders + var msg wire.MsgGetHeaders rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -258,31 +258,31 @@ func TestGetHeadersWireErrors(t *testing.T) { // specifically here instead of the latest because the test data is // using bytes encoded with that protocol version. pver := uint32(60002) - btcwireErr := &btcwire.MessageError{} + wireErr := &wire.MessageError{} // Block 99499 hash. hashStr := "2710f40c87ec93d010a6fd95f42c59a2cbacc60b18cf6b7957535" - hashLocator, err := btcwire.NewShaHashFromStr(hashStr) + hashLocator, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Block 99500 hash. hashStr = "2e7ad7b9eef9479e4aabc65cb831269cc20d2632c13684406dee0" - hashLocator2, err := btcwire.NewShaHashFromStr(hashStr) + hashLocator2, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Block 100000 hash. hashStr = "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" - hashStop, err := btcwire.NewShaHashFromStr(hashStr) + hashStop, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // MsgGetHeaders message with multiple block locators and a stop hash. - baseGetHeaders := btcwire.NewMsgGetHeaders() + baseGetHeaders := wire.NewMsgGetHeaders() baseGetHeaders.ProtocolVersion = pver baseGetHeaders.HashStop = *hashStop baseGetHeaders.AddBlockLocatorHash(hashLocator2) @@ -306,8 +306,8 @@ func TestGetHeadersWireErrors(t *testing.T) { // Message that forces an error by having more than the max allowed // block locator hashes. - maxGetHeaders := btcwire.NewMsgGetHeaders() - for i := 0; i < btcwire.MaxBlockLocatorsPerMsg; i++ { + maxGetHeaders := wire.NewMsgGetHeaders() + for i := 0; i < wire.MaxBlockLocatorsPerMsg; i++ { maxGetHeaders.AddBlockLocatorHash(&mainNetGenesisHash) } maxGetHeaders.BlockLocatorHashes = append(maxGetHeaders.BlockLocatorHashes, @@ -318,12 +318,12 @@ func TestGetHeadersWireErrors(t *testing.T) { } tests := []struct { - in *btcwire.MsgGetHeaders // 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 + in *wire.MsgGetHeaders // 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 protocol version. {baseGetHeaders, baseGetHeadersEncoded, pver, 0, io.ErrShortWrite, io.EOF}, @@ -334,7 +334,7 @@ func TestGetHeadersWireErrors(t *testing.T) { // Force error in stop hash. {baseGetHeaders, baseGetHeadersEncoded, pver, 69, io.ErrShortWrite, io.EOF}, // Force error with greater than max block locator hashes. - {maxGetHeaders, maxGetHeadersEncoded, pver, 7, btcwireErr, btcwireErr}, + {maxGetHeaders, maxGetHeadersEncoded, pver, 7, wireErr, wireErr}, } t.Logf("Running %d tests", len(tests)) @@ -348,9 +348,9 @@ func TestGetHeadersWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -359,7 +359,7 @@ func TestGetHeadersWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgGetHeaders + var msg wire.MsgGetHeaders r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -368,9 +368,9 @@ func TestGetHeadersWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msgheaders.go b/wire/msgheaders.go similarity index 98% rename from msgheaders.go rename to wire/msgheaders.go index c895b6a4..603d94ee 100644 --- a/msgheaders.go +++ b/wire/msgheaders.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msgheaders_test.go b/wire/msgheaders_test.go similarity index 80% rename from msgheaders_test.go rename to wire/msgheaders_test.go index c7912355..afbcf6fb 100644 --- a/msgheaders_test.go +++ b/wire/msgheaders_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,7 +10,7 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) @@ -20,7 +20,7 @@ func TestHeaders(t *testing.T) { // Ensure the command is expected value. wantCmd := "headers" - msg := btcwire.NewMsgHeaders() + msg := wire.NewMsgHeaders() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgHeaders: wrong command - got %v want %v", cmd, wantCmd) @@ -49,10 +49,10 @@ func TestHeaders(t *testing.T) { // Ensure adding more than the max allowed headers per message returns // error. var err error - for i := 0; i < btcwire.MaxBlockHeadersPerMsg+1; i++ { + for i := 0; i < wire.MaxBlockHeadersPerMsg+1; i++ { err = msg.AddBlockHeader(bh) } - if reflect.TypeOf(err) != reflect.TypeOf(&btcwire.MessageError{}) { + if reflect.TypeOf(err) != reflect.TypeOf(&wire.MessageError{}) { t.Errorf("AddBlockHeader: expected error on too many headers " + "not received") } @@ -67,18 +67,18 @@ func TestHeadersWire(t *testing.T) { merkleHash := blockOne.Header.MerkleRoot bits := uint32(0x1d00ffff) nonce := uint32(0x9962e301) - bh := btcwire.NewBlockHeader(&hash, &merkleHash, bits, nonce) + bh := wire.NewBlockHeader(&hash, &merkleHash, bits, nonce) bh.Version = blockOne.Header.Version bh.Timestamp = blockOne.Header.Timestamp // Empty headers message. - noHeaders := btcwire.NewMsgHeaders() + noHeaders := wire.NewMsgHeaders() noHeadersEncoded := []byte{ 0x00, // Varint for number of headers } // Headers message with one header. - oneHeader := btcwire.NewMsgHeaders() + oneHeader := wire.NewMsgHeaders() oneHeader.AddBlockHeader(bh) oneHeaderEncoded := []byte{ 0x01, // VarInt for number of headers. @@ -98,17 +98,17 @@ func TestHeadersWire(t *testing.T) { } tests := []struct { - in *btcwire.MsgHeaders // Message to encode - out *btcwire.MsgHeaders // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgHeaders // Message to encode + out *wire.MsgHeaders // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version with no headers. { noHeaders, noHeaders, noHeadersEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version with one header. @@ -116,7 +116,7 @@ func TestHeadersWire(t *testing.T) { oneHeader, oneHeader, oneHeaderEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version with no headers. @@ -124,7 +124,7 @@ func TestHeadersWire(t *testing.T) { noHeaders, noHeaders, noHeadersEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0035Version with one header. @@ -132,7 +132,7 @@ func TestHeadersWire(t *testing.T) { oneHeader, oneHeader, oneHeaderEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version with no headers. @@ -140,7 +140,7 @@ func TestHeadersWire(t *testing.T) { noHeaders, noHeaders, noHeadersEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version BIP0031Version with one header. @@ -148,14 +148,14 @@ func TestHeadersWire(t *testing.T) { oneHeader, oneHeader, oneHeaderEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion with no headers. { noHeaders, noHeaders, noHeadersEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion with one header. @@ -163,7 +163,7 @@ func TestHeadersWire(t *testing.T) { oneHeader, oneHeader, oneHeaderEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion with no headers. @@ -171,7 +171,7 @@ func TestHeadersWire(t *testing.T) { noHeaders, noHeaders, noHeadersEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion with one header. @@ -179,7 +179,7 @@ func TestHeadersWire(t *testing.T) { oneHeader, oneHeader, oneHeaderEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -199,7 +199,7 @@ func TestHeadersWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgHeaders + var msg wire.MsgHeaders rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -217,19 +217,19 @@ func TestHeadersWire(t *testing.T) { // TestHeadersWireErrors performs negative tests against wire encode and decode // of MsgHeaders to confirm error paths work correctly. func TestHeadersWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - btcwireErr := &btcwire.MessageError{} + pver := wire.ProtocolVersion + wireErr := &wire.MessageError{} hash := mainNetGenesisHash merkleHash := blockOne.Header.MerkleRoot bits := uint32(0x1d00ffff) nonce := uint32(0x9962e301) - bh := btcwire.NewBlockHeader(&hash, &merkleHash, bits, nonce) + bh := wire.NewBlockHeader(&hash, &merkleHash, bits, nonce) bh.Version = blockOne.Header.Version bh.Timestamp = blockOne.Header.Timestamp // Headers message with one header. - oneHeader := btcwire.NewMsgHeaders() + oneHeader := wire.NewMsgHeaders() oneHeader.AddBlockHeader(bh) oneHeaderEncoded := []byte{ 0x01, // VarInt for number of headers. @@ -250,8 +250,8 @@ func TestHeadersWireErrors(t *testing.T) { // Message that forces an error by having more than the max allowed // headers. - maxHeaders := btcwire.NewMsgHeaders() - for i := 0; i < btcwire.MaxBlockHeadersPerMsg; i++ { + maxHeaders := wire.NewMsgHeaders() + for i := 0; i < wire.MaxBlockHeadersPerMsg; i++ { maxHeaders.AddBlockHeader(bh) } maxHeaders.Headers = append(maxHeaders.Headers, bh) @@ -261,11 +261,11 @@ func TestHeadersWireErrors(t *testing.T) { // Intentionally invalid block header that has a transaction count used // to force errors. - bhTrans := btcwire.NewBlockHeader(&hash, &merkleHash, bits, nonce) + bhTrans := wire.NewBlockHeader(&hash, &merkleHash, bits, nonce) bhTrans.Version = blockOne.Header.Version bhTrans.Timestamp = blockOne.Header.Timestamp - transHeader := btcwire.NewMsgHeaders() + transHeader := wire.NewMsgHeaders() transHeader.AddBlockHeader(bhTrans) transHeaderEncoded := []byte{ 0x01, // VarInt for number of headers. @@ -285,12 +285,12 @@ func TestHeadersWireErrors(t *testing.T) { } tests := []struct { - in *btcwire.MsgHeaders // 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 + in *wire.MsgHeaders // 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 error in header count. @@ -298,11 +298,11 @@ func TestHeadersWireErrors(t *testing.T) { // Force error in block header. {oneHeader, oneHeaderEncoded, pver, 5, io.ErrShortWrite, io.EOF}, // Force error with greater than max headers. - {maxHeaders, maxHeadersEncoded, pver, 3, btcwireErr, btcwireErr}, + {maxHeaders, maxHeadersEncoded, pver, 3, wireErr, wireErr}, // Force error with number of transactions. {transHeader, transHeaderEncoded, pver, 81, io.ErrShortWrite, io.EOF}, // Force error with included transactions. - {transHeader, transHeaderEncoded, pver, len(transHeaderEncoded), nil, btcwireErr}, + {transHeader, transHeaderEncoded, pver, len(transHeaderEncoded), nil, wireErr}, } t.Logf("Running %d tests", len(tests)) @@ -316,9 +316,9 @@ func TestHeadersWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -327,7 +327,7 @@ func TestHeadersWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgHeaders + var msg wire.MsgHeaders r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -336,9 +336,9 @@ func TestHeadersWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msginv.go b/wire/msginv.go similarity index 98% rename from msginv.go rename to wire/msginv.go index 1cf9a261..4dca9dd7 100644 --- a/msginv.go +++ b/wire/msginv.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msginv_test.go b/wire/msginv_test.go similarity index 77% rename from msginv_test.go rename to wire/msginv_test.go index 4b8cd4d1..f7bec092 100644 --- a/msginv_test.go +++ b/wire/msginv_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,17 +10,17 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestInv tests the MsgInv API. func TestInv(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Ensure the command is expected value. wantCmd := "inv" - msg := btcwire.NewMsgInv() + msg := wire.NewMsgInv() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgInv: wrong command - got %v want %v", cmd, wantCmd) @@ -37,8 +37,8 @@ func TestInv(t *testing.T) { } // Ensure inventory vectors are added properly. - hash := btcwire.ShaHash{} - iv := btcwire.NewInvVect(btcwire.InvTypeBlock, &hash) + hash := wire.ShaHash{} + iv := wire.NewInvVect(wire.InvTypeBlock, &hash) err := msg.AddInvVect(iv) if err != nil { t.Errorf("AddInvVect: %v", err) @@ -50,7 +50,7 @@ func TestInv(t *testing.T) { // Ensure adding more than the max allowed inventory vectors per // message returns an error. - for i := 0; i < btcwire.MaxInvPerMsg; i++ { + for i := 0; i < wire.MaxInvPerMsg; i++ { err = msg.AddInvVect(iv) } if err == nil { @@ -60,8 +60,8 @@ func TestInv(t *testing.T) { // Ensure creating the message with a size hint larger than the max // works as expected. - msg = btcwire.NewMsgInvSizeHint(btcwire.MaxInvPerMsg + 1) - wantCap := btcwire.MaxInvPerMsg + msg = wire.NewMsgInvSizeHint(wire.MaxInvPerMsg + 1) + wantCap := wire.MaxInvPerMsg if cap(msg.InvList) != wantCap { t.Errorf("NewMsgInvSizeHint: wrong cap for size hint - "+ "got %v, want %v", cap(msg.InvList), wantCap) @@ -75,29 +75,29 @@ func TestInv(t *testing.T) { func TestInvWire(t *testing.T) { // Block 203707 hash. hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" - blockHash, err := btcwire.NewShaHashFromStr(hashStr) + blockHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Transation 1 of Block 203707 hash. hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0" - txHash, err := btcwire.NewShaHashFromStr(hashStr) + txHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) - iv2 := btcwire.NewInvVect(btcwire.InvTypeTx, txHash) + iv := wire.NewInvVect(wire.InvTypeBlock, blockHash) + iv2 := wire.NewInvVect(wire.InvTypeTx, txHash) // Empty inv message. - NoInv := btcwire.NewMsgInv() + NoInv := wire.NewMsgInv() NoInvEncoded := []byte{ 0x00, // Varint for number of inventory vectors } // Inv message with multiple inventory vectors. - MultiInv := btcwire.NewMsgInv() + MultiInv := wire.NewMsgInv() MultiInv.AddInvVect(iv) MultiInv.AddInvVect(iv2) MultiInvEncoded := []byte{ @@ -115,17 +115,17 @@ func TestInvWire(t *testing.T) { } tests := []struct { - in *btcwire.MsgInv // Message to encode - out *btcwire.MsgInv // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgInv // Message to encode + out *wire.MsgInv // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version with no inv vectors. { NoInv, NoInv, NoInvEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version with multiple inv vectors. @@ -133,7 +133,7 @@ func TestInvWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version no inv vectors. @@ -141,7 +141,7 @@ func TestInvWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0035Version with multiple inv vectors. @@ -149,7 +149,7 @@ func TestInvWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version no inv vectors. @@ -157,7 +157,7 @@ func TestInvWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version BIP0031Version with multiple inv vectors. @@ -165,7 +165,7 @@ func TestInvWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion no inv vectors. @@ -173,7 +173,7 @@ func TestInvWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion with multiple inv vectors. @@ -181,7 +181,7 @@ func TestInvWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion no inv vectors. @@ -189,7 +189,7 @@ func TestInvWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion with multiple inv vectors. @@ -197,7 +197,7 @@ func TestInvWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -217,7 +217,7 @@ func TestInvWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgInv + var msg wire.MsgInv rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -235,20 +235,20 @@ func TestInvWire(t *testing.T) { // TestInvWireErrors performs negative tests against wire encode and decode // of MsgInv to confirm error paths work correctly. func TestInvWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - btcwireErr := &btcwire.MessageError{} + pver := wire.ProtocolVersion + wireErr := &wire.MessageError{} // Block 203707 hash. hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" - blockHash, err := btcwire.NewShaHashFromStr(hashStr) + blockHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) + iv := wire.NewInvVect(wire.InvTypeBlock, blockHash) // Base inv message used to induce errors. - baseInv := btcwire.NewMsgInv() + baseInv := wire.NewMsgInv() baseInv.AddInvVect(iv) baseInvEncoded := []byte{ 0x02, // Varint for number of inv vectors @@ -261,8 +261,8 @@ func TestInvWireErrors(t *testing.T) { // Inv message that forces an error by having more than the max allowed // inv vectors. - maxInv := btcwire.NewMsgInv() - for i := 0; i < btcwire.MaxInvPerMsg; i++ { + maxInv := wire.NewMsgInv() + for i := 0; i < wire.MaxInvPerMsg; i++ { maxInv.AddInvVect(iv) } maxInv.InvList = append(maxInv.InvList, iv) @@ -271,12 +271,12 @@ func TestInvWireErrors(t *testing.T) { } tests := []struct { - in *btcwire.MsgInv // 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 + in *wire.MsgInv // 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 error in inventory vector count @@ -284,7 +284,7 @@ func TestInvWireErrors(t *testing.T) { // Force error in inventory list. {baseInv, baseInvEncoded, pver, 1, io.ErrShortWrite, io.EOF}, // Force error with greater than max inventory vectors. - {maxInv, maxInvEncoded, pver, 3, btcwireErr, btcwireErr}, + {maxInv, maxInvEncoded, pver, 3, wireErr, wireErr}, } t.Logf("Running %d tests", len(tests)) @@ -298,9 +298,9 @@ func TestInvWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -309,7 +309,7 @@ func TestInvWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgInv + var msg wire.MsgInv r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -318,9 +318,9 @@ func TestInvWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msgmempool.go b/wire/msgmempool.go similarity index 96% rename from msgmempool.go rename to wire/msgmempool.go index 376b8786..74945f42 100644 --- a/msgmempool.go +++ b/wire/msgmempool.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msgmempool_test.go b/wire/msgmempool_test.go similarity index 86% rename from msgmempool_test.go rename to wire/msgmempool_test.go index 64e23317..cf2659a2 100644 --- a/msgmempool_test.go +++ b/wire/msgmempool_test.go @@ -1,22 +1,22 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" ) func TestMemPool(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Ensure the command is expected value. wantCmd := "mempool" - msg := btcwire.NewMsgMemPool() + msg := wire.NewMsgMemPool() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgMemPool: wrong command - got %v want %v", cmd, wantCmd) @@ -40,7 +40,7 @@ func TestMemPool(t *testing.T) { // Older protocol versions should fail encode since message didn't // exist yet. - oldPver := btcwire.BIP0035Version - 1 + oldPver := wire.BIP0035Version - 1 err = msg.BtcEncode(&buf, oldPver) if err == nil { s := "encode of MsgMemPool passed for old protocol version %v err <%v>" @@ -48,7 +48,7 @@ func TestMemPool(t *testing.T) { } // Test decode with latest protocol version. - readmsg := btcwire.NewMsgMemPool() + readmsg := wire.NewMsgMemPool() err = readmsg.BtcDecode(&buf, pver) if err != nil { t.Errorf("decode of MsgMemPool failed [%v] err <%v>", buf, err) diff --git a/msgmerkleblock.go b/wire/msgmerkleblock.go similarity index 98% rename from msgmerkleblock.go rename to wire/msgmerkleblock.go index dcdcae99..a9086b62 100644 --- a/msgmerkleblock.go +++ b/wire/msgmerkleblock.go @@ -1,8 +1,8 @@ -// Copyright (c) 2014 Conformal Systems LLC. +// Copyright (c) 2014-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msgmerkleblock_test.go b/wire/msgmerkleblock_test.go similarity index 82% rename from msgmerkleblock_test.go rename to wire/msgmerkleblock_test.go index 5d77af07..e2bde90b 100644 --- a/msgmerkleblock_test.go +++ b/wire/msgmerkleblock_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2014 Conformal Systems LLC. +// Copyright (c) 2014-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -12,24 +12,24 @@ import ( "testing" "time" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestMerkleBlock tests the MsgMerkleBlock API. func TestMerkleBlock(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // 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) + bh := wire.NewBlockHeader(prevHash, merkleHash, bits, nonce) // Ensure the command is expected value. wantCmd := "merkleblock" - msg := btcwire.NewMsgMerkleBlock(bh) + msg := wire.NewMsgMerkleBlock(bh) if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgBlock: wrong command - got %v want %v", cmd, wantCmd) @@ -47,9 +47,9 @@ func TestMerkleBlock(t *testing.T) { // Load maxTxPerBlock hashes data := make([]byte, 32) - for i := 0; i < btcwire.MaxTxPerBlock; i++ { + for i := 0; i < wire.MaxTxPerBlock; i++ { rand.Read(data) - hash, err := btcwire.NewShaHash(data) + hash, err := wire.NewShaHash(data) if err != nil { t.Errorf("NewShaHash failed: %v\n", err) return @@ -63,7 +63,7 @@ func TestMerkleBlock(t *testing.T) { // Add one more Tx to test failure. rand.Read(data) - hash, err := btcwire.NewShaHash(data) + hash, err := wire.NewShaHash(data) if err != nil { t.Errorf("NewShaHash failed: %v\n", err) return @@ -82,7 +82,7 @@ func TestMerkleBlock(t *testing.T) { } // Test decode with latest protocol version. - readmsg := btcwire.MsgMerkleBlock{} + readmsg := wire.MsgMerkleBlock{} err = readmsg.BtcDecode(&buf, pver) if err != nil { t.Errorf("decode of MsgMerkleBlock failed [%v] err <%v>", buf, err) @@ -100,7 +100,7 @@ func TestMerkleBlock(t *testing.T) { // 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) + msg.Flags = make([]byte, wire.MaxFlagsPerMerkleBlock+1) err = msg.BtcEncode(&buf, pver) if err == nil { t.Errorf("encode of MsgMerkleBlock succeeded with too many " + @@ -117,21 +117,21 @@ func TestMerkleBlockCrossProtocol(t *testing.T) { merkleHash := &blockOne.Header.MerkleRoot bits := blockOne.Header.Bits nonce := blockOne.Header.Nonce - bh := btcwire.NewBlockHeader(prevHash, merkleHash, bits, nonce) + bh := wire.NewBlockHeader(prevHash, merkleHash, bits, nonce) - msg := btcwire.NewMsgMerkleBlock(bh) + msg := wire.NewMsgMerkleBlock(bh) // Encode with latest protocol version. var buf bytes.Buffer - err := msg.BtcEncode(&buf, btcwire.ProtocolVersion) + err := msg.BtcEncode(&buf, wire.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) + var readmsg wire.MsgFilterLoad + err = readmsg.BtcDecode(&buf, wire.BIP0031Version) if err == nil { t.Errorf("decode of MsgFilterLoad succeeded when it shouldn't have %v", msg) @@ -142,21 +142,21 @@ func TestMerkleBlockCrossProtocol(t *testing.T) { // 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 + in *wire.MsgMerkleBlock // Message to encode + out *wire.MsgMerkleBlock // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { &merkleBlockOne, &merkleBlockOne, merkleBlockOneBytes, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0037Version. { &merkleBlockOne, &merkleBlockOne, merkleBlockOneBytes, - btcwire.BIP0037Version, + wire.BIP0037Version, }, } @@ -176,7 +176,7 @@ func TestMerkleBlockWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgMerkleBlock + var msg wire.MsgMerkleBlock rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -198,16 +198,16 @@ func TestMerkleBlockWireErrors(t *testing.T) { // because the test data is using bytes encoded with that protocol // version. pver := uint32(70001) - pverNoMerkleBlock := btcwire.BIP0037Version - 1 - btcwireErr := &btcwire.MessageError{} + pverNoMerkleBlock := wire.BIP0037Version - 1 + wireErr := &wire.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 + in *wire.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. { @@ -267,7 +267,7 @@ func TestMerkleBlockWireErrors(t *testing.T) { // Force error due to unsupported protocol version. { &merkleBlockOne, merkleBlockOneBytes, pverNoMerkleBlock, - 119, btcwireErr, btcwireErr, + 119, wireErr, wireErr, }, } @@ -282,9 +282,9 @@ func TestMerkleBlockWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -293,7 +293,7 @@ func TestMerkleBlockWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgMerkleBlock + var msg wire.MsgMerkleBlock r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -302,9 +302,9 @@ func TestMerkleBlockWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) @@ -327,7 +327,7 @@ func TestMerkleBlockOverflowErrors(t *testing.T) { // 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) + wire.TstWriteVarInt(&buf, pver, wire.MaxTxPerBlock+1) numHashesOffset := 84 exceedMaxHashes := make([]byte, numHashesOffset) copy(exceedMaxHashes, merkleBlockOneBytes[:numHashesOffset]) @@ -336,7 +336,7 @@ func TestMerkleBlockOverflowErrors(t *testing.T) { // 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) + wire.TstWriteVarInt(&buf, pver, wire.MaxFlagsPerMerkleBlock+1) numFlagBytesOffset := 117 exceedMaxFlagBytes := make([]byte, numFlagBytesOffset) copy(exceedMaxFlagBytes, merkleBlockOneBytes[:numFlagBytesOffset]) @@ -348,15 +348,15 @@ func TestMerkleBlockOverflowErrors(t *testing.T) { err error // Expected error }{ // Block that claims to have more than max allowed hashes. - {exceedMaxHashes, pver, &btcwire.MessageError{}}, + {exceedMaxHashes, pver, &wire.MessageError{}}, // Block that claims to have more than max allowed flag bytes. - {exceedMaxFlagBytes, pver, &btcwire.MessageError{}}, + {exceedMaxFlagBytes, pver, &wire.MessageError{}}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Decode from wire format. - var msg btcwire.MsgMerkleBlock + var msg wire.MsgMerkleBlock r := bytes.NewReader(test.buf) err := msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { @@ -369,16 +369,16 @@ func TestMerkleBlockOverflowErrors(t *testing.T) { // 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{ +var merkleBlockOne = wire.MsgMerkleBlock{ + Header: wire.BlockHeader{ Version: 1, - PrevBlock: btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. + PrevBlock: wire.ShaHash([wire.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. + MerkleRoot: wire.ShaHash([wire.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, @@ -389,8 +389,8 @@ var merkleBlockOne = btcwire.MsgMerkleBlock{ Nonce: 0x9962e301, // 2573394689 }, Transactions: 1, - Hashes: []*btcwire.ShaHash{ - (*btcwire.ShaHash)(&[btcwire.HashSize]byte{ // Make go vet happy. + Hashes: []*wire.ShaHash{ + (*wire.ShaHash)(&[wire.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, diff --git a/msgnotfound.go b/wire/msgnotfound.go similarity index 97% rename from msgnotfound.go rename to wire/msgnotfound.go index 3c18b77d..fc1cd6fc 100644 --- a/msgnotfound.go +++ b/wire/msgnotfound.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msgnotfound_test.go b/wire/msgnotfound_test.go similarity index 76% rename from msgnotfound_test.go rename to wire/msgnotfound_test.go index 5dd14e9e..e6311b9c 100644 --- a/msgnotfound_test.go +++ b/wire/msgnotfound_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,17 +10,17 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestNotFound tests the MsgNotFound API. func TestNotFound(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Ensure the command is expected value. wantCmd := "notfound" - msg := btcwire.NewMsgNotFound() + msg := wire.NewMsgNotFound() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgNotFound: wrong command - got %v want %v", cmd, wantCmd) @@ -37,8 +37,8 @@ func TestNotFound(t *testing.T) { } // Ensure inventory vectors are added properly. - hash := btcwire.ShaHash{} - iv := btcwire.NewInvVect(btcwire.InvTypeBlock, &hash) + hash := wire.ShaHash{} + iv := wire.NewInvVect(wire.InvTypeBlock, &hash) err := msg.AddInvVect(iv) if err != nil { t.Errorf("AddInvVect: %v", err) @@ -50,7 +50,7 @@ func TestNotFound(t *testing.T) { // Ensure adding more than the max allowed inventory vectors per // message returns an error. - for i := 0; i < btcwire.MaxInvPerMsg; i++ { + for i := 0; i < wire.MaxInvPerMsg; i++ { err = msg.AddInvVect(iv) } if err == nil { @@ -66,29 +66,29 @@ func TestNotFound(t *testing.T) { func TestNotFoundWire(t *testing.T) { // Block 203707 hash. hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" - blockHash, err := btcwire.NewShaHashFromStr(hashStr) + blockHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Transation 1 of Block 203707 hash. hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0" - txHash, err := btcwire.NewShaHashFromStr(hashStr) + txHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) - iv2 := btcwire.NewInvVect(btcwire.InvTypeTx, txHash) + iv := wire.NewInvVect(wire.InvTypeBlock, blockHash) + iv2 := wire.NewInvVect(wire.InvTypeTx, txHash) // Empty notfound message. - NoInv := btcwire.NewMsgNotFound() + NoInv := wire.NewMsgNotFound() NoInvEncoded := []byte{ 0x00, // Varint for number of inventory vectors } // NotFound message with multiple inventory vectors. - MultiInv := btcwire.NewMsgNotFound() + MultiInv := wire.NewMsgNotFound() MultiInv.AddInvVect(iv) MultiInv.AddInvVect(iv2) MultiInvEncoded := []byte{ @@ -106,17 +106,17 @@ func TestNotFoundWire(t *testing.T) { } tests := []struct { - in *btcwire.MsgNotFound // Message to encode - out *btcwire.MsgNotFound // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgNotFound // Message to encode + out *wire.MsgNotFound // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version with no inv vectors. { NoInv, NoInv, NoInvEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version with multiple inv vectors. @@ -124,7 +124,7 @@ func TestNotFoundWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version no inv vectors. @@ -132,7 +132,7 @@ func TestNotFoundWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0035Version with multiple inv vectors. @@ -140,7 +140,7 @@ func TestNotFoundWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version no inv vectors. @@ -148,7 +148,7 @@ func TestNotFoundWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version BIP0031Version with multiple inv vectors. @@ -156,7 +156,7 @@ func TestNotFoundWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion no inv vectors. @@ -164,7 +164,7 @@ func TestNotFoundWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion with multiple inv vectors. @@ -172,7 +172,7 @@ func TestNotFoundWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion no inv vectors. @@ -180,7 +180,7 @@ func TestNotFoundWire(t *testing.T) { NoInv, NoInv, NoInvEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion with multiple inv vectors. @@ -188,7 +188,7 @@ func TestNotFoundWire(t *testing.T) { MultiInv, MultiInv, MultiInvEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -208,7 +208,7 @@ func TestNotFoundWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgNotFound + var msg wire.MsgNotFound rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -226,20 +226,20 @@ func TestNotFoundWire(t *testing.T) { // TestNotFoundWireErrors performs negative tests against wire encode and decode // of MsgNotFound to confirm error paths work correctly. func TestNotFoundWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - btcwireErr := &btcwire.MessageError{} + pver := wire.ProtocolVersion + wireErr := &wire.MessageError{} // Block 203707 hash. hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc" - blockHash, err := btcwire.NewShaHashFromStr(hashStr) + blockHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } - iv := btcwire.NewInvVect(btcwire.InvTypeBlock, blockHash) + iv := wire.NewInvVect(wire.InvTypeBlock, blockHash) // Base message used to induce errors. - baseNotFound := btcwire.NewMsgNotFound() + baseNotFound := wire.NewMsgNotFound() baseNotFound.AddInvVect(iv) baseNotFoundEncoded := []byte{ 0x02, // Varint for number of inv vectors @@ -252,8 +252,8 @@ func TestNotFoundWireErrors(t *testing.T) { // Message that forces an error by having more than the max allowed inv // vectors. - maxNotFound := btcwire.NewMsgNotFound() - for i := 0; i < btcwire.MaxInvPerMsg; i++ { + maxNotFound := wire.NewMsgNotFound() + for i := 0; i < wire.MaxInvPerMsg; i++ { maxNotFound.AddInvVect(iv) } maxNotFound.InvList = append(maxNotFound.InvList, iv) @@ -262,19 +262,19 @@ func TestNotFoundWireErrors(t *testing.T) { } tests := []struct { - in *btcwire.MsgNotFound // 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 + in *wire.MsgNotFound // 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 inventory vector count {baseNotFound, baseNotFoundEncoded, pver, 0, io.ErrShortWrite, io.EOF}, // Force error in inventory list. {baseNotFound, baseNotFoundEncoded, pver, 1, io.ErrShortWrite, io.EOF}, // Force error with greater than max inventory vectors. - {maxNotFound, maxNotFoundEncoded, pver, 3, btcwireErr, btcwireErr}, + {maxNotFound, maxNotFoundEncoded, pver, 3, wireErr, wireErr}, } t.Logf("Running %d tests", len(tests)) @@ -288,9 +288,9 @@ func TestNotFoundWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -299,7 +299,7 @@ func TestNotFoundWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgNotFound + var msg wire.MsgNotFound r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -308,9 +308,9 @@ func TestNotFoundWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msgping.go b/wire/msgping.go similarity index 97% rename from msgping.go rename to wire/msgping.go index 58e54f63..33814a2d 100644 --- a/msgping.go +++ b/wire/msgping.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "io" diff --git a/msgping_test.go b/wire/msgping_test.go similarity index 76% rename from msgping_test.go rename to wire/msgping_test.go index b886a38d..f7087dd2 100644 --- a/msgping_test.go +++ b/wire/msgping_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,20 +10,20 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestPing tests the MsgPing API against the latest protocol version. func TestPing(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Ensure we get the same nonce back out. - nonce, err := btcwire.RandomUint64() + nonce, err := wire.RandomUint64() if err != nil { t.Errorf("RandomUint64: Error generating nonce: %v", err) } - msg := btcwire.NewMsgPing(nonce) + msg := wire.NewMsgPing(nonce) if msg.Nonce != nonce { t.Errorf("NewMsgPing: wrong nonce - got %v, want %v", msg.Nonce, nonce) @@ -52,13 +52,13 @@ func TestPing(t *testing.T) { // BIP0031Version. func TestPingBIP0031(t *testing.T) { // Use the protocol version just prior to BIP0031Version changes. - pver := btcwire.BIP0031Version + pver := wire.BIP0031Version - nonce, err := btcwire.RandomUint64() + nonce, err := wire.RandomUint64() if err != nil { t.Errorf("RandomUint64: Error generating nonce: %v", err) } - msg := btcwire.NewMsgPing(nonce) + msg := wire.NewMsgPing(nonce) if msg.Nonce != nonce { t.Errorf("NewMsgPing: wrong nonce - got %v, want %v", msg.Nonce, nonce) @@ -81,7 +81,7 @@ func TestPingBIP0031(t *testing.T) { } // Test decode with old protocol version. - readmsg := btcwire.NewMsgPing(0) + readmsg := wire.NewMsgPing(0) err = readmsg.BtcDecode(&buf, pver) if err != nil { t.Errorf("decode of MsgPing failed [%v] err <%v>", buf, err) @@ -99,11 +99,11 @@ func TestPingBIP0031(t *testing.T) { // TestPingCrossProtocol tests the MsgPing API when encoding with the latest // protocol version and decoding with BIP0031Version. func TestPingCrossProtocol(t *testing.T) { - nonce, err := btcwire.RandomUint64() + nonce, err := wire.RandomUint64() if err != nil { t.Errorf("RandomUint64: Error generating nonce: %v", err) } - msg := btcwire.NewMsgPing(nonce) + msg := wire.NewMsgPing(nonce) if msg.Nonce != nonce { t.Errorf("NewMsgPing: wrong nonce - got %v, want %v", msg.Nonce, nonce) @@ -111,14 +111,14 @@ func TestPingCrossProtocol(t *testing.T) { // Encode with latest protocol version. var buf bytes.Buffer - err = msg.BtcEncode(&buf, btcwire.ProtocolVersion) + err = msg.BtcEncode(&buf, wire.ProtocolVersion) if err != nil { t.Errorf("encode of MsgPing failed %v err <%v>", msg, err) } // Decode with old protocol version. - readmsg := btcwire.NewMsgPing(0) - err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version) + readmsg := wire.NewMsgPing(0) + err = readmsg.BtcDecode(&buf, wire.BIP0031Version) if err != nil { t.Errorf("decode of MsgPing failed [%v] err <%v>", buf, err) } @@ -134,33 +134,33 @@ func TestPingCrossProtocol(t *testing.T) { // versions. func TestPingWire(t *testing.T) { tests := []struct { - in btcwire.MsgPing // Message to encode - out btcwire.MsgPing // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in wire.MsgPing // Message to encode + out wire.MsgPing // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { - btcwire.MsgPing{Nonce: 123123}, // 0x1e0f3 - btcwire.MsgPing{Nonce: 123123}, // 0x1e0f3 + wire.MsgPing{Nonce: 123123}, // 0x1e0f3 + wire.MsgPing{Nonce: 123123}, // 0x1e0f3 []byte{0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0031Version+1 { - btcwire.MsgPing{Nonce: 456456}, // 0x6f708 - btcwire.MsgPing{Nonce: 456456}, // 0x6f708 + wire.MsgPing{Nonce: 456456}, // 0x6f708 + wire.MsgPing{Nonce: 456456}, // 0x6f708 []byte{0x08, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, - btcwire.BIP0031Version + 1, + wire.BIP0031Version + 1, }, // Protocol version BIP0031Version { - btcwire.MsgPing{Nonce: 789789}, // 0xc0d1d - btcwire.MsgPing{Nonce: 0}, // No nonce for pver - []byte{}, // No nonce for pver - btcwire.BIP0031Version, + wire.MsgPing{Nonce: 789789}, // 0xc0d1d + wire.MsgPing{Nonce: 0}, // No nonce for pver + []byte{}, // No nonce for pver + wire.BIP0031Version, }, } @@ -180,7 +180,7 @@ func TestPingWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgPing + var msg wire.MsgPing rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -198,19 +198,19 @@ func TestPingWire(t *testing.T) { // TestPingWireErrors performs negative tests against wire encode and decode // of MsgPing to confirm error paths work correctly. func TestPingWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion tests := []struct { - in *btcwire.MsgPing // 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 + in *wire.MsgPing // 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. { - &btcwire.MsgPing{Nonce: 123123}, // 0x1e0f3 + &wire.MsgPing{Nonce: 123123}, // 0x1e0f3 []byte{0xf3, 0xe0, 0x01, 0x00}, pver, 2, @@ -231,7 +231,7 @@ func TestPingWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgPing + var msg wire.MsgPing r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if err != test.readErr { diff --git a/msgpong.go b/wire/msgpong.go similarity index 97% rename from msgpong.go rename to wire/msgpong.go index 9bd0431a..1795feb9 100644 --- a/msgpong.go +++ b/wire/msgpong.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msgpong_test.go b/wire/msgpong_test.go similarity index 76% rename from msgpong_test.go rename to wire/msgpong_test.go index 5d1f6cff..8b9a8e6f 100644 --- a/msgpong_test.go +++ b/wire/msgpong_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,19 +10,19 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestPongLatest tests the MsgPong API against the latest protocol version. func TestPongLatest(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion - nonce, err := btcwire.RandomUint64() + nonce, err := wire.RandomUint64() if err != nil { t.Errorf("RandomUint64: error generating nonce: %v", err) } - msg := btcwire.NewMsgPong(nonce) + msg := wire.NewMsgPong(nonce) if msg.Nonce != nonce { t.Errorf("NewMsgPong: wrong nonce - got %v, want %v", msg.Nonce, nonce) @@ -52,7 +52,7 @@ func TestPongLatest(t *testing.T) { } // Test decode with latest protocol version. - readmsg := btcwire.NewMsgPong(0) + readmsg := wire.NewMsgPong(0) err = readmsg.BtcDecode(&buf, pver) if err != nil { t.Errorf("decode of MsgPong failed [%v] err <%v>", buf, err) @@ -70,13 +70,13 @@ func TestPongLatest(t *testing.T) { // BIP0031Version. func TestPongBIP0031(t *testing.T) { // Use the protocol version just prior to BIP0031Version changes. - pver := btcwire.BIP0031Version + pver := wire.BIP0031Version - nonce, err := btcwire.RandomUint64() + nonce, err := wire.RandomUint64() if err != nil { t.Errorf("Error generating nonce: %v", err) } - msg := btcwire.NewMsgPong(nonce) + msg := wire.NewMsgPong(nonce) if msg.Nonce != nonce { t.Errorf("Should get same nonce back out.") } @@ -97,7 +97,7 @@ func TestPongBIP0031(t *testing.T) { } // Test decode with old protocol version. - readmsg := btcwire.NewMsgPong(0) + readmsg := wire.NewMsgPong(0) err = readmsg.BtcDecode(&buf, pver) if err == nil { t.Errorf("decode of MsgPong succeeded when it shouldn't have %v", @@ -116,25 +116,25 @@ func TestPongBIP0031(t *testing.T) { // TestPongCrossProtocol tests the MsgPong API when encoding with the latest // protocol version and decoding with BIP0031Version. func TestPongCrossProtocol(t *testing.T) { - nonce, err := btcwire.RandomUint64() + nonce, err := wire.RandomUint64() if err != nil { t.Errorf("Error generating nonce: %v", err) } - msg := btcwire.NewMsgPong(nonce) + msg := wire.NewMsgPong(nonce) if msg.Nonce != nonce { t.Errorf("Should get same nonce back out.") } // Encode with latest protocol version. var buf bytes.Buffer - err = msg.BtcEncode(&buf, btcwire.ProtocolVersion) + err = msg.BtcEncode(&buf, wire.ProtocolVersion) if err != nil { t.Errorf("encode of MsgPong failed %v err <%v>", msg, err) } // Decode with old protocol version. - readmsg := btcwire.NewMsgPong(0) - err = readmsg.BtcDecode(&buf, btcwire.BIP0031Version) + readmsg := wire.NewMsgPong(0) + err = readmsg.BtcDecode(&buf, wire.BIP0031Version) if err == nil { t.Errorf("encode of MsgPong succeeded when it shouldn't have %v", msg) @@ -151,25 +151,25 @@ func TestPongCrossProtocol(t *testing.T) { // versions. func TestPongWire(t *testing.T) { tests := []struct { - in btcwire.MsgPong // Message to encode - out btcwire.MsgPong // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in wire.MsgPong // Message to encode + out wire.MsgPong // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { - btcwire.MsgPong{Nonce: 123123}, // 0x1e0f3 - btcwire.MsgPong{Nonce: 123123}, // 0x1e0f3 + wire.MsgPong{Nonce: 123123}, // 0x1e0f3 + wire.MsgPong{Nonce: 123123}, // 0x1e0f3 []byte{0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0031Version+1 { - btcwire.MsgPong{Nonce: 456456}, // 0x6f708 - btcwire.MsgPong{Nonce: 456456}, // 0x6f708 + wire.MsgPong{Nonce: 456456}, // 0x6f708 + wire.MsgPong{Nonce: 456456}, // 0x6f708 []byte{0x08, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, - btcwire.BIP0031Version + 1, + wire.BIP0031Version + 1, }, } @@ -189,7 +189,7 @@ func TestPongWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgPong + var msg wire.MsgPong rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -207,28 +207,28 @@ func TestPongWire(t *testing.T) { // TestPongWireErrors performs negative tests against wire encode and decode // of MsgPong to confirm error paths work correctly. func TestPongWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - pverNoPong := btcwire.BIP0031Version - btcwireErr := &btcwire.MessageError{} + pver := wire.ProtocolVersion + pverNoPong := wire.BIP0031Version + wireErr := &wire.MessageError{} - basePong := btcwire.NewMsgPong(123123) // 0x1e0f3 + basePong := wire.NewMsgPong(123123) // 0x1e0f3 basePongEncoded := []byte{ 0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, } tests := []struct { - in *btcwire.MsgPong // 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 + in *wire.MsgPong // 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 error in nonce. {basePong, basePongEncoded, pver, 0, io.ErrShortWrite, io.EOF}, // Force error due to unsupported protocol version. - {basePong, basePongEncoded, pverNoPong, 4, btcwireErr, btcwireErr}, + {basePong, basePongEncoded, pverNoPong, 4, wireErr, wireErr}, } t.Logf("Running %d tests", len(tests)) @@ -242,9 +242,9 @@ func TestPongWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -253,7 +253,7 @@ func TestPongWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgPong + var msg wire.MsgPong r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -262,9 +262,9 @@ func TestPongWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msgreject.go b/wire/msgreject.go similarity index 98% rename from msgreject.go rename to wire/msgreject.go index 84f21f95..a9c68b96 100644 --- a/msgreject.go +++ b/wire/msgreject.go @@ -1,8 +1,8 @@ -// Copyright (c) 2014 Conformal Systems LLC. +// Copyright (c) 2014-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/msgreject_test.go b/wire/msgreject_test.go similarity index 78% rename from msgreject_test.go rename to wire/msgreject_test.go index ff9bebf4..8b7a400c 100644 --- a/msgreject_test.go +++ b/wire/msgreject_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2014 Conformal Systems LLC. +// Copyright (c) 2014-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -10,24 +10,24 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestRejectCodeStringer tests the stringized output for the reject code type. func TestRejectCodeStringer(t *testing.T) { tests := []struct { - in btcwire.RejectCode + in wire.RejectCode want string }{ - {btcwire.RejectMalformed, "REJECT_MALFORMED"}, - {btcwire.RejectInvalid, "REJECT_INVALID"}, - {btcwire.RejectObsolete, "REJECT_OBSOLETE"}, - {btcwire.RejectDuplicate, "REJECT_DUPLICATE"}, - {btcwire.RejectNonstandard, "REJECT_NONSTANDARD"}, - {btcwire.RejectDust, "REJECT_DUST"}, - {btcwire.RejectInsufficientFee, "REJECT_INSUFFICIENTFEE"}, - {btcwire.RejectCheckpoint, "REJECT_CHECKPOINT"}, + {wire.RejectMalformed, "REJECT_MALFORMED"}, + {wire.RejectInvalid, "REJECT_INVALID"}, + {wire.RejectObsolete, "REJECT_OBSOLETE"}, + {wire.RejectDuplicate, "REJECT_DUPLICATE"}, + {wire.RejectNonstandard, "REJECT_NONSTANDARD"}, + {wire.RejectDust, "REJECT_DUST"}, + {wire.RejectInsufficientFee, "REJECT_INSUFFICIENTFEE"}, + {wire.RejectCheckpoint, "REJECT_CHECKPOINT"}, {0xff, "Unknown RejectCode (255)"}, } @@ -45,16 +45,16 @@ func TestRejectCodeStringer(t *testing.T) { // TestRejectLatest tests the MsgPong API against the latest protocol version. func TestRejectLatest(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Create reject message data. - rejCommand := (&btcwire.MsgBlock{}).Command() - rejCode := btcwire.RejectDuplicate + rejCommand := (&wire.MsgBlock{}).Command() + rejCode := wire.RejectDuplicate rejReason := "duplicate block" rejHash := mainNetGenesisHash // Ensure we get the correct data back out. - msg := btcwire.NewMsgReject(rejCommand, rejCode, rejReason) + msg := wire.NewMsgReject(rejCommand, rejCode, rejReason) msg.Hash = rejHash if msg.Cmd != rejCommand { t.Errorf("NewMsgReject: wrong rejected command - got %v, "+ @@ -77,7 +77,7 @@ func TestRejectLatest(t *testing.T) { } // Ensure max payload is expected value for latest protocol version. - wantPayload := uint32(btcwire.MaxMessagePayload) + wantPayload := uint32(wire.MaxMessagePayload) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { t.Errorf("MaxPayloadLength: wrong max payload length for "+ @@ -93,7 +93,7 @@ func TestRejectLatest(t *testing.T) { } // Test decode with latest protocol version. - readMsg := btcwire.MsgReject{} + readMsg := wire.MsgReject{} err = readMsg.BtcDecode(&buf, pver) if err != nil { t.Errorf("decode of MsgReject failed %v err <%v>", buf.Bytes(), @@ -123,15 +123,15 @@ func TestRejectLatest(t *testing.T) { // before the version which introduced it (RejectVersion). func TestRejectBeforeAdded(t *testing.T) { // Use the protocol version just prior to RejectVersion. - pver := btcwire.RejectVersion - 1 + pver := wire.RejectVersion - 1 // Create reject message data. - rejCommand := (&btcwire.MsgBlock{}).Command() - rejCode := btcwire.RejectDuplicate + rejCommand := (&wire.MsgBlock{}).Command() + rejCode := wire.RejectDuplicate rejReason := "duplicate block" rejHash := mainNetGenesisHash - msg := btcwire.NewMsgReject(rejCommand, rejCode, rejReason) + msg := wire.NewMsgReject(rejCommand, rejCode, rejReason) msg.Hash = rejHash // Ensure max payload is expected value for old protocol version. @@ -150,7 +150,7 @@ func TestRejectBeforeAdded(t *testing.T) { } // // Test decode with old protocol version. - readMsg := btcwire.MsgReject{} + readMsg := wire.MsgReject{} err = readMsg.BtcDecode(&buf, pver) if err == nil { t.Errorf("decode of MsgReject succeeded when it shouldn't "+ @@ -182,24 +182,24 @@ func TestRejectBeforeAdded(t *testing.T) { // introduced it (RejectVersion). func TestRejectCrossProtocol(t *testing.T) { // Create reject message data. - rejCommand := (&btcwire.MsgBlock{}).Command() - rejCode := btcwire.RejectDuplicate + rejCommand := (&wire.MsgBlock{}).Command() + rejCode := wire.RejectDuplicate rejReason := "duplicate block" rejHash := mainNetGenesisHash - msg := btcwire.NewMsgReject(rejCommand, rejCode, rejReason) + msg := wire.NewMsgReject(rejCommand, rejCode, rejReason) msg.Hash = rejHash // Encode with latest protocol version. var buf bytes.Buffer - err := msg.BtcEncode(&buf, btcwire.ProtocolVersion) + err := msg.BtcEncode(&buf, wire.ProtocolVersion) if err != nil { t.Errorf("encode of MsgReject failed %v err <%v>", msg, err) } // Decode with old protocol version. - readMsg := btcwire.MsgReject{} - err = readMsg.BtcDecode(&buf, btcwire.RejectVersion-1) + readMsg := wire.MsgReject{} + err = readMsg.BtcDecode(&buf, wire.RejectVersion-1) if err == nil { t.Errorf("encode of MsgReject succeeded when it shouldn't "+ "have %v", msg) @@ -226,37 +226,37 @@ func TestRejectCrossProtocol(t *testing.T) { // protocol versions. func TestRejectWire(t *testing.T) { tests := []struct { - msg btcwire.MsgReject // Message to encode - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + msg wire.MsgReject // Message to encode + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version rejected command version (no hash). { - btcwire.MsgReject{ + wire.MsgReject{ Cmd: "version", - Code: btcwire.RejectDuplicate, + Code: wire.RejectDuplicate, Reason: "duplicate version", }, []byte{ 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, // "version" - 0x12, // btcwire.RejectDuplicate + 0x12, // wire.RejectDuplicate 0x11, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, // "duplicate version" }, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version rejected command block (has hash). { - btcwire.MsgReject{ + wire.MsgReject{ Cmd: "block", - Code: btcwire.RejectDuplicate, + Code: wire.RejectDuplicate, Reason: "duplicate block", Hash: mainNetGenesisHash, }, []byte{ 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, // "block" - 0x12, // btcwire.RejectDuplicate + 0x12, // wire.RejectDuplicate 0x0f, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, // "duplicate block" 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, @@ -264,7 +264,7 @@ func TestRejectWire(t *testing.T) { 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, // mainNetGenesisHash }, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, } @@ -284,7 +284,7 @@ func TestRejectWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgReject + var msg wire.MsgReject rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -302,16 +302,16 @@ func TestRejectWire(t *testing.T) { // TestRejectWireErrors performs negative tests against wire encode and decode // of MsgReject to confirm error paths work correctly. func TestRejectWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - pverNoReject := btcwire.RejectVersion - 1 - btcwireErr := &btcwire.MessageError{} + pver := wire.ProtocolVersion + pverNoReject := wire.RejectVersion - 1 + wireErr := &wire.MessageError{} - baseReject := btcwire.NewMsgReject("block", btcwire.RejectDuplicate, + baseReject := wire.NewMsgReject("block", wire.RejectDuplicate, "duplicate block") baseReject.Hash = mainNetGenesisHash baseRejectEncoded := []byte{ 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, // "block" - 0x12, // btcwire.RejectDuplicate + 0x12, // wire.RejectDuplicate 0x0f, 0x64, 0x75, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, // "duplicate block" 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, @@ -321,12 +321,12 @@ func TestRejectWireErrors(t *testing.T) { } tests := []struct { - in *btcwire.MsgReject // 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 + in *wire.MsgReject // 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 error in reject command. @@ -338,7 +338,7 @@ func TestRejectWireErrors(t *testing.T) { // Force error in reject hash. {baseReject, baseRejectEncoded, pver, 23, io.ErrShortWrite, io.EOF}, // Force error due to unsupported protocol version. - {baseReject, baseRejectEncoded, pverNoReject, 6, btcwireErr, btcwireErr}, + {baseReject, baseRejectEncoded, pverNoReject, 6, wireErr, wireErr}, } t.Logf("Running %d tests", len(tests)) @@ -352,9 +352,9 @@ func TestRejectWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -363,7 +363,7 @@ func TestRejectWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgReject + var msg wire.MsgReject r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -372,9 +372,9 @@ func TestRejectWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) diff --git a/msgtx.go b/wire/msgtx.go similarity index 99% rename from msgtx.go rename to wire/msgtx.go index c01ba275..19a0bc3e 100644 --- a/msgtx.go +++ b/wire/msgtx.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "bytes" diff --git a/msgtx_test.go b/wire/msgtx_test.go similarity index 89% rename from msgtx_test.go rename to wire/msgtx_test.go index eefcba80..d165d03d 100644 --- a/msgtx_test.go +++ b/wire/msgtx_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -11,24 +11,24 @@ import ( "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestTx tests the MsgTx API. func TestTx(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Block 100000 hash. hashStr := "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" - hash, err := btcwire.NewShaHashFromStr(hashStr) + hash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } // Ensure the command is expected value. wantCmd := "tx" - msg := btcwire.NewMsgTx() + msg := wire.NewMsgTx() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgAddr: wrong command - got %v want %v", cmd, wantCmd) @@ -48,7 +48,7 @@ func TestTx(t *testing.T) { // NOTE: This is a block hash and made up index, but we're only // testing package functionality. prevOutIndex := uint32(1) - prevOut := btcwire.NewOutPoint(hash, prevOutIndex) + prevOut := wire.NewOutPoint(hash, prevOutIndex) if !prevOut.Hash.IsEqual(hash) { t.Errorf("NewOutPoint: wrong hash - got %v, want %v", spew.Sprint(&prevOut.Hash), spew.Sprint(hash)) @@ -65,7 +65,7 @@ func TestTx(t *testing.T) { // Ensure we get the same transaction input back out. sigScript := []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62} - txIn := btcwire.NewTxIn(prevOut, sigScript) + txIn := wire.NewTxIn(prevOut, sigScript) if !reflect.DeepEqual(&txIn.PreviousOutPoint, prevOut) { t.Errorf("NewTxIn: wrong prev outpoint - got %v, want %v", spew.Sprint(&txIn.PreviousOutPoint), @@ -92,7 +92,7 @@ func TestTx(t *testing.T) { 0xa6, // 65-byte signature 0xac, // OP_CHECKSIG } - txOut := btcwire.NewTxOut(txValue, pkScript) + txOut := wire.NewTxOut(txValue, pkScript) if txOut.Value != txValue { t.Errorf("NewTxOut: wrong pk script - got %v, want %v", txOut.Value, txValue) @@ -132,23 +132,23 @@ func TestTx(t *testing.T) { func TestTxSha(t *testing.T) { // Hash of first transaction from block 113875. hashStr := "f051e59b5e2503ac626d03aaeac8ab7be2d72ba4b7e97119c5852d70d52dcb86" - wantHash, err := btcwire.NewShaHashFromStr(hashStr) + wantHash, err := wire.NewShaHashFromStr(hashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) return } // First transaction from block 113875. - msgTx := btcwire.NewMsgTx() - txIn := btcwire.TxIn{ - PreviousOutPoint: btcwire.OutPoint{ - Hash: btcwire.ShaHash{}, + msgTx := wire.NewMsgTx() + txIn := wire.TxIn{ + PreviousOutPoint: wire.OutPoint{ + Hash: wire.ShaHash{}, Index: 0xffffffff, }, SignatureScript: []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62}, Sequence: 0xffffffff, } - txOut := btcwire.TxOut{ + txOut := wire.TxOut{ Value: 5000000000, PkScript: []byte{ 0x41, // OP_DATA_65 @@ -183,7 +183,7 @@ func TestTxSha(t *testing.T) { // of transaction inputs and outputs and protocol versions. func TestTxWire(t *testing.T) { // Empty tx message. - noTx := btcwire.NewMsgTx() + noTx := wire.NewMsgTx() noTx.Version = 1 noTxEncoded := []byte{ 0x01, 0x00, 0x00, 0x00, // Version @@ -193,17 +193,17 @@ func TestTxWire(t *testing.T) { } tests := []struct { - in *btcwire.MsgTx // Message to encode - out *btcwire.MsgTx // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgTx // Message to encode + out *wire.MsgTx // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version with no transactions. { noTx, noTx, noTxEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version with multiple transactions. @@ -211,7 +211,7 @@ func TestTxWire(t *testing.T) { multiTx, multiTx, multiTxEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version with no transactions. @@ -219,7 +219,7 @@ func TestTxWire(t *testing.T) { noTx, noTx, noTxEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0035Version with multiple transactions. @@ -227,7 +227,7 @@ func TestTxWire(t *testing.T) { multiTx, multiTx, multiTxEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version with no transactions. @@ -235,7 +235,7 @@ func TestTxWire(t *testing.T) { noTx, noTx, noTxEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version BIP0031Version with multiple transactions. @@ -243,7 +243,7 @@ func TestTxWire(t *testing.T) { multiTx, multiTx, multiTxEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion with no transactions. @@ -251,7 +251,7 @@ func TestTxWire(t *testing.T) { noTx, noTx, noTxEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion with multiple transactions. @@ -259,7 +259,7 @@ func TestTxWire(t *testing.T) { multiTx, multiTx, multiTxEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion with no transactions. @@ -267,7 +267,7 @@ func TestTxWire(t *testing.T) { noTx, noTx, noTxEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, // Protocol version MultipleAddressVersion with multiple transactions. @@ -275,7 +275,7 @@ func TestTxWire(t *testing.T) { multiTx, multiTx, multiTxEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -295,7 +295,7 @@ func TestTxWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgTx + var msg wire.MsgTx rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -319,12 +319,12 @@ func TestTxWireErrors(t *testing.T) { pver := uint32(60002) tests := []struct { - in *btcwire.MsgTx // 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 + in *wire.MsgTx // 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. {multiTx, multiTxEncoded, pver, 0, io.ErrShortWrite, io.EOF}, @@ -366,7 +366,7 @@ func TestTxWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgTx + var msg wire.MsgTx r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if err != test.readErr { @@ -379,7 +379,7 @@ func TestTxWireErrors(t *testing.T) { // TestTxSerialize tests MsgTx serialize and deserialize. func TestTxSerialize(t *testing.T) { - noTx := btcwire.NewMsgTx() + noTx := wire.NewMsgTx() noTx.Version = 1 noTxEncoded := []byte{ 0x01, 0x00, 0x00, 0x00, // Version @@ -389,9 +389,9 @@ func TestTxSerialize(t *testing.T) { } tests := []struct { - in *btcwire.MsgTx // Message to encode - out *btcwire.MsgTx // Expected decoded message - buf []byte // Serialized data + in *wire.MsgTx // Message to encode + out *wire.MsgTx // Expected decoded message + buf []byte // Serialized data }{ // No transactions. { @@ -424,7 +424,7 @@ func TestTxSerialize(t *testing.T) { } // Deserialize the transaction. - var tx btcwire.MsgTx + var tx wire.MsgTx rbuf := bytes.NewReader(test.buf) err = tx.Deserialize(rbuf) if err != nil { @@ -443,11 +443,11 @@ func TestTxSerialize(t *testing.T) { // of MsgTx to confirm error paths work correctly. func TestTxSerializeErrors(t *testing.T) { tests := []struct { - in *btcwire.MsgTx // Value to encode - buf []byte // Serialized data - max int // Max size of fixed buffer to induce errors - writeErr error // Expected write error - readErr error // Expected read error + in *wire.MsgTx // Value to encode + buf []byte // Serialized data + max int // Max size of fixed buffer to induce errors + writeErr error // Expected write error + readErr error // Expected read error }{ // Force error in version. {multiTx, multiTxEncoded, 0, io.ErrShortWrite, io.EOF}, @@ -489,7 +489,7 @@ func TestTxSerializeErrors(t *testing.T) { } // Deserialize the transaction. - var tx btcwire.MsgTx + var tx wire.MsgTx r := newFixedReader(test.max, test.buf) err = tx.Deserialize(r) if err != test.readErr { @@ -523,7 +523,7 @@ func TestTxOverflowErrors(t *testing.T) { 0x00, 0x00, 0x00, 0x01, // Version 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Varint for number of input transactions - }, pver, txVer, &btcwire.MessageError{}, + }, pver, txVer, &wire.MessageError{}, }, // Transaction that claims to have ~uint64(0) outputs. @@ -533,7 +533,7 @@ func TestTxOverflowErrors(t *testing.T) { 0x00, // Varint for number of input transactions 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Varint for number of output transactions - }, pver, txVer, &btcwire.MessageError{}, + }, pver, txVer, &wire.MessageError{}, }, // Transaction that has an input with a signature script that @@ -549,7 +549,7 @@ func TestTxOverflowErrors(t *testing.T) { 0xff, 0xff, 0xff, 0xff, // Prevous output index 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Varint for length of signature script - }, pver, txVer, &btcwire.MessageError{}, + }, pver, txVer, &wire.MessageError{}, }, // Transaction that has an output with a public key script @@ -569,14 +569,14 @@ func TestTxOverflowErrors(t *testing.T) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Transaction amount 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Varint for length of public key script - }, pver, txVer, &btcwire.MessageError{}, + }, pver, txVer, &wire.MessageError{}, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Decode from wire format. - var msg btcwire.MsgTx + var msg wire.MsgTx r := bytes.NewReader(test.buf) err := msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { @@ -600,12 +600,12 @@ func TestTxOverflowErrors(t *testing.T) { // transactions is accurate. func TestTxSerializeSize(t *testing.T) { // Empty tx message. - noTx := btcwire.NewMsgTx() + noTx := wire.NewMsgTx() noTx.Version = 1 tests := []struct { - in *btcwire.MsgTx // Tx to encode - size int // Expected serialized size + in *wire.MsgTx // Tx to encode + size int // Expected serialized size }{ // No inputs or outpus. {noTx, 10}, @@ -626,12 +626,12 @@ func TestTxSerializeSize(t *testing.T) { } // multiTx is a MsgTx with an input and output and used in various tests. -var multiTx = &btcwire.MsgTx{ +var multiTx = &wire.MsgTx{ Version: 1, - TxIn: []*btcwire.TxIn{ + TxIn: []*wire.TxIn{ { - PreviousOutPoint: btcwire.OutPoint{ - Hash: btcwire.ShaHash{}, + PreviousOutPoint: wire.OutPoint{ + Hash: wire.ShaHash{}, Index: 0xffffffff, }, SignatureScript: []byte{ @@ -640,7 +640,7 @@ var multiTx = &btcwire.MsgTx{ Sequence: 0xffffffff, }, }, - TxOut: []*btcwire.TxOut{ + TxOut: []*wire.TxOut{ { Value: 0x12a05f200, PkScript: []byte{ diff --git a/msgverack.go b/wire/msgverack.go similarity index 95% rename from msgverack.go rename to wire/msgverack.go index a6ccfa67..95214352 100644 --- a/msgverack.go +++ b/wire/msgverack.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "io" diff --git a/msgverack_test.go b/wire/msgverack_test.go similarity index 78% rename from msgverack_test.go rename to wire/msgverack_test.go index f018d9a8..b6dee460 100644 --- a/msgverack_test.go +++ b/wire/msgverack_test.go @@ -1,25 +1,25 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" "reflect" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestVerAck tests the MsgVerAck API. func TestVerAck(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Ensure the command is expected value. wantCmd := "verack" - msg := btcwire.NewMsgVerAck() + msg := wire.NewMsgVerAck() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgVerAck: wrong command - got %v want %v", cmd, wantCmd) @@ -40,21 +40,21 @@ func TestVerAck(t *testing.T) { // TestVerAckWire tests the MsgVerAck wire encode and decode for various // protocol versions. func TestVerAckWire(t *testing.T) { - msgVerAck := btcwire.NewMsgVerAck() + msgVerAck := wire.NewMsgVerAck() msgVerAckEncoded := []byte{} tests := []struct { - in *btcwire.MsgVerAck // Message to encode - out *btcwire.MsgVerAck // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgVerAck // Message to encode + out *wire.MsgVerAck // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { msgVerAck, msgVerAck, msgVerAckEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0035Version. @@ -62,7 +62,7 @@ func TestVerAckWire(t *testing.T) { msgVerAck, msgVerAck, msgVerAckEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version. @@ -70,7 +70,7 @@ func TestVerAckWire(t *testing.T) { msgVerAck, msgVerAck, msgVerAckEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion. @@ -78,7 +78,7 @@ func TestVerAckWire(t *testing.T) { msgVerAck, msgVerAck, msgVerAckEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion. @@ -86,7 +86,7 @@ func TestVerAckWire(t *testing.T) { msgVerAck, msgVerAck, msgVerAckEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -106,7 +106,7 @@ func TestVerAckWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgVerAck + var msg wire.MsgVerAck rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { diff --git a/msgversion.go b/wire/msgversion.go similarity index 98% rename from msgversion.go rename to wire/msgversion.go index 2e233a56..f62f42c6 100644 --- a/msgversion.go +++ b/wire/msgversion.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "bytes" @@ -17,9 +17,10 @@ import ( // version message (MsgVersion). const MaxUserAgentLen = 2000 -// DefaultUserAgent for btcwire in the stack +// DefaultUserAgent for wire in the stack const DefaultUserAgent = "/btcwire:0.2.0/" + // MsgVersion implements the Message interface and represents a bitcoin version // message. It is used for a peer to advertise itself as soon as an outbound // connection is made. The remote peer then uses this information along with diff --git a/msgversion_test.go b/wire/msgversion_test.go similarity index 81% rename from msgversion_test.go rename to wire/msgversion_test.go index f4b431e5..3507f1e2 100644 --- a/msgversion_test.go +++ b/wire/msgversion_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -13,33 +13,33 @@ import ( "testing" "time" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) // TestVersion tests the MsgVersion API. func TestVersion(t *testing.T) { - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion // Create version message data. lastBlock := int32(234234) tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} - me, err := btcwire.NewNetAddress(tcpAddrMe, btcwire.SFNodeNetwork) + me, err := wire.NewNetAddress(tcpAddrMe, wire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } tcpAddrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333} - you, err := btcwire.NewNetAddress(tcpAddrYou, btcwire.SFNodeNetwork) + you, err := wire.NewNetAddress(tcpAddrYou, wire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } - nonce, err := btcwire.RandomUint64() + nonce, err := wire.RandomUint64() if err != nil { t.Errorf("RandomUint64: error generating nonce: %v", err) } // Ensure we get the correct data back out. - msg := btcwire.NewMsgVersion(me, you, nonce, lastBlock) + msg := wire.NewMsgVersion(me, you, nonce, lastBlock) if msg.ProtocolVersion != int32(pver) { t.Errorf("NewMsgVersion: wrong protocol version - got %v, want %v", msg.ProtocolVersion, pver) @@ -56,9 +56,9 @@ func TestVersion(t *testing.T) { t.Errorf("NewMsgVersion: wrong nonce - got %v, want %v", msg.Nonce, nonce) } - if msg.UserAgent != btcwire.DefaultUserAgent { + if msg.UserAgent != wire.DefaultUserAgent { t.Errorf("NewMsgVersion: wrong user agent - got %v, want %v", - msg.UserAgent, btcwire.DefaultUserAgent) + msg.UserAgent, wire.DefaultUserAgent) } if msg.LastBlock != lastBlock { t.Errorf("NewMsgVersion: wrong last block - got %v, want %v", @@ -70,7 +70,7 @@ func TestVersion(t *testing.T) { } msg.AddUserAgent("myclient", "1.2.3", "optional", "comments") - customUserAgent := btcwire.DefaultUserAgent + "myclient:1.2.3(optional; comments)/" + customUserAgent := wire.DefaultUserAgent + "myclient:1.2.3(optional; comments)/" if msg.UserAgent != customUserAgent { t.Errorf("AddUserAgent: wrong user agent - got %s, want %s", msg.UserAgent, customUserAgent) @@ -85,10 +85,10 @@ func TestVersion(t *testing.T) { // accounting for ":", "/" err = msg.AddUserAgent(strings.Repeat("t", - btcwire.MaxUserAgentLen-len(customUserAgent)-2+1), "") - if _, ok := err.(*btcwire.MessageError); !ok { + wire.MaxUserAgentLen-len(customUserAgent)-2+1), "") + if _, ok := err.(*wire.MessageError); !ok { t.Errorf("AddUserAgent: expected error not received "+ - "- got %v, want %T", err, btcwire.MessageError{}) + "- got %v, want %T", err, wire.MessageError{}) } @@ -98,7 +98,7 @@ func TestVersion(t *testing.T) { msg.Services, 0) } - if msg.HasService(btcwire.SFNodeNetwork) { + if msg.HasService(wire.SFNodeNetwork) { t.Errorf("HasService: SFNodeNetwork service is set") } @@ -123,18 +123,18 @@ func TestVersion(t *testing.T) { } // Ensure adding the full service node flag works. - msg.AddService(btcwire.SFNodeNetwork) - if msg.Services != btcwire.SFNodeNetwork { + msg.AddService(wire.SFNodeNetwork) + if msg.Services != wire.SFNodeNetwork { t.Errorf("AddService: wrong services - got %v, want %v", - msg.Services, btcwire.SFNodeNetwork) + msg.Services, wire.SFNodeNetwork) } - if !msg.HasService(btcwire.SFNodeNetwork) { + if !msg.HasService(wire.SFNodeNetwork) { t.Errorf("HasService: SFNodeNetwork service not set") } // Use a fake connection. conn := &fakeConn{localAddr: tcpAddrMe, remoteAddr: tcpAddrYou} - msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, lastBlock) + msg, err = wire.NewMsgVersionFromConn(conn, nonce, lastBlock) if err != nil { t.Errorf("NewMsgVersionFromConn: %v", err) } @@ -154,10 +154,10 @@ func TestVersion(t *testing.T) { localAddr: &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333}, remoteAddr: tcpAddrYou, } - msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, lastBlock) - if err != btcwire.ErrInvalidNetAddr { + msg, err = wire.NewMsgVersionFromConn(conn, nonce, lastBlock) + if err != wire.ErrInvalidNetAddr { t.Errorf("NewMsgVersionFromConn: expected error not received "+ - "- got %v, want %v", err, btcwire.ErrInvalidNetAddr) + "- got %v, want %v", err, wire.ErrInvalidNetAddr) } // Use a fake connection with remote UDP addresses to force a failure. @@ -165,10 +165,10 @@ func TestVersion(t *testing.T) { localAddr: tcpAddrMe, remoteAddr: &net.UDPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333}, } - msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, lastBlock) - if err != btcwire.ErrInvalidNetAddr { + msg, err = wire.NewMsgVersionFromConn(conn, nonce, lastBlock) + if err != wire.ErrInvalidNetAddr { t.Errorf("NewMsgVersionFromConn: expected error not received "+ - "- got %v, want %v", err, btcwire.ErrInvalidNetAddr) + "- got %v, want %v", err, wire.ErrInvalidNetAddr) } return @@ -187,17 +187,17 @@ func TestVersionWire(t *testing.T) { verRelayTxFalseEncoded[len(verRelayTxFalseEncoded)-1] = 0 tests := []struct { - in *btcwire.MsgVersion // Message to encode - out *btcwire.MsgVersion // Expected decoded message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in *wire.MsgVersion // Message to encode + out *wire.MsgVersion // Expected decoded message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { baseVersionBIP0037, baseVersionBIP0037, baseVersionBIP0037Encoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version BIP0037Version with relay transactions field @@ -206,7 +206,7 @@ func TestVersionWire(t *testing.T) { baseVersionBIP0037, baseVersionBIP0037, baseVersionBIP0037Encoded, - btcwire.BIP0037Version, + wire.BIP0037Version, }, // Protocol version BIP0037Version with relay transactions field @@ -215,7 +215,7 @@ func TestVersionWire(t *testing.T) { verRelayTxFalse, verRelayTxFalse, verRelayTxFalseEncoded, - btcwire.BIP0037Version, + wire.BIP0037Version, }, // Protocol version BIP0035Version. @@ -223,7 +223,7 @@ func TestVersionWire(t *testing.T) { baseVersion, baseVersion, baseVersionEncoded, - btcwire.BIP0035Version, + wire.BIP0035Version, }, // Protocol version BIP0031Version. @@ -231,7 +231,7 @@ func TestVersionWire(t *testing.T) { baseVersion, baseVersion, baseVersionEncoded, - btcwire.BIP0031Version, + wire.BIP0031Version, }, // Protocol version NetAddressTimeVersion. @@ -239,7 +239,7 @@ func TestVersionWire(t *testing.T) { baseVersion, baseVersion, baseVersionEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion. @@ -247,7 +247,7 @@ func TestVersionWire(t *testing.T) { baseVersion, baseVersion, baseVersionEncoded, - btcwire.MultipleAddressVersion, + wire.MultipleAddressVersion, }, } @@ -267,7 +267,7 @@ func TestVersionWire(t *testing.T) { } // Decode the message from wire format. - var msg btcwire.MsgVersion + var msg wire.MsgVersion rbuf := bytes.NewBuffer(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -289,7 +289,7 @@ func TestVersionWireErrors(t *testing.T) { // because the test data is using bytes encoded with that protocol // version. pver := uint32(60002) - btcwireErr := &btcwire.MessageError{} + wireErr := &wire.MessageError{} // Ensure calling MsgVersion.BtcDecode with a non *bytes.Buffer returns // error. @@ -302,12 +302,12 @@ func TestVersionWireErrors(t *testing.T) { // Copy the base version and change the user agent to exceed max limits. bvc := *baseVersion exceedUAVer := &bvc - newUA := "/" + strings.Repeat("t", btcwire.MaxUserAgentLen-8+1) + ":0.0.1/" + newUA := "/" + strings.Repeat("t", wire.MaxUserAgentLen-8+1) + ":0.0.1/" exceedUAVer.UserAgent = newUA // Encode the new UA length as a varint. var newUAVarIntBuf bytes.Buffer - err := btcwire.TstWriteVarInt(&newUAVarIntBuf, pver, uint64(len(newUA))) + err := wire.TstWriteVarInt(&newUAVarIntBuf, pver, uint64(len(newUA))) if err != nil { t.Errorf("writeVarInt: error %v", err) } @@ -324,12 +324,12 @@ func TestVersionWireErrors(t *testing.T) { copy(exceedUAVerEncoded[83+len(newUA):], baseVersionEncoded[97:100]) tests := []struct { - in *btcwire.MsgVersion // 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 + in *wire.MsgVersion // 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 protocol version. {baseVersion, baseVersionEncoded, pver, 0, io.ErrShortWrite, io.EOF}, @@ -353,10 +353,10 @@ func TestVersionWireErrors(t *testing.T) { // it's optional. { baseVersionBIP0037, baseVersionBIP0037Encoded, - btcwire.BIP0037Version, 101, io.ErrShortWrite, nil, + wire.BIP0037Version, 101, io.ErrShortWrite, nil, }, // Force error due to user agent too big - {exceedUAVer, exceedUAVerEncoded, pver, newLen, btcwireErr, btcwireErr}, + {exceedUAVer, exceedUAVerEncoded, pver, newLen, wireErr, wireErr}, } t.Logf("Running %d tests", len(tests)) @@ -370,9 +370,9 @@ func TestVersionWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) @@ -381,7 +381,7 @@ func TestVersionWireErrors(t *testing.T) { } // Decode from wire format. - var msg btcwire.MsgVersion + var msg wire.MsgVersion buf := bytes.NewBuffer(test.buf[0:test.max]) err = msg.BtcDecode(buf, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { @@ -390,9 +390,9 @@ func TestVersionWireErrors(t *testing.T) { continue } - // For errors which are not of type btcwire.MessageError, check + // For errors which are not of type wire.MessageError, check // them for equality. - if _, ok := err.(*btcwire.MessageError); !ok { + if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) @@ -407,13 +407,13 @@ func TestVersionWireErrors(t *testing.T) { func TestVersionOptionalFields(t *testing.T) { // onlyRequiredVersion is a version message that only contains the // required versions and all other values set to their default values. - onlyRequiredVersion := btcwire.MsgVersion{ + onlyRequiredVersion := wire.MsgVersion{ ProtocolVersion: 60002, - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST) - AddrYou: btcwire.NetAddress{ + AddrYou: wire.NetAddress{ Timestamp: time.Time{}, // Zero value -- no timestamp in version - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("192.168.0.1"), Port: 8333, }, @@ -424,9 +424,9 @@ func TestVersionOptionalFields(t *testing.T) { // addrMeVersion is a version message that contains all fields through // the AddrMe field. addrMeVersion := onlyRequiredVersion - addrMeVersion.AddrMe = btcwire.NetAddress{ + addrMeVersion.AddrMe = wire.NetAddress{ Timestamp: time.Time{}, // Zero value -- no timestamp in version - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("127.0.0.1"), Port: 8333, } @@ -455,40 +455,40 @@ func TestVersionOptionalFields(t *testing.T) { copy(lastBlockVersionEncoded, baseVersionEncoded) tests := []struct { - msg *btcwire.MsgVersion // Expected message - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + msg *wire.MsgVersion // Expected message + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ { &onlyRequiredVersion, onlyRequiredVersionEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, { &addrMeVersion, addrMeVersionEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, { &nonceVersion, nonceVersionEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, { &uaVersion, uaVersionEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, { &lastBlockVersion, lastBlockVersionEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, } for i, test := range tests { // Decode the message from wire format. - var msg btcwire.MsgVersion + var msg wire.MsgVersion rbuf := bytes.NewBuffer(test.buf) err := msg.BtcDecode(rbuf, test.pver) if err != nil { @@ -504,19 +504,19 @@ func TestVersionOptionalFields(t *testing.T) { } // baseVersion is used in the various tests as a baseline MsgVersion. -var baseVersion = &btcwire.MsgVersion{ +var baseVersion = &wire.MsgVersion{ ProtocolVersion: 60002, - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST) - AddrYou: btcwire.NetAddress{ + AddrYou: wire.NetAddress{ Timestamp: time.Time{}, // Zero value -- no timestamp in version - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("192.168.0.1"), Port: 8333, }, - AddrMe: btcwire.NetAddress{ + AddrMe: wire.NetAddress{ Timestamp: time.Time{}, // Zero value -- no timestamp in version - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("127.0.0.1"), Port: 8333, }, @@ -550,19 +550,19 @@ var baseVersionEncoded = []byte{ // baseVersionBIP0037 is used in the various tests as a baseline MsgVersion for // BIP0037. -var baseVersionBIP0037 = &btcwire.MsgVersion{ +var baseVersionBIP0037 = &wire.MsgVersion{ ProtocolVersion: 70001, - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST) - AddrYou: btcwire.NetAddress{ + AddrYou: wire.NetAddress{ Timestamp: time.Time{}, // Zero value -- no timestamp in version - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("192.168.0.1"), Port: 8333, }, - AddrMe: btcwire.NetAddress{ + AddrMe: wire.NetAddress{ Timestamp: time.Time{}, // Zero value -- no timestamp in version - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("127.0.0.1"), Port: 8333, }, diff --git a/netaddress.go b/wire/netaddress.go similarity index 98% rename from netaddress.go rename to wire/netaddress.go index f4017111..ad6abbf2 100644 --- a/netaddress.go +++ b/wire/netaddress.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "encoding/binary" diff --git a/netaddress_test.go b/wire/netaddress_test.go similarity index 77% rename from netaddress_test.go rename to wire/netaddress_test.go index e683eb01..b7e8775e 100644 --- a/netaddress_test.go +++ b/wire/netaddress_test.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" "github.com/davecgh/go-spew/spew" ) @@ -26,7 +26,7 @@ func TestNetAddress(t *testing.T) { IP: ip, Port: port, } - na, err := btcwire.NewNetAddress(tcpAddr, 0) + na, err := wire.NewNetAddress(tcpAddr, 0) if err != nil { t.Errorf("NewNetAddress: %v", err) } @@ -43,24 +43,24 @@ func TestNetAddress(t *testing.T) { t.Errorf("NetNetAddress: wrong services - got %v, want %v", na.Services, 0) } - if na.HasService(btcwire.SFNodeNetwork) { + if na.HasService(wire.SFNodeNetwork) { t.Errorf("HasService: SFNodeNetwork service is set") } // Ensure adding the full service node flag works. - na.AddService(btcwire.SFNodeNetwork) - if na.Services != btcwire.SFNodeNetwork { + na.AddService(wire.SFNodeNetwork) + if na.Services != wire.SFNodeNetwork { t.Errorf("AddService: wrong services - got %v, want %v", - na.Services, btcwire.SFNodeNetwork) + na.Services, wire.SFNodeNetwork) } - if !na.HasService(btcwire.SFNodeNetwork) { + if !na.HasService(wire.SFNodeNetwork) { t.Errorf("HasService: SFNodeNetwork service not set") } // Ensure max payload is expected value for latest protocol version. - pver := btcwire.ProtocolVersion + pver := wire.ProtocolVersion wantPayload := uint32(30) - maxPayload := btcwire.TstMaxNetAddressPayload(btcwire.ProtocolVersion) + maxPayload := wire.TstMaxNetAddressPayload(wire.ProtocolVersion) if maxPayload != wantPayload { t.Errorf("maxNetAddressPayload: wrong max payload length for "+ "protocol version %d - got %v, want %v", pver, @@ -69,9 +69,9 @@ func TestNetAddress(t *testing.T) { // Protocol version before NetAddressTimeVersion when timestamp was // added. Ensure max payload is expected value for it. - pver = btcwire.NetAddressTimeVersion - 1 + pver = wire.NetAddressTimeVersion - 1 wantPayload = 26 - maxPayload = btcwire.TstMaxNetAddressPayload(pver) + maxPayload = wire.TstMaxNetAddressPayload(pver) if maxPayload != wantPayload { t.Errorf("maxNetAddressPayload: wrong max payload length for "+ "protocol version %d - got %v, want %v", pver, @@ -80,10 +80,10 @@ func TestNetAddress(t *testing.T) { // Check for expected failure on wrong address type. udpAddr := &net.UDPAddr{} - _, err = btcwire.NewNetAddress(udpAddr, 0) - if err != btcwire.ErrInvalidNetAddr { + _, err = wire.NewNetAddress(udpAddr, 0) + if err != wire.ErrInvalidNetAddr { t.Errorf("NewNetAddress: expected error not received - "+ - "got %v, want %v", err, btcwire.ErrInvalidNetAddr) + "got %v, want %v", err, wire.ErrInvalidNetAddr) } } @@ -91,9 +91,9 @@ func TestNetAddress(t *testing.T) { // protocol versions and timestamp flag combinations. func TestNetAddressWire(t *testing.T) { // baseNetAddr is used in the various tests as a baseline NetAddress. - baseNetAddr := btcwire.NetAddress{ + baseNetAddr := wire.NetAddress{ Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("127.0.0.1"), Port: 8333, } @@ -121,11 +121,11 @@ func TestNetAddressWire(t *testing.T) { } tests := []struct { - in btcwire.NetAddress // NetAddress to encode - out btcwire.NetAddress // Expected decoded NetAddress - ts bool // Include timestamp? - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding + in wire.NetAddress // NetAddress to encode + out wire.NetAddress // Expected decoded NetAddress + ts bool // Include timestamp? + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding }{ // Latest protocol version without ts flag. { @@ -133,7 +133,7 @@ func TestNetAddressWire(t *testing.T) { baseNetAddrNoTS, false, baseNetAddrNoTSEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Latest protocol version with ts flag. @@ -142,7 +142,7 @@ func TestNetAddressWire(t *testing.T) { baseNetAddr, true, baseNetAddrEncoded, - btcwire.ProtocolVersion, + wire.ProtocolVersion, }, // Protocol version NetAddressTimeVersion without ts flag. @@ -151,7 +151,7 @@ func TestNetAddressWire(t *testing.T) { baseNetAddrNoTS, false, baseNetAddrNoTSEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion with ts flag. @@ -160,7 +160,7 @@ func TestNetAddressWire(t *testing.T) { baseNetAddr, true, baseNetAddrEncoded, - btcwire.NetAddressTimeVersion, + wire.NetAddressTimeVersion, }, // Protocol version NetAddressTimeVersion-1 without ts flag. @@ -169,7 +169,7 @@ func TestNetAddressWire(t *testing.T) { baseNetAddrNoTS, false, baseNetAddrNoTSEncoded, - btcwire.NetAddressTimeVersion - 1, + wire.NetAddressTimeVersion - 1, }, // Protocol version NetAddressTimeVersion-1 with timestamp. @@ -181,7 +181,7 @@ func TestNetAddressWire(t *testing.T) { baseNetAddrNoTS, true, baseNetAddrNoTSEncoded, - btcwire.NetAddressTimeVersion - 1, + wire.NetAddressTimeVersion - 1, }, } @@ -189,7 +189,7 @@ func TestNetAddressWire(t *testing.T) { for i, test := range tests { // Encode to wire format. var buf bytes.Buffer - err := btcwire.TstWriteNetAddress(&buf, test.pver, &test.in, test.ts) + err := wire.TstWriteNetAddress(&buf, test.pver, &test.in, test.ts) if err != nil { t.Errorf("writeNetAddress #%d error %v", i, err) continue @@ -201,9 +201,9 @@ func TestNetAddressWire(t *testing.T) { } // Decode the message from wire format. - var na btcwire.NetAddress + var na wire.NetAddress rbuf := bytes.NewReader(test.buf) - err = btcwire.TstReadNetAddress(rbuf, test.pver, &na, test.ts) + err = wire.TstReadNetAddress(rbuf, test.pver, &na, test.ts) if err != nil { t.Errorf("readNetAddress #%d error %v", i, err) continue @@ -219,25 +219,25 @@ func TestNetAddressWire(t *testing.T) { // TestNetAddressWireErrors performs negative tests against wire encode and // decode NetAddress to confirm error paths work correctly. func TestNetAddressWireErrors(t *testing.T) { - pver := btcwire.ProtocolVersion - pverNAT := btcwire.NetAddressTimeVersion - 1 + pver := wire.ProtocolVersion + pverNAT := wire.NetAddressTimeVersion - 1 // baseNetAddr is used in the various tests as a baseline NetAddress. - baseNetAddr := btcwire.NetAddress{ + baseNetAddr := wire.NetAddress{ Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST - Services: btcwire.SFNodeNetwork, + Services: wire.SFNodeNetwork, IP: net.ParseIP("127.0.0.1"), Port: 8333, } tests := []struct { - in *btcwire.NetAddress // Value to encode - buf []byte // Wire encoding - pver uint32 // Protocol version for wire encoding - ts bool // Include timestamp flag - max int // Max size of fixed buffer to induce errors - writeErr error // Expected write error - readErr error // Expected read error + in *wire.NetAddress // Value to encode + buf []byte // Wire encoding + pver uint32 // Protocol version for wire encoding + ts bool // Include timestamp flag + max int // Max size of fixed buffer to induce errors + writeErr error // Expected write error + readErr error // Expected read error }{ // Latest protocol version with timestamp and intentional // read/write errors. @@ -274,7 +274,7 @@ func TestNetAddressWireErrors(t *testing.T) { for i, test := range tests { // Encode to wire format. w := newFixedWriter(test.max) - err := btcwire.TstWriteNetAddress(w, test.pver, test.in, test.ts) + err := wire.TstWriteNetAddress(w, test.pver, test.in, test.ts) if err != test.writeErr { t.Errorf("writeNetAddress #%d wrong error got: %v, want: %v", i, err, test.writeErr) @@ -282,9 +282,9 @@ func TestNetAddressWireErrors(t *testing.T) { } // Decode from wire format. - var na btcwire.NetAddress + var na wire.NetAddress r := newFixedReader(test.max, test.buf) - err = btcwire.TstReadNetAddress(r, test.pver, &na, test.ts) + err = wire.TstReadNetAddress(r, test.pver, &na, test.ts) if err != test.readErr { t.Errorf("readNetAddress #%d wrong error got: %v, want: %v", i, err, test.readErr) diff --git a/protocol.go b/wire/protocol.go similarity index 98% rename from protocol.go rename to wire/protocol.go index 89f0fcd2..ad4e67be 100644 --- a/protocol.go +++ b/wire/protocol.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "fmt" diff --git a/protocol_test.go b/wire/protocol_test.go similarity index 75% rename from protocol_test.go rename to wire/protocol_test.go index e8e25b84..8d067238 100644 --- a/protocol_test.go +++ b/wire/protocol_test.go @@ -1,23 +1,23 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" ) // TestServiceFlagStringer tests the stringized output for service flag types. func TestServiceFlagStringer(t *testing.T) { tests := []struct { - in btcwire.ServiceFlag + in wire.ServiceFlag want string }{ {0, "0x0"}, - {btcwire.SFNodeNetwork, "SFNodeNetwork"}, + {wire.SFNodeNetwork, "SFNodeNetwork"}, {0xffffffff, "SFNodeNetwork|0xfffffffe"}, } @@ -35,13 +35,13 @@ func TestServiceFlagStringer(t *testing.T) { // TestBitcoinNetStringer tests the stringized output for bitcoin net types. func TestBitcoinNetStringer(t *testing.T) { tests := []struct { - in btcwire.BitcoinNet + in wire.BitcoinNet want string }{ - {btcwire.MainNet, "MainNet"}, - {btcwire.TestNet, "TestNet"}, - {btcwire.TestNet3, "TestNet3"}, - {btcwire.SimNet, "SimNet"}, + {wire.MainNet, "MainNet"}, + {wire.TestNet, "TestNet"}, + {wire.TestNet3, "TestNet3"}, + {wire.SimNet, "SimNet"}, {0xffffffff, "Unknown BitcoinNet (4294967295)"}, } diff --git a/shahash.go b/wire/shahash.go similarity index 97% rename from shahash.go rename to wire/shahash.go index de71f294..63f30ac0 100644 --- a/shahash.go +++ b/wire/shahash.go @@ -1,8 +1,8 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire +package wire import ( "bytes" diff --git a/shahash_test.go b/wire/shahash_test.go similarity index 84% rename from shahash_test.go rename to wire/shahash_test.go index cc527d2e..2e646b74 100644 --- a/shahash_test.go +++ b/wire/shahash_test.go @@ -1,15 +1,15 @@ -// Copyright (c) 2013-2014 Conformal Systems LLC. +// Copyright (c) 2013-2015 Conformal Systems LLC. // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package btcwire_test +package wire_test import ( "bytes" "encoding/hex" "testing" - "github.com/btcsuite/btcwire" + "github.com/btcsuite/btcd/wire" ) // TestShaHash tests the ShaHash API. @@ -17,7 +17,7 @@ func TestShaHash(t *testing.T) { // Hash of block 234439. blockHashStr := "14a0810ac680a3eb3f82edc878cea25ec41d6b790744e5daeef" - blockHash, err := btcwire.NewShaHashFromStr(blockHashStr) + blockHash, err := wire.NewShaHashFromStr(blockHashStr) if err != nil { t.Errorf("NewShaHashFromStr: %v", err) } @@ -30,15 +30,15 @@ func TestShaHash(t *testing.T) { 0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } - hash, err := btcwire.NewShaHash(buf) + hash, err := wire.NewShaHash(buf) if err != nil { t.Errorf("NewShaHash: unexpected error %v", err) } // Ensure proper size. - if len(hash) != btcwire.HashSize { + if len(hash) != wire.HashSize { t.Errorf("NewShaHash: hash length mismatch - got: %v, want: %v", - len(hash), btcwire.HashSize) + len(hash), wire.HashSize) } // Ensure contents match. @@ -70,8 +70,8 @@ func TestShaHash(t *testing.T) { } // Invalid size for NewShaHash. - invalidHash := make([]byte, btcwire.HashSize+1) - _, err = btcwire.NewShaHash(invalidHash) + invalidHash := make([]byte, wire.HashSize+1) + _, err = wire.NewShaHash(invalidHash) if err == nil { t.Errorf("NewShaHash: failed to received expected err - got: nil") } @@ -81,7 +81,7 @@ func TestShaHash(t *testing.T) { func TestShaHashString(t *testing.T) { // Block 100000 hash. wantStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" - hash := btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. + hash := wire.ShaHash([wire.HashSize]byte{ // Make go vet happy. 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39, 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2, 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa, @@ -99,7 +99,7 @@ func TestShaHashString(t *testing.T) { func TestNewShaHashFromStr(t *testing.T) { tests := []struct { in string - want btcwire.ShaHash + want wire.ShaHash err error }{ // Genesis hash. @@ -119,14 +119,14 @@ func TestNewShaHashFromStr(t *testing.T) { // Empty string. { "", - btcwire.ShaHash{}, + wire.ShaHash{}, nil, }, // Single digit hash. { "1", - btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. + wire.ShaHash([wire.HashSize]byte{ // Make go vet happy. 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -138,7 +138,7 @@ func TestNewShaHashFromStr(t *testing.T) { // Block 203707 with stripped leading zeros. { "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc", - btcwire.ShaHash([btcwire.HashSize]byte{ // Make go vet happy. + wire.ShaHash([wire.HashSize]byte{ // Make go vet happy. 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7, 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b, 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b, @@ -150,14 +150,14 @@ func TestNewShaHashFromStr(t *testing.T) { // Hash string that is too long. { "01234567890123456789012345678901234567890123456789012345678912345", - btcwire.ShaHash{}, - btcwire.ErrHashStrSize, + wire.ShaHash{}, + wire.ErrHashStrSize, }, // Hash string that is contains non-hex chars. { "abcdefg", - btcwire.ShaHash{}, + wire.ShaHash{}, hex.InvalidByteError('g'), }, } @@ -166,7 +166,7 @@ func TestNewShaHashFromStr(t *testing.T) { unexpectedResultStr := "NewShaHashFromStr #%d got: %v want: %v" t.Logf("Running %d tests", len(tests)) for i, test := range tests { - result, err := btcwire.NewShaHashFromStr(test.in) + result, err := wire.NewShaHashFromStr(test.in) if err != test.err { t.Errorf(unexpectedErrStr, i, err, test.err) continue