162 lines
4.5 KiB
Go
162 lines
4.5 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 (
|
|
"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 {
|
|
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,
|
|
}
|
|
}
|