5f971e10e6
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.
107 lines
3 KiB
Go
107 lines
3 KiB
Go
// 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 := fmt.Sprintf("too many invvect in message [max %v]",
|
|
MaxInvPerMsg)
|
|
return messageError("MsgNotFound.AddInvVect", str)
|
|
}
|
|
|
|
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 := fmt.Sprintf("too many invvect in message [%v]", count)
|
|
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)
|
|
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 := fmt.Sprintf("too many invvect in message [%v]", count)
|
|
return messageError("MsgNotFound.BtcEncode", str)
|
|
}
|
|
|
|
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{
|
|
InvList: make([]*InvVect, 0, defaultInvListAlloc),
|
|
}
|
|
}
|