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)