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"`
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."`
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support."`
onionlookup func(string) ([]net.IP, error)
lookup func(string) ([]net.IP, error)
oniondial func(string, string) (net.Conn, error)

165
doc.go
View file

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

37
peer.go
View file

@ -28,7 +28,7 @@ import (
const (
// maxProtocolVersion is the max protocol version the peer supports.
maxProtocolVersion = 70002
maxProtocolVersion = 70011
// outputBufferSize is the number of elements the output channels use.
outputBufferSize = 50
@ -335,8 +335,8 @@ func (p *peer) pushVersionMsg() error {
// by the remote peer in its version message
msg.AddrYou.Services = wire.SFNodeNetwork
// Advertise that we're a full node.
msg.Services = wire.SFNodeNetwork
// Advertise our supported services.
msg.Services = p.server.services
// Advertise our max supported protocol version.
msg.ProtocolVersion = maxProtocolVersion
@ -1088,11 +1088,33 @@ func (p *peer) handleGetHeadersMsg(msg *wire.MsgGetHeaders) {
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
// 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
// message is received.
func (p *peer) handleFilterAddMsg(msg *wire.MsgFilterAdd) {
if !p.isValidBIP0111(msg.Command()) {
return
}
if !p.filter.IsLoaded() {
peerLog.Debugf("%s sent a filteradd request with no filter "+
"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
// received.
func (p *peer) handleFilterClearMsg(msg *wire.MsgFilterClear) {
if !p.isValidBIP0111(msg.Command()) {
return
}
if !p.filter.IsLoaded() {
peerLog.Debugf("%s sent a filterclear request with no "+
"filter loaded -- disconnecting", p)
p.Disconnect()
return
}
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
// merkle blocks and associated transactions that match the filter.
func (p *peer) handleFilterLoadMsg(msg *wire.MsgFilterLoad) {
if !p.isValidBIP0111(msg.Command()) {
return
}
// Transaction relay is no longer disabled once a filterload message is
// received regardless of its original state.
p.relayMtx.Lock()

View file

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

View file

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

View file

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

View file

@ -18,7 +18,7 @@ import (
const MaxUserAgentLen = 2000
// 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
// message. It is used for a peer to advertise itself as soon as an outbound

View file

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

View file

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