1// Copyright (c) 2014-2015 The btcsuite developers
2// Use of this source code is governed by an ISC
3// license that can be found in the LICENSE file.
4
5package wire
6
7import (
8	"fmt"
9	"io"
10)
11
12// BloomUpdateType specifies how the filter is updated when a match is found
13type BloomUpdateType uint8
14
15const (
16	// BloomUpdateNone indicates the filter is not adjusted when a match is
17	// found.
18	BloomUpdateNone BloomUpdateType = 0
19
20	// BloomUpdateAll indicates if the filter matches any data element in a
21	// public key script, the outpoint is serialized and inserted into the
22	// filter.
23	BloomUpdateAll BloomUpdateType = 1
24
25	// BloomUpdateP2PubkeyOnly indicates if the filter matches a data
26	// element in a public key script and the script is of the standard
27	// pay-to-pubkey or multisig, the outpoint is serialized and inserted
28	// into the filter.
29	BloomUpdateP2PubkeyOnly BloomUpdateType = 2
30)
31
32const (
33	// MaxFilterLoadHashFuncs is the maximum number of hash functions to
34	// load into the Bloom filter.
35	MaxFilterLoadHashFuncs = 50
36
37	// MaxFilterLoadFilterSize is the maximum size in bytes a filter may be.
38	MaxFilterLoadFilterSize = 36000
39)
40
41// MsgFilterLoad implements the Message interface and represents a bitcoin
42// filterload message which is used to reset a Bloom filter.
43//
44// This message was not added until protocol version BIP0037Version.
45type MsgFilterLoad struct {
46	Filter    []byte
47	HashFuncs uint32
48	Tweak     uint32
49	Flags     BloomUpdateType
50}
51
52// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
53// This is part of the Message interface implementation.
54func (msg *MsgFilterLoad) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
55	if pver < BIP0037Version {
56		str := fmt.Sprintf("filterload message invalid for protocol "+
57			"version %d", pver)
58		return messageError("MsgFilterLoad.BtcDecode", str)
59	}
60
61	var err error
62	msg.Filter, err = ReadVarBytes(r, pver, MaxFilterLoadFilterSize,
63		"filterload filter size")
64	if err != nil {
65		return err
66	}
67
68	err = readElements(r, &msg.HashFuncs, &msg.Tweak, &msg.Flags)
69	if err != nil {
70		return err
71	}
72
73	if msg.HashFuncs > MaxFilterLoadHashFuncs {
74		str := fmt.Sprintf("too many filter hash functions for message "+
75			"[count %v, max %v]", msg.HashFuncs, MaxFilterLoadHashFuncs)
76		return messageError("MsgFilterLoad.BtcDecode", str)
77	}
78
79	return nil
80}
81
82// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
83// This is part of the Message interface implementation.
84func (msg *MsgFilterLoad) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
85	if pver < BIP0037Version {
86		str := fmt.Sprintf("filterload message invalid for protocol "+
87			"version %d", pver)
88		return messageError("MsgFilterLoad.BtcEncode", str)
89	}
90
91	size := len(msg.Filter)
92	if size > MaxFilterLoadFilterSize {
93		str := fmt.Sprintf("filterload filter size too large for message "+
94			"[size %v, max %v]", size, MaxFilterLoadFilterSize)
95		return messageError("MsgFilterLoad.BtcEncode", str)
96	}
97
98	if msg.HashFuncs > MaxFilterLoadHashFuncs {
99		str := fmt.Sprintf("too many filter hash functions for message "+
100			"[count %v, max %v]", msg.HashFuncs, MaxFilterLoadHashFuncs)
101		return messageError("MsgFilterLoad.BtcEncode", str)
102	}
103
104	err := WriteVarBytes(w, pver, msg.Filter)
105	if err != nil {
106		return err
107	}
108
109	return writeElements(w, msg.HashFuncs, msg.Tweak, msg.Flags)
110}
111
112// Command returns the protocol command string for the message.  This is part
113// of the Message interface implementation.
114func (msg *MsgFilterLoad) Command() string {
115	return CmdFilterLoad
116}
117
118// MaxPayloadLength returns the maximum length the payload can be for the
119// receiver.  This is part of the Message interface implementation.
120func (msg *MsgFilterLoad) MaxPayloadLength(pver uint32) uint32 {
121	// Num filter bytes (varInt) + filter + 4 bytes hash funcs +
122	// 4 bytes tweak + 1 byte flags.
123	return uint32(VarIntSerializeSize(MaxFilterLoadFilterSize)) +
124		MaxFilterLoadFilterSize + 9
125}
126
127// NewMsgFilterLoad returns a new bitcoin filterload message that conforms to
128// the Message interface.  See MsgFilterLoad for details.
129func NewMsgFilterLoad(filter []byte, hashFuncs uint32, tweak uint32, flags BloomUpdateType) *MsgFilterLoad {
130	return &MsgFilterLoad{
131		Filter:    filter,
132		HashFuncs: hashFuncs,
133		Tweak:     tweak,
134		Flags:     flags,
135	}
136}
137