/
msggetblocktxns.go
119 lines (104 loc) · 3.59 KB
/
msggetblocktxns.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package wire
import (
"errors"
"fmt"
"github.com/gcash/bchd/chaincfg/chainhash"
"io"
)
// MsgGetBlockTxns implements the Message interface and represents a Bitcoin getblocktxn
// message. It is used to request missing transactions as part of the compact block
// protocol.
type MsgGetBlockTxns struct {
BlockHash chainhash.Hash
Indexes []uint32
}
// BchDecode decodes r using the bitcoin protocol encoding into the receiver.
// This is part of the Message interface implementation.
func (msg *MsgGetBlockTxns) BchDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
if pver < BIP0152Version {
str := fmt.Sprintf("getblocktxn message invalid for protocol "+
"version %d", pver)
return messageError("MsgGetBlockTxns.BchDecode", str)
}
if err := readElement(r, &msg.BlockHash); err != nil {
return err
}
indexCount, err := ReadVarInt(r, pver)
if err != nil {
return err
}
for i := uint64(0); i < indexCount; i++ {
index, err := ReadVarInt(r, pver)
if err != nil {
return err
}
msg.Indexes = append(msg.Indexes, uint32(index))
}
return nil
}
// BchEncode encodes the receiver to w using the bitcoin protocol encoding.
// This is part of the Message interface implementation.
func (msg *MsgGetBlockTxns) BchEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
if pver < BIP0152Version {
str := fmt.Sprintf("sendcmpct message invalid for protocol "+
"version %d", pver)
return messageError("MsgSendCmpct.BchDecode", str)
}
if err := writeElement(w, &msg.BlockHash); err != nil {
return err
}
if err := WriteVarInt(w, pver, uint64(len(msg.Indexes))); err != nil {
return err
}
for _, index := range msg.Indexes {
if err := WriteVarInt(w, pver, uint64(index)); 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 *MsgGetBlockTxns) Command() string {
return CmdGetBlockTxns
}
// MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation.
func (msg *MsgGetBlockTxns) MaxPayloadLength(pver uint32) uint32 {
// In practice this will always be less than the payload but the number
// of txs in a block can vary so we really don't know the real max.
return maxMessagePayload()
}
// RequestedTransactions extracts the transactions that were requested by this
// message from the given block and returns them.
func (msg *MsgGetBlockTxns) RequestedTransactions(block *MsgBlock) ([]*MsgTx, error) {
var requestedTxs []*MsgTx
lastIndex := uint32(0)
for _, i := range msg.Indexes {
if i+lastIndex > uint32(len(block.Transactions)-1) {
return nil, errors.New("transaction index out of range")
}
requestedTxs = append(requestedTxs, block.Transactions[i+lastIndex])
lastIndex += i + 1
}
return requestedTxs, nil
}
// NewMsgGetBlockTxnsFromBlock parses a block and for each nil transasction
// ads a index to the getblocktxn message that is returned.
func NewMsgGetBlockTxnsFromBlock(block *MsgBlock) *MsgGetBlockTxns {
msg := &MsgGetBlockTxns{BlockHash: block.BlockHash()}
lastIndex := 0
for i, tx := range block.Transactions {
if tx == nil {
msg.Indexes = append(msg.Indexes, uint32(i-lastIndex))
lastIndex = i + 1
}
}
return msg
}
// NewMsgGetBlockTxns returns a new bitcoin getblocktxn message that conforms to the
// Message interface using the passed parameters and defaults for the remaining
// fields.
func NewMsgGetBlockTxns(blockHash chainhash.Hash, indexes []uint32) *MsgGetBlockTxns {
return &MsgGetBlockTxns{BlockHash: blockHash, Indexes: indexes}
}