package btcwire import ( "fmt" ) // ProtocolVersion is the peer protocol version implemented by this package. // It advertises support for compact filters, witness data, and the // sendaddrv2 and wtxidrelay messages. const ProtocolVersion = 70016 // Service bits advertised by peers in the version message and in network // addresses. const ( // ServiceNodeNetwork indicates a peer that can serve the full block chain. ServiceNodeNetwork uint64 = 1 // ServiceNodeWitness indicates a peer that can serve witness data. ServiceNodeWitness uint64 = 1 << 3 // ServiceNodeCompactFilters indicates a peer that can serve BIP157 // compact filters. ServiceNodeCompactFilters uint64 = 1 << 6 ) // MaxUserAgentSize is the largest user agent string accepted in a version // message, as specified by BIP14. const MaxUserAgentSize = 256 // Version is the first message exchanged with a peer. It announces the // protocol version, the services each side offers, and the sender's view of // the chain tip. type Version struct { // ProtocolVersion is the sender's protocol version. ProtocolVersion int32 // Services is the set of services offered by the sender. Services uint64 // Timestamp is the sender's time in seconds since the Unix epoch. Timestamp int64 // AddrRecv is the address the sender believes this message is reaching. AddrRecv NetAddress // AddrFrom is the address of the sender. AddrFrom NetAddress // Nonce is a randomly generated value used to detect self connections. Nonce uint64 // UserAgent is the BIP14 user agent string. UserAgent string // LastBlock is the height of the sender's best block. LastBlock int32 // Relay is whether the sender wants to receive unannounced transactions. // When decoding a payload that predates the field it defaults to true, // matching the behaviour of Bitcoin Core. Relay bool } // EncodePayload returns the wire encoding of the version message. Every // integer is little endian except the ports inside the network addresses, // which are big endian. func (v *Version) EncodePayload() ([]byte, error) { if len(v.UserAgent) > MaxUserAgentSize { return nil, fmt.Errorf( "btcwire: user agent is %d bytes, maximum is %d: %w", len(v.UserAgent), MaxUserAgentSize, ErrInvalidPayload, ) } var e Encoder e.Uint32(uint32(v.ProtocolVersion)) e.Uint64(v.Services) e.Uint64(uint64(v.Timestamp)) v.AddrRecv.encode(&e) v.AddrFrom.encode(&e) e.Uint64(v.Nonce) if err := WriteVarBytes(&e, []byte(v.UserAgent)); err != nil { return nil, fmt.Errorf("btcwire: encoding user agent: %w", err) } e.Uint32(uint32(v.LastBlock)) if v.Relay { e.Uint8(1) } else { e.Uint8(0) } return e.Bytes(), nil } // DecodePayload replaces v with the version message decoded from b. Unknown // trailing bytes are ignored so that newer protocol fields do not break // decoding. func (v *Version) DecodePayload(b []byte) error { d := NewDecoder(b) var ( out Version err error ) pv, err := d.Uint32() if err != nil { return fmt.Errorf("btcwire: decoding version protocol version: %w", err) } out.ProtocolVersion = int32(pv) if out.Services, err = d.Uint64(); err != nil { return fmt.Errorf("btcwire: decoding version services: %w", err) } timestamp, err := d.Uint64() if err != nil { return fmt.Errorf("btcwire: decoding version timestamp: %w", err) } out.Timestamp = int64(timestamp) if err = out.AddrRecv.decode(d); err != nil { return fmt.Errorf("btcwire: decoding version receiving address: %w", err) } if err = out.AddrFrom.decode(d); err != nil { return fmt.Errorf("btcwire: decoding version sending address: %w", err) } if out.Nonce, err = d.Uint64(); err != nil { return fmt.Errorf("btcwire: decoding version nonce: %w", err) } userAgent, err := ReadVarBytes(d, MaxUserAgentSize) if err != nil { return fmt.Errorf("btcwire: decoding version user agent: %w", err) } out.UserAgent = string(userAgent) lastBlock, err := d.Uint32() if err != nil { return fmt.Errorf("btcwire: decoding version last block: %w", err) } out.LastBlock = int32(lastBlock) // The relay flag is optional: it was added in protocol version 70001. out.Relay = true if d.Remaining() > 0 { relay, err := d.Uint8() if err != nil { return fmt.Errorf("btcwire: decoding version relay flag: %w", err) } out.Relay = relay != 0 } *v = out return nil } // VerAck acknowledges a peer's version message. type VerAck struct{} // EncodePayload returns the empty verack payload. func (v *VerAck) EncodePayload() ([]byte, error) { return encodeEmptyPayload() } // DecodePayload verifies that a verack payload is empty. func (v *VerAck) DecodePayload(b []byte) error { return decodeEmptyPayload("verack", b) } // SendHeaders asks a peer to announce new blocks with a headers message // instead of an inv message. type SendHeaders struct{} // EncodePayload returns the empty sendheaders payload. func (s *SendHeaders) EncodePayload() ([]byte, error) { return encodeEmptyPayload() } // DecodePayload verifies that a sendheaders payload is empty. func (s *SendHeaders) DecodePayload(b []byte) error { return decodeEmptyPayload("sendheaders", b) } // WtxidRelay tells a peer to compute transaction relay identifiers from the // wtxid. type WtxidRelay struct{} // EncodePayload returns the empty wtxidrelay payload. func (w *WtxidRelay) EncodePayload() ([]byte, error) { return encodeEmptyPayload() } // DecodePayload verifies that a wtxidrelay payload is empty. func (w *WtxidRelay) DecodePayload(b []byte) error { return decodeEmptyPayload("wtxidrelay", b) } // SendAddrV2 tells a peer that the sender understands the addrv2 message. type SendAddrV2 struct{} // EncodePayload returns the empty sendaddrv2 payload. func (s *SendAddrV2) EncodePayload() ([]byte, error) { return encodeEmptyPayload() } // DecodePayload verifies that a sendaddrv2 payload is empty. func (s *SendAddrV2) DecodePayload(b []byte) error { return decodeEmptyPayload("sendaddrv2", b) } // Ping is sent to check that a peer is still reachable. type Ping struct { // Nonce is echoed by the peer in its pong. Nonce uint64 } // EncodePayload returns the wire encoding of the ping message. func (p *Ping) EncodePayload() ([]byte, error) { return encodeNonceMessage(p.Nonce) } // DecodePayload replaces p with the ping message decoded from b. func (p *Ping) DecodePayload(b []byte) error { nonce, err := decodeNonceMessage("ping", b) if err != nil { return err } p.Nonce = nonce return nil } // Pong answers a ping. type Pong struct { // Nonce is the nonce of the ping being answered. Nonce uint64 } // EncodePayload returns the wire encoding of the pong message. func (p *Pong) EncodePayload() ([]byte, error) { return encodeNonceMessage(p.Nonce) } // DecodePayload replaces p with the pong message decoded from b. func (p *Pong) DecodePayload(b []byte) error { nonce, err := decodeNonceMessage("pong", b) if err != nil { return err } p.Nonce = nonce return nil } // FeeFilter asks a peer to announce only transactions that pay at least // FeeRate satoshis per kilobyte. type FeeFilter struct { // FeeRate is the minimum fee rate in satoshis per kilobyte. FeeRate int64 } // EncodePayload returns the wire encoding of the feefilter message. func (f *FeeFilter) EncodePayload() ([]byte, error) { var e Encoder e.Uint64(uint64(f.FeeRate)) return e.Bytes(), nil } // DecodePayload replaces f with the feefilter message decoded from b. func (f *FeeFilter) DecodePayload(b []byte) error { if len(b) != 8 { return fmt.Errorf( "btcwire: feefilter payload must be 8 bytes, got %d: %w", len(b), ErrInvalidPayload, ) } d := NewDecoder(b) rate, err := d.Int64() if err != nil { return fmt.Errorf("btcwire: decoding feefilter rate: %w", err) } f.FeeRate = rate return nil } // encodeEmptyPayload is the EncodePayload implementation shared by messages // whose payload has no fields. func encodeEmptyPayload() ([]byte, error) { return nil, nil } // decodeEmptyPayload rejects a payload for a message whose payload must be // empty. func decodeEmptyPayload(name string, b []byte) error { if len(b) != 0 { return fmt.Errorf( "btcwire: %s payload must be empty, got %d bytes: %w", name, len(b), ErrInvalidPayload, ) } return nil } // encodeNonceMessage encodes the payload shared by ping and pong. func encodeNonceMessage(nonce uint64) ([]byte, error) { var e Encoder e.Uint64(nonce) return e.Bytes(), nil } // decodeNonceMessage decodes the payload shared by ping and pong. func decodeNonceMessage(name string, b []byte) (uint64, error) { if len(b) != 8 { return 0, fmt.Errorf( "btcwire: %s payload must be 8 bytes, got %d: %w", name, len(b), ErrInvalidPayload, ) } nonce, err := NewDecoder(b).Uint64() if err != nil { return 0, fmt.Errorf("btcwire: decoding %s nonce: %w", name, err) } return nonce, nil }