diff --git a/config.go b/config.go index f5d892a7..e004e428 100644 --- a/config.go +++ b/config.go @@ -27,6 +27,7 @@ import ( "github.com/btcsuite/btcd/database" _ "github.com/btcsuite/btcd/database/ffldb" "github.com/btcsuite/btcd/mempool" + "github.com/btcsuite/btcd/peer" "github.com/btcsuite/btcutil" "github.com/btcsuite/go-socks/socks" flags "github.com/jessevdk/go-flags" @@ -47,7 +48,7 @@ const ( defaultMaxRPCConcurrentReqs = 20 defaultDbType = "ffldb" defaultFreeTxRelayLimit = 15.0 - defaultTrickleTimeout = time.Second * 10 + defaultTrickleInterval = peer.DefaultTrickleInterval defaultBlockMinSize = 0 defaultBlockMaxSize = 750000 defaultBlockMinWeight = 0 @@ -141,7 +142,7 @@ type config struct { MinRelayTxFee float64 `long:"minrelaytxfee" description:"The minimum transaction fee in BTC/kB to be considered a non-zero fee."` FreeTxRelayLimit float64 `long:"limitfreerelay" description:"Limit relay of transactions with no transaction fee to the given amount in thousands of bytes per minute"` NoRelayPriority bool `long:"norelaypriority" description:"Do not require free or low-fee transactions to have high priority for relaying"` - TrickleTimeout time.Duration `long:"trickletimeout" description:"Minimum time between attempts to send new inventory to a connected peer"` + TrickleInterval time.Duration `long:"trickleinterval" description:"Minimum time between attempts to send new inventory to a connected peer"` MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"` Generate bool `long:"generate" description:"Generate (mine) bitcoins using the CPU"` MiningAddrs []string `long:"miningaddr" description:"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"` @@ -417,7 +418,7 @@ func loadConfig() (*config, []string, error) { RPCCert: defaultRPCCertFile, MinRelayTxFee: mempool.DefaultMinRelayTxFee.ToBTC(), FreeTxRelayLimit: defaultFreeTxRelayLimit, - TrickleTimeout: defaultTrickleTimeout, + TrickleInterval: defaultTrickleInterval, BlockMinSize: defaultBlockMinSize, BlockMaxSize: defaultBlockMaxSize, BlockMinWeight: defaultBlockMinWeight, diff --git a/glide.lock b/glide.lock index 67185c22..7d4dca90 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: e6f57b384b22282a2cb4e96aea9c46dc455b44336da09e64a9b19d13d877e7a4 -updated: 2018-08-22T19:51:39.57143044-07:00 +hash: 4d4efdd452d746ef15b66d35caadb3cbd58bb299e9c1f5172e90b2f3f272863f +updated: 2018-08-23T22:38:49.421147894-07:00 imports: - name: github.com/aead/siphash version: 83563a290f60225eb120d724600b9690c3fb536f diff --git a/peer/example_test.go b/peer/example_test.go index 5c4b570d..a549fe21 100644 --- a/peer/example_test.go +++ b/peer/example_test.go @@ -23,7 +23,7 @@ func mockRemotePeer() error { UserAgentName: "peer", // User agent name to advertise. UserAgentVersion: "1.0.0", // User agent version to advertise. ChainParams: &chaincfg.SimNetParams, - TrickleTimeout: time.Second * 10, + TrickleInterval: time.Second * 10, } // Accept connections on the simnet port. @@ -70,7 +70,7 @@ func Example_newOutboundPeer() { UserAgentVersion: "1.0.0", // User agent version to advertise. ChainParams: &chaincfg.SimNetParams, Services: 0, - TrickleTimeout: time.Second * 10, + TrickleInterval: time.Second * 10, Listeners: peer.MessageListeners{ OnVersion: func(p *peer.Peer, msg *wire.MsgVersion) { fmt.Println("outbound: received version") diff --git a/peer/peer.go b/peer/peer.go index 04332aa4..4fa77cf7 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -30,6 +30,10 @@ const ( // MaxProtocolVersion is the max protocol version the peer supports. MaxProtocolVersion = wire.FeeFilterVersion + // DefaultTrickleInterval is the min time between attempts to send an + // inv message to a peer. + DefaultTrickleInterval = 10 * time.Second + // minAcceptableProtocolVersion is the lowest protocol version that a // connected peer may support. minAcceptableProtocolVersion = wire.MultipleAddressVersion @@ -266,9 +270,9 @@ type Config struct { // messages. Listeners MessageListeners - // TrickleTimeout is the duration of the ticker which trickles down the + // TrickleInterval is the duration of the ticker which trickles down the // inventory to a peer. - TrickleTimeout time.Duration + TrickleInterval time.Duration } // minUint32 is a helper function to return the minimum of two uint32s. @@ -1549,7 +1553,7 @@ out: func (p *Peer) queueHandler() { pendingMsgs := list.New() invSendQueue := list.New() - trickleTicker := time.NewTicker(p.cfg.TrickleTimeout) + trickleTicker := time.NewTicker(p.cfg.TrickleInterval) defer trickleTicker.Stop() // We keep the waiting flag so that we know if we have a message queued @@ -2173,6 +2177,11 @@ func newPeerBase(origCfg *Config, inbound bool) *Peer { cfg.ChainParams = &chaincfg.TestNet3Params } + // Set the trickle interval if a non-positive value is specified. + if cfg.TrickleInterval <= 0 { + cfg.TrickleInterval = DefaultTrickleInterval + } + p := Peer{ inbound: inbound, wireEncoding: wire.BaseEncoding, diff --git a/peer/peer_test.go b/peer/peer_test.go index e87d2f95..daf87ab8 100644 --- a/peer/peer_test.go +++ b/peer/peer_test.go @@ -236,7 +236,7 @@ func TestPeerConnection(t *testing.T) { ChainParams: &chaincfg.MainNetParams, ProtocolVersion: wire.RejectVersion, // Configure with older version Services: 0, - TrickleTimeout: time.Second * 10, + TrickleInterval: time.Second * 10, } peer2Cfg := &peer.Config{ Listeners: peer1Cfg.Listeners, @@ -245,7 +245,7 @@ func TestPeerConnection(t *testing.T) { UserAgentComments: []string{"comment"}, ChainParams: &chaincfg.MainNetParams, Services: wire.SFNodeNetwork | wire.SFNodeWitness, - TrickleTimeout: time.Second * 10, + TrickleInterval: time.Second * 10, } wantStats1 := peerStats{ @@ -449,7 +449,7 @@ func TestPeerListeners(t *testing.T) { UserAgentComments: []string{"comment"}, ChainParams: &chaincfg.MainNetParams, Services: wire.SFNodeBloom, - TrickleTimeout: time.Second * 10, + TrickleInterval: time.Second * 10, } inConn, outConn := pipe( &conn{raddr: "10.0.0.1:8333"}, @@ -620,7 +620,7 @@ func TestOutboundPeer(t *testing.T) { UserAgentComments: []string{"comment"}, ChainParams: &chaincfg.MainNetParams, Services: 0, - TrickleTimeout: time.Second * 10, + TrickleInterval: time.Second * 10, } r, w := io.Pipe() @@ -761,7 +761,7 @@ func TestUnsupportedVersionPeer(t *testing.T) { UserAgentComments: []string{"comment"}, ChainParams: &chaincfg.MainNetParams, Services: 0, - TrickleTimeout: time.Second * 10, + TrickleInterval: time.Second * 10, } localNA := wire.NewNetAddressIPPort( diff --git a/server.go b/server.go index a581a081..46a86861 100644 --- a/server.go +++ b/server.go @@ -1943,7 +1943,7 @@ func newPeerConfig(sp *serverPeer) *peer.Config { Services: sp.server.services, DisableRelayTx: cfg.BlocksOnly, ProtocolVersion: peer.MaxProtocolVersion, - TrickleTimeout: cfg.TrickleTimeout, + TrickleInterval: cfg.TrickleInterval, } } diff --git a/wire/msgcfcheckpt.go b/wire/msgcfcheckpt.go index 32f9575e..fc3fd532 100644 --- a/wire/msgcfcheckpt.go +++ b/wire/msgcfcheckpt.go @@ -5,6 +5,7 @@ package wire import ( + "errors" "fmt" "io" @@ -15,8 +16,17 @@ const ( // CFCheckptInterval is the gap (in number of blocks) between each // filter header checkpoint. CFCheckptInterval = 1000 + + // maxCFHeadersLen is the max number of filter headers we will attempt + // to decode. + maxCFHeadersLen = 100000 ) +// ErrInsaneCFHeaderCount signals that we were asked to decode an +// unreasonable number of cfilter headers. +var ErrInsaneCFHeaderCount = errors.New( + "refusing to decode unreasonable number of filter headers") + // MsgCFCheckpt implements the Message interface and represents a bitcoin // cfcheckpt message. It is used to deliver committed filter header information // in response to a getcfcheckpt message (MsgGetCFCheckpt). See MsgGetCFCheckpt @@ -60,6 +70,11 @@ func (msg *MsgCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) return err } + // Refuse to decode an insane number of cfheaders. + if count > maxCFHeadersLen { + return ErrInsaneCFHeaderCount + } + // Create a contiguous slice of hashes to deserialize into in order to // reduce the number of allocations. msg.FilterHeaders = make([]*chainhash.Hash, count)