forked from cerc-io/ipld-eth-server
Update dependencies
- uses newer version of go-ethereum required for go1.11
This commit is contained in:
+2
@@ -23,6 +23,7 @@ func mockRemotePeer() error {
|
||||
UserAgentName: "peer", // User agent name to advertise.
|
||||
UserAgentVersion: "1.0.0", // User agent version to advertise.
|
||||
ChainParams: &chaincfg.SimNetParams,
|
||||
TrickleInterval: time.Second * 10,
|
||||
}
|
||||
|
||||
// Accept connections on the simnet port.
|
||||
@@ -69,6 +70,7 @@ func Example_newOutboundPeer() {
|
||||
UserAgentVersion: "1.0.0", // User agent version to advertise.
|
||||
ChainParams: &chaincfg.SimNetParams,
|
||||
Services: 0,
|
||||
TrickleInterval: time.Second * 10,
|
||||
Listeners: peer.MessageListeners{
|
||||
OnVersion: func(p *peer.Peer, msg *wire.MsgVersion) {
|
||||
fmt.Println("outbound: received version")
|
||||
|
||||
+295
-225
@@ -1,4 +1,5 @@
|
||||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2013-2018 The btcsuite developers
|
||||
// Copyright (c) 2016-2018 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
@@ -29,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
|
||||
@@ -64,10 +69,6 @@ const (
|
||||
// stalling. The deadlines are adjusted for callback running times and
|
||||
// only checked on each stall tick interval.
|
||||
stallResponseTimeout = 30 * time.Second
|
||||
|
||||
// trickleTimeout is the duration of the ticker which trickles down the
|
||||
// inventory to a peer.
|
||||
trickleTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -123,6 +124,17 @@ type MessageListeners struct {
|
||||
// OnBlock is invoked when a peer receives a block bitcoin message.
|
||||
OnBlock func(p *Peer, msg *wire.MsgBlock, buf []byte)
|
||||
|
||||
// OnCFilter is invoked when a peer receives a cfilter bitcoin message.
|
||||
OnCFilter func(p *Peer, msg *wire.MsgCFilter)
|
||||
|
||||
// OnCFHeaders is invoked when a peer receives a cfheaders bitcoin
|
||||
// message.
|
||||
OnCFHeaders func(p *Peer, msg *wire.MsgCFHeaders)
|
||||
|
||||
// OnCFCheckpt is invoked when a peer receives a cfcheckpt bitcoin
|
||||
// message.
|
||||
OnCFCheckpt func(p *Peer, msg *wire.MsgCFCheckpt)
|
||||
|
||||
// OnInv is invoked when a peer receives an inv bitcoin message.
|
||||
OnInv func(p *Peer, msg *wire.MsgInv)
|
||||
|
||||
@@ -144,6 +156,18 @@ type MessageListeners struct {
|
||||
// message.
|
||||
OnGetHeaders func(p *Peer, msg *wire.MsgGetHeaders)
|
||||
|
||||
// OnGetCFilters is invoked when a peer receives a getcfilters bitcoin
|
||||
// message.
|
||||
OnGetCFilters func(p *Peer, msg *wire.MsgGetCFilters)
|
||||
|
||||
// OnGetCFHeaders is invoked when a peer receives a getcfheaders
|
||||
// bitcoin message.
|
||||
OnGetCFHeaders func(p *Peer, msg *wire.MsgGetCFHeaders)
|
||||
|
||||
// OnGetCFCheckpt is invoked when a peer receives a getcfcheckpt
|
||||
// bitcoin message.
|
||||
OnGetCFCheckpt func(p *Peer, msg *wire.MsgGetCFCheckpt)
|
||||
|
||||
// OnFeeFilter is invoked when a peer receives a feefilter bitcoin message.
|
||||
OnFeeFilter func(p *Peer, msg *wire.MsgFeeFilter)
|
||||
|
||||
@@ -245,6 +269,10 @@ type Config struct {
|
||||
// Listeners houses callback functions to be invoked on receiving peer
|
||||
// messages.
|
||||
Listeners MessageListeners
|
||||
|
||||
// TrickleInterval is the duration of the ticker which trickles down the
|
||||
// inventory to a peer.
|
||||
TrickleInterval time.Duration
|
||||
}
|
||||
|
||||
// minUint32 is a helper function to return the minimum of two uint32s.
|
||||
@@ -778,85 +806,6 @@ func (p *Peer) IsWitnessEnabled() bool {
|
||||
return witnessEnabled
|
||||
}
|
||||
|
||||
// localVersionMsg creates a version message that can be used to send to the
|
||||
// remote peer.
|
||||
func (p *Peer) localVersionMsg() (*wire.MsgVersion, error) {
|
||||
var blockNum int32
|
||||
if p.cfg.NewestBlock != nil {
|
||||
var err error
|
||||
_, blockNum, err = p.cfg.NewestBlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
theirNA := p.na
|
||||
|
||||
// If we are behind a proxy and the connection comes from the proxy then
|
||||
// we return an unroutable address as their address. This is to prevent
|
||||
// leaking the tor proxy address.
|
||||
if p.cfg.Proxy != "" {
|
||||
proxyaddress, _, err := net.SplitHostPort(p.cfg.Proxy)
|
||||
// invalid proxy means poorly configured, be on the safe side.
|
||||
if err != nil || p.na.IP.String() == proxyaddress {
|
||||
theirNA = wire.NewNetAddressIPPort(net.IP([]byte{0, 0, 0, 0}), 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a wire.NetAddress with only the services set to use as the
|
||||
// "addrme" in the version message.
|
||||
//
|
||||
// Older nodes previously added the IP and port information to the
|
||||
// address manager which proved to be unreliable as an inbound
|
||||
// connection from a peer didn't necessarily mean the peer itself
|
||||
// accepted inbound connections.
|
||||
//
|
||||
// Also, the timestamp is unused in the version message.
|
||||
ourNA := &wire.NetAddress{
|
||||
Services: p.cfg.Services,
|
||||
}
|
||||
|
||||
// Generate a unique nonce for this peer so self connections can be
|
||||
// detected. This is accomplished by adding it to a size-limited map of
|
||||
// recently seen nonces.
|
||||
nonce := uint64(rand.Int63())
|
||||
sentNonces.Add(nonce)
|
||||
|
||||
// Version message.
|
||||
msg := wire.NewMsgVersion(ourNA, theirNA, nonce, blockNum)
|
||||
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
|
||||
// of whether it knows it supports it or not. Also, bitcoind sets
|
||||
// the services field of the local peer to 0 regardless of support.
|
||||
//
|
||||
// Realistically, this should be set as follows:
|
||||
// - For outgoing connections:
|
||||
// - Set the local netaddress services to what the local peer
|
||||
// actually supports
|
||||
// - Set the remote netaddress services to 0 to indicate no services
|
||||
// as they are still unknown
|
||||
// - For incoming connections:
|
||||
// - Set the local netaddress services to what the local peer
|
||||
// actually supports
|
||||
// - Set the remote netaddress services to the what was advertised by
|
||||
// by the remote peer in its version message
|
||||
msg.AddrYou.Services = wire.SFNodeNetwork
|
||||
|
||||
// Advertise the services flag
|
||||
msg.Services = p.cfg.Services
|
||||
|
||||
// Advertise our max supported protocol version.
|
||||
msg.ProtocolVersion = int32(p.cfg.ProtocolVersion)
|
||||
|
||||
// Advertise if inv messages for transactions are desired.
|
||||
msg.DisableRelayTx = p.cfg.DisableRelayTx
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// PushAddrMsg sends an addr message to the connected peer using the provided
|
||||
// addresses. This function is useful over manually sending the message via
|
||||
// QueueMessage since it automatically limits the addresses to the maximum
|
||||
@@ -1018,72 +967,6 @@ func (p *Peer) PushRejectMsg(command string, code wire.RejectCode, reason string
|
||||
<-doneChan
|
||||
}
|
||||
|
||||
// handleRemoteVersionMsg is invoked when a version bitcoin message is received
|
||||
// from the remote peer. It will return an error if the remote peer's version
|
||||
// is not compatible with ours.
|
||||
func (p *Peer) handleRemoteVersionMsg(msg *wire.MsgVersion) error {
|
||||
// Detect self connections.
|
||||
if !allowSelfConns && sentNonces.Exists(msg.Nonce) {
|
||||
return errors.New("disconnecting peer connected to self")
|
||||
}
|
||||
|
||||
// Notify and disconnect clients that have a protocol version that is
|
||||
// too old.
|
||||
//
|
||||
// NOTE: If minAcceptableProtocolVersion is raised to be higher than
|
||||
// wire.RejectVersion, this should send a reject packet before
|
||||
// disconnecting.
|
||||
if uint32(msg.ProtocolVersion) < minAcceptableProtocolVersion {
|
||||
reason := fmt.Sprintf("protocol version must be %d or greater",
|
||||
minAcceptableProtocolVersion)
|
||||
return errors.New(reason)
|
||||
}
|
||||
|
||||
// Updating a bunch of stats including block based stats, and the
|
||||
// peer's time offset.
|
||||
p.statsMtx.Lock()
|
||||
p.lastBlock = msg.LastBlock
|
||||
p.startingHeight = msg.LastBlock
|
||||
p.timeOffset = msg.Timestamp.Unix() - time.Now().Unix()
|
||||
p.statsMtx.Unlock()
|
||||
|
||||
// Negotiate the protocol version.
|
||||
p.flagsMtx.Lock()
|
||||
p.advertisedProtoVer = uint32(msg.ProtocolVersion)
|
||||
p.protocolVersion = minUint32(p.protocolVersion, p.advertisedProtoVer)
|
||||
p.versionKnown = true
|
||||
log.Debugf("Negotiated protocol version %d for peer %s",
|
||||
p.protocolVersion, p)
|
||||
|
||||
// Set the peer's ID.
|
||||
p.id = atomic.AddInt32(&nodeCount, 1)
|
||||
|
||||
// Set the supported services for the peer to what the remote peer
|
||||
// advertised.
|
||||
p.services = msg.Services
|
||||
|
||||
// Set the remote peer's user agent.
|
||||
p.userAgent = msg.UserAgent
|
||||
|
||||
// Determine if the peer would like to receive witness data with
|
||||
// transactions, or not.
|
||||
if p.services&wire.SFNodeWitness == wire.SFNodeWitness {
|
||||
p.witnessEnabled = true
|
||||
}
|
||||
p.flagsMtx.Unlock()
|
||||
|
||||
// Once the version message has been exchanged, we're able to determine
|
||||
// if this peer knows how to encode witness data over the wire
|
||||
// protocol. If so, then we'll switch to a decoding mode which is
|
||||
// prepared for the new transaction format introduced as part of
|
||||
// BIP0144.
|
||||
if p.services&wire.SFNodeWitness == wire.SFNodeWitness {
|
||||
p.wireEncoding = wire.WitnessEncoding
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// handlePingMsg is invoked when a peer receives a ping bitcoin message. For
|
||||
// recent clients (protocol version > BIP0031Version), it replies with a pong
|
||||
// message. For older clients, it does nothing and anything other than failure
|
||||
@@ -1579,6 +1462,31 @@ out:
|
||||
p.cfg.Listeners.OnGetHeaders(p, msg)
|
||||
}
|
||||
|
||||
case *wire.MsgGetCFilters:
|
||||
if p.cfg.Listeners.OnGetCFilters != nil {
|
||||
p.cfg.Listeners.OnGetCFilters(p, msg)
|
||||
}
|
||||
|
||||
case *wire.MsgGetCFHeaders:
|
||||
if p.cfg.Listeners.OnGetCFHeaders != nil {
|
||||
p.cfg.Listeners.OnGetCFHeaders(p, msg)
|
||||
}
|
||||
|
||||
case *wire.MsgGetCFCheckpt:
|
||||
if p.cfg.Listeners.OnGetCFCheckpt != nil {
|
||||
p.cfg.Listeners.OnGetCFCheckpt(p, msg)
|
||||
}
|
||||
|
||||
case *wire.MsgCFilter:
|
||||
if p.cfg.Listeners.OnCFilter != nil {
|
||||
p.cfg.Listeners.OnCFilter(p, msg)
|
||||
}
|
||||
|
||||
case *wire.MsgCFHeaders:
|
||||
if p.cfg.Listeners.OnCFHeaders != nil {
|
||||
p.cfg.Listeners.OnCFHeaders(p, msg)
|
||||
}
|
||||
|
||||
case *wire.MsgFeeFilter:
|
||||
if p.cfg.Listeners.OnFeeFilter != nil {
|
||||
p.cfg.Listeners.OnFeeFilter(p, msg)
|
||||
@@ -1645,7 +1553,7 @@ out:
|
||||
func (p *Peer) queueHandler() {
|
||||
pendingMsgs := list.New()
|
||||
invSendQueue := list.New()
|
||||
trickleTicker := time.NewTicker(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
|
||||
@@ -1692,7 +1600,19 @@ out:
|
||||
case iv := <-p.outputInvChan:
|
||||
// No handshake? They'll find out soon enough.
|
||||
if p.VersionKnown() {
|
||||
invSendQueue.PushBack(iv)
|
||||
// If this is a new block, then we'll blast it
|
||||
// out immediately, sipping the inv trickle
|
||||
// queue.
|
||||
if iv.Type == wire.InvTypeBlock ||
|
||||
iv.Type == wire.InvTypeWitnessBlock {
|
||||
|
||||
invMsg := wire.NewMsgInvSizeHint(1)
|
||||
invMsg.AddInvVect(iv)
|
||||
waiting = queuePacket(outMsg{msg: invMsg},
|
||||
pendingMsgs, waiting)
|
||||
} else {
|
||||
invSendQueue.PushBack(iv)
|
||||
}
|
||||
}
|
||||
|
||||
case <-trickleTicker.C:
|
||||
@@ -1932,40 +1852,6 @@ func (p *Peer) QueueInventory(invVect *wire.InvVect) {
|
||||
p.outputInvChan <- invVect
|
||||
}
|
||||
|
||||
// AssociateConnection associates the given conn to the peer. Calling this
|
||||
// function when the peer is already connected will have no effect.
|
||||
func (p *Peer) AssociateConnection(conn net.Conn) {
|
||||
// Already connected?
|
||||
if !atomic.CompareAndSwapInt32(&p.connected, 0, 1) {
|
||||
return
|
||||
}
|
||||
|
||||
p.conn = conn
|
||||
p.timeConnected = time.Now()
|
||||
|
||||
if p.inbound {
|
||||
p.addr = p.conn.RemoteAddr().String()
|
||||
|
||||
// Set up a NetAddress for the peer to be used with AddrManager. We
|
||||
// only do this inbound because outbound set this up at connection time
|
||||
// and no point recomputing.
|
||||
na, err := newNetAddress(p.conn.RemoteAddr(), p.services)
|
||||
if err != nil {
|
||||
log.Errorf("Cannot create remote net address: %v", err)
|
||||
p.Disconnect()
|
||||
return
|
||||
}
|
||||
p.na = na
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := p.start(); err != nil {
|
||||
log.Debugf("Cannot start peer %v: %v", p, err)
|
||||
p.Disconnect()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Connected returns whether or not the peer is currently connected.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
@@ -1989,51 +1875,72 @@ func (p *Peer) Disconnect() {
|
||||
close(p.quit)
|
||||
}
|
||||
|
||||
// start begins processing input and output messages.
|
||||
func (p *Peer) start() error {
|
||||
log.Tracef("Starting peer %s", p)
|
||||
|
||||
negotiateErr := make(chan error)
|
||||
go func() {
|
||||
if p.inbound {
|
||||
negotiateErr <- p.negotiateInboundProtocol()
|
||||
} else {
|
||||
negotiateErr <- p.negotiateOutboundProtocol()
|
||||
}
|
||||
}()
|
||||
|
||||
// Negotiate the protocol within the specified negotiateTimeout.
|
||||
select {
|
||||
case err := <-negotiateErr:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case <-time.After(negotiateTimeout):
|
||||
return errors.New("protocol negotiation timeout")
|
||||
// handleRemoteVersionMsg is invoked when a version bitcoin message is received
|
||||
// from the remote peer. It will return an error if the remote peer's version
|
||||
// is not compatible with ours.
|
||||
func (p *Peer) handleRemoteVersionMsg(msg *wire.MsgVersion) error {
|
||||
// Detect self connections.
|
||||
if !allowSelfConns && sentNonces.Exists(msg.Nonce) {
|
||||
return errors.New("disconnecting peer connected to self")
|
||||
}
|
||||
log.Debugf("Connected to %s", p.Addr())
|
||||
|
||||
// The protocol has been negotiated successfully so start processing input
|
||||
// and output messages.
|
||||
go p.stallHandler()
|
||||
go p.inHandler()
|
||||
go p.queueHandler()
|
||||
go p.outHandler()
|
||||
go p.pingHandler()
|
||||
// Notify and disconnect clients that have a protocol version that is
|
||||
// too old.
|
||||
//
|
||||
// NOTE: If minAcceptableProtocolVersion is raised to be higher than
|
||||
// wire.RejectVersion, this should send a reject packet before
|
||||
// disconnecting.
|
||||
if uint32(msg.ProtocolVersion) < minAcceptableProtocolVersion {
|
||||
reason := fmt.Sprintf("protocol version must be %d or greater",
|
||||
minAcceptableProtocolVersion)
|
||||
return errors.New(reason)
|
||||
}
|
||||
|
||||
// Updating a bunch of stats including block based stats, and the
|
||||
// peer's time offset.
|
||||
p.statsMtx.Lock()
|
||||
p.lastBlock = msg.LastBlock
|
||||
p.startingHeight = msg.LastBlock
|
||||
p.timeOffset = msg.Timestamp.Unix() - time.Now().Unix()
|
||||
p.statsMtx.Unlock()
|
||||
|
||||
// Negotiate the protocol version.
|
||||
p.flagsMtx.Lock()
|
||||
p.advertisedProtoVer = uint32(msg.ProtocolVersion)
|
||||
p.protocolVersion = minUint32(p.protocolVersion, p.advertisedProtoVer)
|
||||
p.versionKnown = true
|
||||
log.Debugf("Negotiated protocol version %d for peer %s",
|
||||
p.protocolVersion, p)
|
||||
|
||||
// Set the peer's ID.
|
||||
p.id = atomic.AddInt32(&nodeCount, 1)
|
||||
|
||||
// Set the supported services for the peer to what the remote peer
|
||||
// advertised.
|
||||
p.services = msg.Services
|
||||
|
||||
// Set the remote peer's user agent.
|
||||
p.userAgent = msg.UserAgent
|
||||
|
||||
// Determine if the peer would like to receive witness data with
|
||||
// transactions, or not.
|
||||
if p.services&wire.SFNodeWitness == wire.SFNodeWitness {
|
||||
p.witnessEnabled = true
|
||||
}
|
||||
p.flagsMtx.Unlock()
|
||||
|
||||
// Once the version message has been exchanged, we're able to determine
|
||||
// if this peer knows how to encode witness data over the wire
|
||||
// protocol. If so, then we'll switch to a decoding mode which is
|
||||
// prepared for the new transaction format introduced as part of
|
||||
// BIP0144.
|
||||
if p.services&wire.SFNodeWitness == wire.SFNodeWitness {
|
||||
p.wireEncoding = wire.WitnessEncoding
|
||||
}
|
||||
|
||||
// Send our verack message now that the IO processing machinery has started.
|
||||
p.QueueMessage(wire.NewMsgVerAck(), nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WaitForDisconnect waits until the peer has completely disconnected and all
|
||||
// resources are cleaned up. This will happen if either the local or remote
|
||||
// side has been disconnected or the peer is forcibly disconnected via
|
||||
// Disconnect.
|
||||
func (p *Peer) WaitForDisconnect() {
|
||||
<-p.quit
|
||||
}
|
||||
|
||||
// readRemoteVersionMsg waits for the next message to arrive from the remote
|
||||
// peer. If the next message is not a version message or the version is not
|
||||
// acceptable then return an error.
|
||||
@@ -2064,6 +1971,85 @@ func (p *Peer) readRemoteVersionMsg() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// localVersionMsg creates a version message that can be used to send to the
|
||||
// remote peer.
|
||||
func (p *Peer) localVersionMsg() (*wire.MsgVersion, error) {
|
||||
var blockNum int32
|
||||
if p.cfg.NewestBlock != nil {
|
||||
var err error
|
||||
_, blockNum, err = p.cfg.NewestBlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
theirNA := p.na
|
||||
|
||||
// If we are behind a proxy and the connection comes from the proxy then
|
||||
// we return an unroutable address as their address. This is to prevent
|
||||
// leaking the tor proxy address.
|
||||
if p.cfg.Proxy != "" {
|
||||
proxyaddress, _, err := net.SplitHostPort(p.cfg.Proxy)
|
||||
// invalid proxy means poorly configured, be on the safe side.
|
||||
if err != nil || p.na.IP.String() == proxyaddress {
|
||||
theirNA = wire.NewNetAddressIPPort(net.IP([]byte{0, 0, 0, 0}), 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a wire.NetAddress with only the services set to use as the
|
||||
// "addrme" in the version message.
|
||||
//
|
||||
// Older nodes previously added the IP and port information to the
|
||||
// address manager which proved to be unreliable as an inbound
|
||||
// connection from a peer didn't necessarily mean the peer itself
|
||||
// accepted inbound connections.
|
||||
//
|
||||
// Also, the timestamp is unused in the version message.
|
||||
ourNA := &wire.NetAddress{
|
||||
Services: p.cfg.Services,
|
||||
}
|
||||
|
||||
// Generate a unique nonce for this peer so self connections can be
|
||||
// detected. This is accomplished by adding it to a size-limited map of
|
||||
// recently seen nonces.
|
||||
nonce := uint64(rand.Int63())
|
||||
sentNonces.Add(nonce)
|
||||
|
||||
// Version message.
|
||||
msg := wire.NewMsgVersion(ourNA, theirNA, nonce, blockNum)
|
||||
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
|
||||
// of whether it knows it supports it or not. Also, bitcoind sets
|
||||
// the services field of the local peer to 0 regardless of support.
|
||||
//
|
||||
// Realistically, this should be set as follows:
|
||||
// - For outgoing connections:
|
||||
// - Set the local netaddress services to what the local peer
|
||||
// actually supports
|
||||
// - Set the remote netaddress services to 0 to indicate no services
|
||||
// as they are still unknown
|
||||
// - For incoming connections:
|
||||
// - Set the local netaddress services to what the local peer
|
||||
// actually supports
|
||||
// - Set the remote netaddress services to the what was advertised by
|
||||
// by the remote peer in its version message
|
||||
msg.AddrYou.Services = wire.SFNodeNetwork
|
||||
|
||||
// Advertise the services flag
|
||||
msg.Services = p.cfg.Services
|
||||
|
||||
// Advertise our max supported protocol version.
|
||||
msg.ProtocolVersion = int32(p.cfg.ProtocolVersion)
|
||||
|
||||
// Advertise if inv messages for transactions are desired.
|
||||
msg.DisableRelayTx = p.cfg.DisableRelayTx
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// writeLocalVersionMsg writes our version message to the remote peer.
|
||||
func (p *Peer) writeLocalVersionMsg() error {
|
||||
localVerMsg, err := p.localVersionMsg()
|
||||
@@ -2096,6 +2082,85 @@ func (p *Peer) negotiateOutboundProtocol() error {
|
||||
return p.readRemoteVersionMsg()
|
||||
}
|
||||
|
||||
// start begins processing input and output messages.
|
||||
func (p *Peer) start() error {
|
||||
log.Tracef("Starting peer %s", p)
|
||||
|
||||
negotiateErr := make(chan error, 1)
|
||||
go func() {
|
||||
if p.inbound {
|
||||
negotiateErr <- p.negotiateInboundProtocol()
|
||||
} else {
|
||||
negotiateErr <- p.negotiateOutboundProtocol()
|
||||
}
|
||||
}()
|
||||
|
||||
// Negotiate the protocol within the specified negotiateTimeout.
|
||||
select {
|
||||
case err := <-negotiateErr:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case <-time.After(negotiateTimeout):
|
||||
return errors.New("protocol negotiation timeout")
|
||||
}
|
||||
log.Debugf("Connected to %s", p.Addr())
|
||||
|
||||
// The protocol has been negotiated successfully so start processing input
|
||||
// and output messages.
|
||||
go p.stallHandler()
|
||||
go p.inHandler()
|
||||
go p.queueHandler()
|
||||
go p.outHandler()
|
||||
go p.pingHandler()
|
||||
|
||||
// Send our verack message now that the IO processing machinery has started.
|
||||
p.QueueMessage(wire.NewMsgVerAck(), nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssociateConnection associates the given conn to the peer. Calling this
|
||||
// function when the peer is already connected will have no effect.
|
||||
func (p *Peer) AssociateConnection(conn net.Conn) {
|
||||
// Already connected?
|
||||
if !atomic.CompareAndSwapInt32(&p.connected, 0, 1) {
|
||||
return
|
||||
}
|
||||
|
||||
p.conn = conn
|
||||
p.timeConnected = time.Now()
|
||||
|
||||
if p.inbound {
|
||||
p.addr = p.conn.RemoteAddr().String()
|
||||
|
||||
// Set up a NetAddress for the peer to be used with AddrManager. We
|
||||
// only do this inbound because outbound set this up at connection time
|
||||
// and no point recomputing.
|
||||
na, err := newNetAddress(p.conn.RemoteAddr(), p.services)
|
||||
if err != nil {
|
||||
log.Errorf("Cannot create remote net address: %v", err)
|
||||
p.Disconnect()
|
||||
return
|
||||
}
|
||||
p.na = na
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := p.start(); err != nil {
|
||||
log.Debugf("Cannot start peer %v: %v", p, err)
|
||||
p.Disconnect()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// WaitForDisconnect waits until the peer has completely disconnected and all
|
||||
// resources are cleaned up. This will happen if either the local or remote
|
||||
// side has been disconnected or the peer is forcibly disconnected via
|
||||
// Disconnect.
|
||||
func (p *Peer) WaitForDisconnect() {
|
||||
<-p.quit
|
||||
}
|
||||
|
||||
// newPeerBase returns a new base bitcoin peer based on the inbound flag. This
|
||||
// is used by the NewInboundPeer and NewOutboundPeer functions to perform base
|
||||
// setup needed by both types of peers.
|
||||
@@ -2112,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,
|
||||
|
||||
+41
@@ -236,6 +236,7 @@ func TestPeerConnection(t *testing.T) {
|
||||
ChainParams: &chaincfg.MainNetParams,
|
||||
ProtocolVersion: wire.RejectVersion, // Configure with older version
|
||||
Services: 0,
|
||||
TrickleInterval: time.Second * 10,
|
||||
}
|
||||
peer2Cfg := &peer.Config{
|
||||
Listeners: peer1Cfg.Listeners,
|
||||
@@ -244,6 +245,7 @@ func TestPeerConnection(t *testing.T) {
|
||||
UserAgentComments: []string{"comment"},
|
||||
ChainParams: &chaincfg.MainNetParams,
|
||||
Services: wire.SFNodeNetwork | wire.SFNodeWitness,
|
||||
TrickleInterval: time.Second * 10,
|
||||
}
|
||||
|
||||
wantStats1 := peerStats{
|
||||
@@ -399,6 +401,21 @@ func TestPeerListeners(t *testing.T) {
|
||||
OnGetHeaders: func(p *peer.Peer, msg *wire.MsgGetHeaders) {
|
||||
ok <- msg
|
||||
},
|
||||
OnGetCFilters: func(p *peer.Peer, msg *wire.MsgGetCFilters) {
|
||||
ok <- msg
|
||||
},
|
||||
OnGetCFHeaders: func(p *peer.Peer, msg *wire.MsgGetCFHeaders) {
|
||||
ok <- msg
|
||||
},
|
||||
OnGetCFCheckpt: func(p *peer.Peer, msg *wire.MsgGetCFCheckpt) {
|
||||
ok <- msg
|
||||
},
|
||||
OnCFilter: func(p *peer.Peer, msg *wire.MsgCFilter) {
|
||||
ok <- msg
|
||||
},
|
||||
OnCFHeaders: func(p *peer.Peer, msg *wire.MsgCFHeaders) {
|
||||
ok <- msg
|
||||
},
|
||||
OnFeeFilter: func(p *peer.Peer, msg *wire.MsgFeeFilter) {
|
||||
ok <- msg
|
||||
},
|
||||
@@ -432,6 +449,7 @@ func TestPeerListeners(t *testing.T) {
|
||||
UserAgentComments: []string{"comment"},
|
||||
ChainParams: &chaincfg.MainNetParams,
|
||||
Services: wire.SFNodeBloom,
|
||||
TrickleInterval: time.Second * 10,
|
||||
}
|
||||
inConn, outConn := pipe(
|
||||
&conn{raddr: "10.0.0.1:8333"},
|
||||
@@ -522,6 +540,27 @@ func TestPeerListeners(t *testing.T) {
|
||||
"OnGetHeaders",
|
||||
wire.NewMsgGetHeaders(),
|
||||
},
|
||||
{
|
||||
"OnGetCFilters",
|
||||
wire.NewMsgGetCFilters(wire.GCSFilterRegular, 0, &chainhash.Hash{}),
|
||||
},
|
||||
{
|
||||
"OnGetCFHeaders",
|
||||
wire.NewMsgGetCFHeaders(wire.GCSFilterRegular, 0, &chainhash.Hash{}),
|
||||
},
|
||||
{
|
||||
"OnGetCFCheckpt",
|
||||
wire.NewMsgGetCFCheckpt(wire.GCSFilterRegular, &chainhash.Hash{}),
|
||||
},
|
||||
{
|
||||
"OnCFilter",
|
||||
wire.NewMsgCFilter(wire.GCSFilterRegular, &chainhash.Hash{},
|
||||
[]byte("payload")),
|
||||
},
|
||||
{
|
||||
"OnCFHeaders",
|
||||
wire.NewMsgCFHeaders(),
|
||||
},
|
||||
{
|
||||
"OnFeeFilter",
|
||||
wire.NewMsgFeeFilter(15000),
|
||||
@@ -581,6 +620,7 @@ func TestOutboundPeer(t *testing.T) {
|
||||
UserAgentComments: []string{"comment"},
|
||||
ChainParams: &chaincfg.MainNetParams,
|
||||
Services: 0,
|
||||
TrickleInterval: time.Second * 10,
|
||||
}
|
||||
|
||||
r, w := io.Pipe()
|
||||
@@ -721,6 +761,7 @@ func TestUnsupportedVersionPeer(t *testing.T) {
|
||||
UserAgentComments: []string{"comment"},
|
||||
ChainParams: &chaincfg.MainNetParams,
|
||||
Services: 0,
|
||||
TrickleInterval: time.Second * 10,
|
||||
}
|
||||
|
||||
localNA := wire.NewNetAddressIPPort(
|
||||
|
||||
Reference in New Issue
Block a user