wire: Implement SFNodeBloom (BIP0111).

SFNodeBloom is a new service flag that a node is required to use to
indicate that it supports bloom filtering.  This includes a protocol
version bump to 70011 and a wire version bump to 0.3.0.

btcd:
The SFNodeBloom flag is set by default.  A new configuration option
--nopeerbloomfilters has been added to to disable bloom filtering.

Any node advertising a version greater than or equal to 70011 that
attempts to use bloom filtering will be disconnected if bloom
filtering is disabled.

This mimics Bitcoin Core commit afb0ccaf9c9e4e8fac7db3564c4e19c9218c6b03
This commit is contained in:
David Hill 2015-08-24 11:48:59 -04:00
parent 064cc8e7c3
commit c9ee3d9c5e
9 changed files with 156 additions and 98 deletions

View file

@ -116,6 +116,7 @@ type config struct {
GetWorkKeys []string `long:"getworkkey" description:"DEPRECATED -- Use the --miningaddr option instead"` GetWorkKeys []string `long:"getworkkey" description:"DEPRECATED -- Use the --miningaddr option instead"`
AddrIndex bool `long:"addrindex" description:"Build and maintain a full address index. Currently only supported by leveldb."` AddrIndex bool `long:"addrindex" description:"Build and maintain a full address index. Currently only supported by leveldb."`
DropAddrIndex bool `long:"dropaddrindex" description:"Deletes the address-based transaction index from the database on start up, and the exits."` DropAddrIndex bool `long:"dropaddrindex" description:"Deletes the address-based transaction index from the database on start up, and the exits."`
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support."`
onionlookup func(string) ([]net.IP, error) onionlookup func(string) ([]net.IP, error)
lookup func(string) ([]net.IP, error) lookup func(string) ([]net.IP, error)
oniondial func(string, string) (net.Conn, error) oniondial func(string, string) (net.Conn, error)

165
doc.go
View file

@ -21,86 +21,91 @@ Usage:
btcd [OPTIONS] btcd [OPTIONS]
Application Options: Application Options:
-V, --version Display version information and exit -V, --version Display version information and exit
-C, --configfile= Path to configuration file -C, --configfile= Path to configuration file
-b, --datadir= Directory to store data -b, --datadir= Directory to store data
-a, --addpeer= Add a peer to connect with at startup --logdir= Directory to log output.
--connect= Connect only to the specified peers at startup -a, --addpeer= Add a peer to connect with at startup
--nolisten Disable listening for incoming connections -- NOTE: --connect= Connect only to the specified peers at startup
Listening is automatically disabled if the --connect --nolisten Disable listening for incoming connections -- NOTE:
or --proxy options are used without also specifying Listening is automatically disabled if the --connect
listen interfaces via --listen or --proxy options are used without also specifying
--listen= Add an interface/port to listen for connections listen interfaces via --listen
(default all interfaces port: 8333, testnet: 18333) --listen= Add an interface/port to listen for connections
--maxpeers= Max number of inbound and outbound peers (125) (default all interfaces port: 8333, testnet: 18333)
--banduration= How long to ban misbehaving peers. Valid time units --maxpeers= Max number of inbound and outbound peers (125)
are {s, m, h}. Minimum 1 second (24h0m0s) --banduration= How long to ban misbehaving peers. Valid time units
-u, --rpcuser= Username for RPC connections are {s, m, h}. Minimum 1 second (24h0m0s)
-P, --rpcpass= Password for RPC connections -u, --rpcuser= Username for RPC connections
--rpclimituser= Username for limited RPC connections -P, --rpcpass= Password for RPC connections
--rpclimitpass= Password for limited RPC connections --rpclimituser= Username for limited RPC connections
--rpclisten= Add an interface/port to listen for RPC connections --rpclimitpass= Password for limited RPC connections
(default port: 8334, testnet: 18334) --rpclisten= Add an interface/port to listen for RPC connections
--rpccert= File containing the certificate file (default port: 8334, testnet: 18334)
--rpckey= File containing the certificate key --rpccert= File containing the certificate file
--rpcmaxclients= Max number of RPC clients for standard connections --rpckey= File containing the certificate key
(10) --rpcmaxclients= Max number of RPC clients for standard connections
--rpcmaxwebsockets= Max number of RPC clients for standard connections (10)
(25) --rpcmaxwebsockets= Max number of RPC websocket connections (25)
--norpc Disable built-in RPC server -- NOTE: The RPC server --norpc Disable built-in RPC server -- NOTE: The RPC server
is disabled by default if no rpcuser/rpcpass is is disabled by default if no rpcuser/rpcpass or
specified rpclimituser/rpclimitpass is specified
--notls Disable TLS for the RPC server -- NOTE: This is only --notls Disable TLS for the RPC server -- NOTE: This is only
allowed if the RPC server is bound to localhost allowed if the RPC server is bound to localhost
--nodnsseed Disable DNS seeding for peers --nodnsseed Disable DNS seeding for peers
--externalip: Add an ip to the list of local addresses we claim to --externalip= Add an ip to the list of local addresses we claim to
listen on to peers listen on to peers
--proxy= Connect via SOCKS5 proxy (eg. 127.0.0.1:9050) --proxy= Connect via SOCKS5 proxy (eg. 127.0.0.1:9050)
--proxyuser= Username for proxy server --proxyuser= Username for proxy server
--proxypass= Password for proxy server --proxypass= Password for proxy server
--onion= Connect to tor hidden services via SOCKS5 proxy (eg. --onion= Connect to tor hidden services via SOCKS5 proxy
127.0.0.1:9050) (eg. 127.0.0.1:9050)
--onionuser= Username for onion proxy server --onionuser= Username for onion proxy server
--onionpass= Password for onion proxy server --onionpass= Password for onion proxy server
--noonion= Disable connecting to tor hidden services --noonion Disable connecting to tor hidden services
--torisolation Enable Tor stream isolation by randomizing user --torisolation Enable Tor stream isolation by randomizing user
credentials for each connection. credentials for each connection.
--testnet= Use the test network --testnet Use the test network
--regtest= Use the regression test network --regtest Use the regression test network
--nocheckpoints= Disable built-in checkpoints. Don't do this unless --simnet Use the simulation test network
you know what you're doing. --nocheckpoints Disable built-in checkpoints. Don't do this unless
--dbtype= Database backend to use for the Block Chain (leveldb) you know what you're doing.
--profile= Enable HTTP profiling on given port -- NOTE port must --dbtype= Database backend to use for the Block Chain
be between 1024 and 65536 (6060) (leveldb)
--cpuprofile= Write CPU profile to the specified file --profile= Enable HTTP profiling on given port -- NOTE port
-d, --debuglevel: Logging level for all subsystems {trace, debug, info, must be between 1024 and 65536
warn, error, critical} -- You may also specify --cpuprofile= Write CPU profile to the specified file
<subsystem>=<level>,<subsystem2>=<level>,... to set -d, --debuglevel= Logging level for all subsystems {trace, debug,
the log level for individual subsystems -- Use show info, warn, error, critical} -- You may also specify
to list available subsystems (info) <subsystem>=<level>,<subsystem2>=<level>,... to set
--upnp Use UPnP to map our listening port outside of NAT the log level for individual subsystems -- Use show
--limitfreerelay= Limit relay of transactions with no transaction fee to list available subsystems (info)
to the given amount in thousands of bytes per minute --upnp Use UPnP to map our listening port outside of NAT
(15) --limitfreerelay= Limit relay of transactions with no transaction fee
--norelaypriority Do not require free or low-fee transactions to have to the given amount in thousands of bytes per
high priority for relaying minute (15)
--maxorphantx= Max number of orphan transactions to keep in memory --norelaypriority Do not require free or low-fee transactions to have
(1000) high priority for relaying
--generate= Generate (mine) bitcoins using the CPU --maxorphantx= Max number of orphan transactions to keep in memory
--miningaddr= Add the specified payment address to the list of (1000)
addresses to use for generated blocks -- At least --generate Generate (mine) bitcoins using the CPU
one address is required if the generate option is set --miningaddr= Add the specified payment address to the list of
--blockminsize= Mininum block size in bytes to be used when creating addresses to use for generated blocks -- At least
a block one address is required if the generate option is
--blockmaxsize= Maximum block size in bytes to be used when creating set
a block (750000) --blockminsize= Mininum block size in bytes to be used when creating
--blockprioritysize= Size in bytes for high-priority/low-fee transactions a block
when creating a block (50000) --blockmaxsize= Maximum block size in bytes to be used when creating
--getworkkey= DEPRECATED -- Use the --miningaddr option instead a block (750000)
--addrindex= Build and maintain a full address index. Currently --blockprioritysize= Size in bytes for high-priority/low-fee transactions
only supported by leveldb. when creating a block (50000)
--dropaddrindex= Deletes the address-based transaction index from the --getworkkey= DEPRECATED -- Use the --miningaddr option instead
database on start up, and the exits. --addrindex Build and maintain a full address index. Currently
only supported by leveldb.
--dropaddrindex Deletes the address-based transaction index from the
database on start up, and the exits.
--nopeerbloomfilters Disable bloom filtering support.
Help Options: Help Options:
-h, --help Show this help message -h, --help Show this help message

37
peer.go
View file

@ -28,7 +28,7 @@ import (
const ( const (
// maxProtocolVersion is the max protocol version the peer supports. // maxProtocolVersion is the max protocol version the peer supports.
maxProtocolVersion = 70002 maxProtocolVersion = 70011
// outputBufferSize is the number of elements the output channels use. // outputBufferSize is the number of elements the output channels use.
outputBufferSize = 50 outputBufferSize = 50
@ -335,8 +335,8 @@ func (p *peer) pushVersionMsg() error {
// by the remote peer in its version message // by the remote peer in its version message
msg.AddrYou.Services = wire.SFNodeNetwork msg.AddrYou.Services = wire.SFNodeNetwork
// Advertise that we're a full node. // Advertise our supported services.
msg.Services = wire.SFNodeNetwork msg.Services = p.server.services
// Advertise our max supported protocol version. // Advertise our max supported protocol version.
msg.ProtocolVersion = maxProtocolVersion msg.ProtocolVersion = maxProtocolVersion
@ -1088,11 +1088,33 @@ func (p *peer) handleGetHeadersMsg(msg *wire.MsgGetHeaders) {
p.QueueMessage(headersMsg, nil) p.QueueMessage(headersMsg, nil)
} }
// isValidBIP0111 is a helper function for the bloom filter commands to check
// BIP0111 compliance.
func (p *peer) isValidBIP0111(cmd string) bool {
if p.server.services&wire.SFNodeBloom != wire.SFNodeBloom {
if p.ProtocolVersion() >= wire.BIP0111Version {
peerLog.Debugf("%s sent an unsupported %s "+
"request -- disconnecting", p, cmd)
p.Disconnect()
} else {
peerLog.Debugf("Ignoring %s request from %s -- bloom "+
"support is disabled", cmd, p)
}
return false
}
return true
}
// handleFilterAddMsg is invoked when a peer receives a filteradd bitcoin // handleFilterAddMsg is invoked when a peer receives a filteradd bitcoin
// message and is used by remote peers to add data to an already loaded bloom // message and is used by remote peers to add data to an already loaded bloom
// filter. The peer will be disconnected if a filter is not loaded when this // filter. The peer will be disconnected if a filter is not loaded when this
// message is received. // message is received.
func (p *peer) handleFilterAddMsg(msg *wire.MsgFilterAdd) { func (p *peer) handleFilterAddMsg(msg *wire.MsgFilterAdd) {
if !p.isValidBIP0111(msg.Command()) {
return
}
if !p.filter.IsLoaded() { if !p.filter.IsLoaded() {
peerLog.Debugf("%s sent a filteradd request with no filter "+ peerLog.Debugf("%s sent a filteradd request with no filter "+
"loaded -- disconnecting", p) "loaded -- disconnecting", p)
@ -1108,12 +1130,17 @@ func (p *peer) handleFilterAddMsg(msg *wire.MsgFilterAdd) {
// The peer will be disconnected if a filter is not loaded when this message is // The peer will be disconnected if a filter is not loaded when this message is
// received. // received.
func (p *peer) handleFilterClearMsg(msg *wire.MsgFilterClear) { func (p *peer) handleFilterClearMsg(msg *wire.MsgFilterClear) {
if !p.isValidBIP0111(msg.Command()) {
return
}
if !p.filter.IsLoaded() { if !p.filter.IsLoaded() {
peerLog.Debugf("%s sent a filterclear request with no "+ peerLog.Debugf("%s sent a filterclear request with no "+
"filter loaded -- disconnecting", p) "filter loaded -- disconnecting", p)
p.Disconnect() p.Disconnect()
return return
} }
p.filter.Unload() p.filter.Unload()
} }
@ -1121,6 +1148,10 @@ func (p *peer) handleFilterClearMsg(msg *wire.MsgFilterClear) {
// message and it used to load a bloom filter that should be used for delivering // message and it used to load a bloom filter that should be used for delivering
// merkle blocks and associated transactions that match the filter. // merkle blocks and associated transactions that match the filter.
func (p *peer) handleFilterLoadMsg(msg *wire.MsgFilterLoad) { func (p *peer) handleFilterLoadMsg(msg *wire.MsgFilterLoad) {
if !p.isValidBIP0111(msg.Command()) {
return
}
// Transaction relay is no longer disabled once a filterload message is // Transaction relay is no longer disabled once a filterload message is
// received regardless of its original state. // received regardless of its original state.
p.relayMtx.Lock() p.relayMtx.Lock()

View file

@ -144,6 +144,8 @@
; Disable listening for incoming connections. This will override all listeners. ; Disable listening for incoming connections. This will override all listeners.
; nolisten=1 ; nolisten=1
; Disable peer bloom filtering. See BIP0111.
; nopeerbloomfilters=1
; ------------------------------------------------------------------------------ ; ------------------------------------------------------------------------------
; RPC server options - The following options control the built-in RPC server ; RPC server options - The following options control the built-in RPC server

View file

@ -28,16 +28,16 @@ import (
) )
const ( const (
// These constants are used by the DNS seed code to pick a random last seen // These constants are used by the DNS seed code to pick a random last
// time. // seen time.
secondsIn3Days int32 = 24 * 60 * 60 * 3 secondsIn3Days int32 = 24 * 60 * 60 * 3
secondsIn4Days int32 = 24 * 60 * 60 * 4 secondsIn4Days int32 = 24 * 60 * 60 * 4
) )
const ( const (
// supportedServices describes which services are supported by the // defaultServices describes the default services that are supported by
// server. // the server.
supportedServices = wire.SFNodeNetwork defaultServices = wire.SFNodeNetwork | wire.SFNodeBloom
// defaultMaxOutbound is the default number of max outbound peers. // defaultMaxOutbound is the default number of max outbound peers.
defaultMaxOutbound = 8 defaultMaxOutbound = 8
@ -109,6 +109,7 @@ type server struct {
nat NAT nat NAT
db database.Db db database.Db
timeSource blockchain.MedianTimeSource timeSource blockchain.MedianTimeSource
services wire.ServiceFlag
} }
type peerState struct { type peerState struct {
@ -1216,7 +1217,7 @@ out:
continue out continue out
} }
na := wire.NewNetAddressIPPort(externalip, uint16(listenPort), na := wire.NewNetAddressIPPort(externalip, uint16(listenPort),
wire.SFNodeNetwork) s.services)
err = s.addrManager.AddLocalAddress(na, addrmgr.UpnpPrio) err = s.addrManager.AddLocalAddress(na, addrmgr.UpnpPrio)
if err != nil { if err != nil {
// XXX DeletePortMapping? // XXX DeletePortMapping?
@ -1250,6 +1251,11 @@ func newServer(listenAddrs []string, db database.Db, chainParams *chaincfg.Param
return nil, err return nil, err
} }
services := defaultServices
if cfg.NoPeerBloomFilters {
services &^= wire.SFNodeBloom
}
amgr := addrmgr.New(cfg.DataDir, btcdLookup) amgr := addrmgr.New(cfg.DataDir, btcdLookup)
var listeners []net.Listener var listeners []net.Listener
@ -1287,7 +1293,7 @@ func newServer(listenAddrs []string, db database.Db, chainParams *chaincfg.Param
eport = uint16(port) eport = uint16(port)
} }
na, err := amgr.HostToNetAddress(host, eport, na, err := amgr.HostToNetAddress(host, eport,
wire.SFNodeNetwork) services)
if err != nil { if err != nil {
srvrLog.Warnf("Not adding %s as "+ srvrLog.Warnf("Not adding %s as "+
"externalip: %v", sip, err) "externalip: %v", sip, err)
@ -1323,7 +1329,7 @@ func newServer(listenAddrs []string, db database.Db, chainParams *chaincfg.Param
continue continue
} }
na := wire.NewNetAddressIPPort(ip, na := wire.NewNetAddressIPPort(ip,
uint16(port), wire.SFNodeNetwork) uint16(port), services)
if discover { if discover {
err = amgr.AddLocalAddress(na, addrmgr.InterfacePrio) err = amgr.AddLocalAddress(na, addrmgr.InterfacePrio)
if err != nil { if err != nil {
@ -1394,6 +1400,7 @@ func newServer(listenAddrs []string, db database.Db, chainParams *chaincfg.Param
nat: nat, nat: nat,
db: db, db: db,
timeSource: blockchain.NewMedianTime(), timeSource: blockchain.NewMedianTime(),
services: services,
} }
bm, err := newBlockManager(&s) bm, err := newBlockManager(&s)
if err != nil { if err != nil {

View file

@ -151,9 +151,10 @@ Bitcoin Improvement Proposals
This package includes spec changes outlined by the following BIPs: This package includes spec changes outlined by the following BIPs:
BIP0014 (https://en.bitcoin.it/wiki/BIP_0014) BIP0014 (https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki)
BIP0031 (https://en.bitcoin.it/wiki/BIP_0031) BIP0031 (https://github.com/bitcoin/bips/blob/master/bip-0031.mediawiki)
BIP0035 (https://en.bitcoin.it/wiki/BIP_0035) BIP0035 (https://github.com/bitcoin/bips/blob/master/bip-0035.mediawiki)
BIP0037 (https://en.bitcoin.it/wiki/BIP_0037) BIP0037 (https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki)
BIP0111 (https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki)
*/ */
package wire package wire

View file

@ -18,7 +18,7 @@ import (
const MaxUserAgentLen = 2000 const MaxUserAgentLen = 2000
// DefaultUserAgent for wire in the stack // DefaultUserAgent for wire in the stack
const DefaultUserAgent = "/btcwire:0.2.1/" const DefaultUserAgent = "/btcwire:0.3.0/"
// MsgVersion implements the Message interface and represents a bitcoin version // MsgVersion implements the Message interface and represents a bitcoin version
// message. It is used for a peer to advertise itself as soon as an outbound // message. It is used for a peer to advertise itself as soon as an outbound

View file

@ -12,7 +12,7 @@ import (
const ( const (
// ProtocolVersion is the latest protocol version this package supports. // ProtocolVersion is the latest protocol version this package supports.
ProtocolVersion uint32 = 70002 ProtocolVersion uint32 = 70011
// MultipleAddressVersion is the protocol version which added multiple // MultipleAddressVersion is the protocol version which added multiple
// addresses per message (pver >= MultipleAddressVersion). // addresses per message (pver >= MultipleAddressVersion).
@ -35,6 +35,10 @@ const (
// with a relay flag (pver >= BIP0037Version). // with a relay flag (pver >= BIP0037Version).
BIP0037Version uint32 = 70001 BIP0037Version uint32 = 70001
// BIP0111Version is the protocol version which added the SFNodeBloom
// service flag.
BIP0111Version uint32 = 70011
// RejectVersion is the protocol version which added a new reject // RejectVersion is the protocol version which added a new reject
// message. // message.
RejectVersion uint32 = 70002 RejectVersion uint32 = 70002
@ -50,12 +54,17 @@ const (
// SFNodeGetUTXO is a flag used to indicate a peer supports the // SFNodeGetUTXO is a flag used to indicate a peer supports the
// getutxos and utxos commands (BIP0064). // getutxos and utxos commands (BIP0064).
SFNodeGetUTXO SFNodeGetUTXO
// SFNodeBloom is a flag used to indiciate a peer supports bloom
// filtering.
SFNodeBloom
) )
// Map of service flags back to their constant names for pretty printing. // Map of service flags back to their constant names for pretty printing.
var sfStrings = map[ServiceFlag]string{ var sfStrings = map[ServiceFlag]string{
SFNodeNetwork: "SFNodeNetwork", SFNodeNetwork: "SFNodeNetwork",
SFNodeGetUTXO: "SFNodeGetUTXO", SFNodeGetUTXO: "SFNodeGetUTXO",
SFNodeBloom: "SFNodeBloom",
} }
// orderedSFStrings is an ordered list of service flags from highest to // orderedSFStrings is an ordered list of service flags from highest to
@ -63,6 +72,7 @@ var sfStrings = map[ServiceFlag]string{
var orderedSFStrings = []ServiceFlag{ var orderedSFStrings = []ServiceFlag{
SFNodeNetwork, SFNodeNetwork,
SFNodeGetUTXO, SFNodeGetUTXO,
SFNodeBloom,
} }
// String returns the ServiceFlag in human-readable form. // String returns the ServiceFlag in human-readable form.

View file

@ -19,7 +19,8 @@ func TestServiceFlagStringer(t *testing.T) {
{0, "0x0"}, {0, "0x0"},
{wire.SFNodeNetwork, "SFNodeNetwork"}, {wire.SFNodeNetwork, "SFNodeNetwork"},
{wire.SFNodeGetUTXO, "SFNodeGetUTXO"}, {wire.SFNodeGetUTXO, "SFNodeGetUTXO"},
{0xffffffff, "SFNodeNetwork|SFNodeGetUTXO|0xfffffffc"}, {wire.SFNodeBloom, "SFNodeBloom"},
{0xffffffff, "SFNodeNetwork|SFNodeGetUTXO|SFNodeBloom|0xfffffff8"},
} }
t.Logf("Running %d tests", len(tests)) t.Logf("Running %d tests", len(tests))