inv.go raw
1 package btcwire
2
3 import (
4 "fmt"
5
6 "git.smesh.lol/nostrino/pkg/crypto/chainhash"
7 )
8
9 // Inventory vector types.
10 const (
11 // InvVectTypeError is the reserved error type.
12 InvVectTypeError uint32 = 0
13
14 // InvVectTypeTx identifies a transaction by txid.
15 InvVectTypeTx uint32 = 1
16
17 // InvVectTypeBlock identifies a block by block hash.
18 InvVectTypeBlock uint32 = 2
19
20 // InvVectTypeFilteredBlock identifies a filtered block.
21 InvVectTypeFilteredBlock uint32 = 3
22
23 // InvVectTypeWitnessTx identifies a transaction by wtxid.
24 InvVectTypeWitnessTx uint32 = 0x40000001
25 )
26
27 // MaxInvPerMsg is the largest number of inventory vectors a single inv,
28 // getdata, or notfound message may carry.
29 const MaxInvPerMsg = 50000
30
31 // InvVect is one inventory vector: a type and the hash of the object it
32 // identifies.
33 type InvVect struct {
34 // Type is one of the InvVectType constants.
35 Type uint32
36
37 // Hash identifies the object. Its interpretation depends on Type.
38 Hash chainhash.Hash
39 }
40
41 // Inv announces objects a peer has available.
42 type Inv struct {
43 // InvList is the announced inventory.
44 InvList []InvVect
45 }
46
47 // EncodePayload returns the wire encoding of the inv message.
48 func (v *Inv) EncodePayload() ([]byte, error) {
49 return encodeInvList("inv", v.InvList)
50 }
51
52 // DecodePayload replaces v with the inv message decoded from b.
53 func (v *Inv) DecodePayload(b []byte) error {
54 list, err := decodeInvList("inv", b)
55 if err != nil {
56 return err
57 }
58 v.InvList = list
59 return nil
60 }
61
62 // GetData requests objects announced by a peer.
63 type GetData struct {
64 // InvList is the requested inventory.
65 InvList []InvVect
66 }
67
68 // EncodePayload returns the wire encoding of the getdata message.
69 func (g *GetData) EncodePayload() ([]byte, error) {
70 return encodeInvList("getdata", g.InvList)
71 }
72
73 // DecodePayload replaces g with the getdata message decoded from b.
74 func (g *GetData) DecodePayload(b []byte) error {
75 list, err := decodeInvList("getdata", b)
76 if err != nil {
77 return err
78 }
79 g.InvList = list
80 return nil
81 }
82
83 // NotFound reports inventory that a peer could not provide.
84 type NotFound struct {
85 // InvList is the unavailable inventory.
86 InvList []InvVect
87 }
88
89 // EncodePayload returns the wire encoding of the notfound message.
90 func (n *NotFound) EncodePayload() ([]byte, error) {
91 return encodeInvList("notfound", n.InvList)
92 }
93
94 // DecodePayload replaces n with the notfound message decoded from b.
95 func (n *NotFound) DecodePayload(b []byte) error {
96 list, err := decodeInvList("notfound", b)
97 if err != nil {
98 return err
99 }
100 n.InvList = list
101 return nil
102 }
103
104 // invVectSize is the encoded size of one inventory vector.
105 const invVectSize = 4 + chainhash.HashSize
106
107 // encodeInvList appends a compact size count followed by the inventory
108 // vectors.
109 func encodeInvList(name string, list []InvVect) ([]byte, error) {
110 if len(list) > MaxInvPerMsg {
111 return nil, fmt.Errorf(
112 "btcwire: %s carries %d inventory vectors, maximum is %d: %w",
113 name, len(list), MaxInvPerMsg, ErrTooManyItems,
114 )
115 }
116 var e Encoder
117 e.CompactSize(uint64(len(list)))
118 for i := range list {
119 e.Uint32(list[i].Type)
120 e.Hash(list[i].Hash)
121 }
122 return e.Bytes(), nil
123 }
124
125 // decodeInvList decodes a compact size count followed by that many inventory
126 // vectors.
127 func decodeInvList(name string, b []byte) ([]InvVect, error) {
128 d := NewDecoder(b)
129 count, err := d.count(MaxInvPerMsg, invVectSize, name+" inventory vector")
130 if err != nil {
131 return nil, err
132 }
133 list := make([]InvVect, count)
134 for i := range list {
135 if list[i].Type, err = d.Uint32(); err != nil {
136 return nil, fmt.Errorf("btcwire: decoding %s inventory type %d: %w", name, i, err)
137 }
138 if list[i].Hash, err = d.Hash(); err != nil {
139 return nil, fmt.Errorf("btcwire: decoding %s inventory hash %d: %w", name, i, err)
140 }
141 }
142 return list, nil
143 }
144