mirror of
				https://github.com/kaspanet/kaspad.git
				synced 2025-10-14 00:59:33 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			250 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) 2013-2016 The btcsuite developers
 | |
| // Use of this source code is governed by an ISC
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package wire
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 
 | |
| 	"github.com/kaspanet/kaspad/util/subnetworkid"
 | |
| 
 | |
| 	"github.com/kaspanet/kaspad/util/daghash"
 | |
| )
 | |
| 
 | |
| // 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
 | |
| 
 | |
| // MaxMassPerBlock is the maximum total transaction mass a block may have.
 | |
| const MaxMassPerBlock = 10000000
 | |
| 
 | |
| // MaxMassPerTx is the maximum total mass a transaction may have.
 | |
| const MaxMassPerTx = MaxMassPerBlock / 2
 | |
| 
 | |
| // maxTxPerBlock is the maximum number of transactions that could
 | |
| // possibly fit into a block.
 | |
| const maxTxPerBlock = (MaxMassPerBlock / 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 {
 | |
| 	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.
 | |
| type MsgBlock struct {
 | |
| 	Header       BlockHeader
 | |
| 	Transactions []*MsgTx
 | |
| }
 | |
| 
 | |
| // AddTransaction adds a transaction to the message.
 | |
| func (msg *MsgBlock) AddTransaction(tx *MsgTx) {
 | |
| 	msg.Transactions = append(msg.Transactions, tx)
 | |
| }
 | |
| 
 | |
| // ClearTransactions removes all transactions from the message.
 | |
| func (msg *MsgBlock) ClearTransactions() {
 | |
| 	msg.Transactions = make([]*MsgTx, 0, defaultTransactionAlloc)
 | |
| }
 | |
| 
 | |
| // 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 {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	txCount, err := ReadVarInt(r)
 | |
| 	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.
 | |
| 	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 {
 | |
| 			return err
 | |
| 		}
 | |
| 		msg.Transactions = append(msg.Transactions, &tx)
 | |
| 	}
 | |
| 
 | |
| 	return 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
 | |
| 	}
 | |
| 
 | |
| 	txCount, err := ReadVarInt(r)
 | |
| 	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.
 | |
| 	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.
 | |
| 	msg.Transactions = make([]*MsgTx, 0, txCount)
 | |
| 	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 {
 | |
| 	err := writeBlockHeader(w, pver, &msg.Header)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	err = WriteVarInt(w, uint64(len(msg.Transactions)))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	for _, tx := range msg.Transactions {
 | |
| 		err = tx.BtcEncode(w, pver)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	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)
 | |
| }
 | |
| 
 | |
| // SerializeSize returns the number of bytes it would take to serialize the
 | |
| // block.
 | |
| func (msg *MsgBlock) SerializeSize() int {
 | |
| 	// Block header bytes + Serialized varint size for the number of
 | |
| 	// transactions.
 | |
| 	n := msg.Header.SerializeSize() + 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 {
 | |
| 	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 {
 | |
| 	return MaxMessagePayload
 | |
| }
 | |
| 
 | |
| // BlockHash computes the block identifier hash for this block.
 | |
| func (msg *MsgBlock) BlockHash() *daghash.Hash {
 | |
| 	return msg.Header.BlockHash()
 | |
| }
 | |
| 
 | |
| // ConvertToPartial clears out all the payloads of the subnetworks that are
 | |
| // incompatible with the given subnetwork ID.
 | |
| // Note: this operation modifies the block in place.
 | |
| func (msg *MsgBlock) ConvertToPartial(subnetworkID *subnetworkid.SubnetworkID) {
 | |
| 	for _, tx := range msg.Transactions {
 | |
| 		if !tx.SubnetworkID.IsEqual(subnetworkID) {
 | |
| 			tx.Payload = []byte{}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // 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,
 | |
| 		Transactions: make([]*MsgTx, 0, defaultTransactionAlloc),
 | |
| 	}
 | |
| }
 | 
