diff --git a/config.go b/config.go index b104856e..39dc2d1f 100644 --- a/config.go +++ b/config.go @@ -141,6 +141,7 @@ type config struct { BlockMinSize uint32 `long:"blockminsize" description:"Mininum block size in bytes to be used when creating a block"` BlockMaxSize uint32 `long:"blockmaxsize" description:"Maximum block size in bytes to be used when creating a block"` BlockPrioritySize uint32 `long:"blockprioritysize" description:"Size in bytes for high-priority/low-fee transactions when creating a block"` + UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."` NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"` SigCacheMaxSize uint `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"` BlocksOnly bool `long:"blocksonly" description:"Do not accept transactions from remote peers."` @@ -736,6 +737,18 @@ func loadConfig() (*config, []string, error) { cfg.BlockPrioritySize = minUint32(cfg.BlockPrioritySize, cfg.BlockMaxSize) cfg.BlockMinSize = minUint32(cfg.BlockMinSize, cfg.BlockMaxSize) + // Look for illegal characters in the user agent comments. + for _, uaComment := range cfg.UserAgentComments { + if strings.ContainsAny(uaComment, "/:()") { + err := fmt.Errorf("%s: The following characters must not "+ + "appear in user agent comments: '/', ':', '(', ')'", + funcName) + fmt.Fprintln(os.Stderr, err) + fmt.Fprintln(os.Stderr, usageMessage) + return nil, nil, err + } + } + // --txindex and --droptxindex do not mix. if cfg.TxIndex && cfg.DropTxIndex { err := fmt.Errorf("%s: the --txindex and --droptxindex "+ diff --git a/doc.go b/doc.go index 29e7a0b4..90da387a 100644 --- a/doc.go +++ b/doc.go @@ -77,6 +77,8 @@ Application Options: --addcheckpoint= Add a custom checkpoint. Format: ':' --nocheckpoints Disable built-in checkpoints. Don't do this unless you know what you're doing. + --uacomment= Comment to add to the user agent -- + See BIP 14 for more information. --dbtype= Database backend to use for the Block Chain (ffldb) --profile= Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536 diff --git a/peer/peer.go b/peer/peer.go index 1e272a2c..07bebfaa 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -214,6 +214,11 @@ type Config struct { // form "major.minor.revision" e.g. "2.6.41". UserAgentVersion string + // UserAgentComments specify the user agent comments to advertise. These + // values must not contain the illegal characters specified in BIP 14: + // '/', ':', '(', ')'. + UserAgentComments []string + // ChainParams identifies which chain parameters the peer is associated // with. It is highly recommended to specify this field, however it can // be omitted in which case the test network will be used. @@ -799,7 +804,8 @@ func (p *Peer) localVersionMsg() (*wire.MsgVersion, error) { // Version message. msg := wire.NewMsgVersion(ourNA, theirNA, nonce, blockNum) - msg.AddUserAgent(p.cfg.UserAgentName, p.cfg.UserAgentVersion) + msg.AddUserAgent(p.cfg.UserAgentName, p.cfg.UserAgentVersion, + p.cfg.UserAgentComments...) // XXX: bitcoind appears to always enable the full node services flag // of the remote peer netaddress field in the version message regardless diff --git a/peer/peer_test.go b/peer/peer_test.go index 71fa71e4..2db94404 100644 --- a/peer/peer_test.go +++ b/peer/peer_test.go @@ -218,13 +218,14 @@ func TestPeerConnection(t *testing.T) { } }, }, - UserAgentName: "peer", - UserAgentVersion: "1.0", - ChainParams: &chaincfg.MainNetParams, - Services: 0, + UserAgentName: "peer", + UserAgentVersion: "1.0", + UserAgentComments: []string{"comment"}, + ChainParams: &chaincfg.MainNetParams, + Services: 0, } wantStats := peerStats{ - wantUserAgent: wire.DefaultUserAgent + "peer:1.0/", + wantUserAgent: wire.DefaultUserAgent + "peer:1.0(comment)/", wantServices: 0, wantProtocolVersion: peer.MaxProtocolVersion, wantConnected: true, @@ -234,8 +235,8 @@ func TestPeerConnection(t *testing.T) { wantLastPingNonce: uint64(0), wantLastPingMicros: int64(0), wantTimeOffset: int64(0), - wantBytesSent: 158, // 134 version + 24 verack - wantBytesReceived: 158, + wantBytesSent: 167, // 143 version + 24 verack + wantBytesReceived: 167, } tests := []struct { name string @@ -387,10 +388,11 @@ func TestPeerListeners(t *testing.T) { ok <- msg }, }, - UserAgentName: "peer", - UserAgentVersion: "1.0", - ChainParams: &chaincfg.MainNetParams, - Services: wire.SFNodeBloom, + UserAgentName: "peer", + UserAgentVersion: "1.0", + UserAgentComments: []string{"comment"}, + ChainParams: &chaincfg.MainNetParams, + Services: wire.SFNodeBloom, } inConn, outConn := pipe( &conn{raddr: "10.0.0.1:8333"}, @@ -535,10 +537,11 @@ func TestOutboundPeer(t *testing.T) { NewestBlock: func() (*chainhash.Hash, int32, error) { return nil, 0, errors.New("newest block not found") }, - UserAgentName: "peer", - UserAgentVersion: "1.0", - ChainParams: &chaincfg.MainNetParams, - Services: 0, + UserAgentName: "peer", + UserAgentVersion: "1.0", + UserAgentComments: []string{"comment"}, + ChainParams: &chaincfg.MainNetParams, + Services: 0, } r, w := io.Pipe() diff --git a/sample-btcd.conf b/sample-btcd.conf index 8345d799..3ac9aab4 100644 --- a/sample-btcd.conf +++ b/sample-btcd.conf @@ -156,6 +156,9 @@ ; Add additional checkpoints. Format: ':' ; addcheckpoint=: +; Add comments to the user agent that is advertised to peers. +; Must not include characters '/', ':', '(' and ')'. +; uacomment= ; ------------------------------------------------------------------------------ ; RPC server options - The following options control the built-in RPC server diff --git a/server.go b/server.go index 820cedfc..b7cc43e5 100644 --- a/server.go +++ b/server.go @@ -1617,15 +1617,16 @@ func newPeerConfig(sp *serverPeer) *peer.Config { // other implementations' alert messages, we will not relay theirs. OnAlert: nil, }, - NewestBlock: sp.newestBlock, - HostToNetAddress: sp.server.addrManager.HostToNetAddress, - Proxy: cfg.Proxy, - UserAgentName: userAgentName, - UserAgentVersion: userAgentVersion, - ChainParams: sp.server.chainParams, - Services: sp.server.services, - DisableRelayTx: cfg.BlocksOnly, - ProtocolVersion: wire.FeeFilterVersion, + NewestBlock: sp.newestBlock, + HostToNetAddress: sp.server.addrManager.HostToNetAddress, + Proxy: cfg.Proxy, + UserAgentName: userAgentName, + UserAgentVersion: userAgentVersion, + UserAgentComments: cfg.UserAgentComments, + ChainParams: sp.server.chainParams, + Services: sp.server.services, + DisableRelayTx: cfg.BlocksOnly, + ProtocolVersion: wire.FeeFilterVersion, } }