[DEV-333] Update version message to include sub-network (#163)

* [DEV-333] Added subnetwork to local peer version message.

* [DEV-333] Fixed broken references.

* [DEV-333] Added serialization/deserialization of the version message.

* [DEV-333] Added rejection for peers with wrong subnetwork.

* [DEV-333] Fixed bad comment.

* [DEV-333] Renamed ChainParams to DAGParams.

* [DEV-333] Fixed partial nodes disconnecting from full nodes.

* [DEV-333] chain -> DAG

* [DEV-333] Possibly fixed outbound msgVersion rules.

* [DEV-333] Combined the two incompatible subnetwork cases into one if.

* [DEV-333] Reformatted the condition.
This commit is contained in:
stasatdaglabs 2019-01-15 16:25:56 +02:00 committed by Svarog
parent 3a5abb6584
commit 10ee7df252
9 changed files with 93 additions and 45 deletions

View File

@ -49,9 +49,9 @@ var (
// Config is a descriptor containing the cpu miner configuration.
type Config struct {
// ChainParams identifies which chain parameters the cpu miner is
// DAGParams identifies which DAG parameters the cpu miner is
// associated with.
ChainParams *dagconfig.Params
DAGParams *dagconfig.Params
// BlockTemplateGenerator identifies the instance to use in order to
// generate block templates that the miner will attempt to solve.

View File

@ -22,7 +22,8 @@ func mockRemotePeer() error {
peerCfg := &peer.Config{
UserAgentName: "peer", // User agent name to advertise.
UserAgentVersion: "1.0.0", // User agent version to advertise.
ChainParams: &dagconfig.SimNetParams,
DAGParams: &dagconfig.SimNetParams,
Subnetwork: &wire.SubnetworkSupportsAll,
}
// Accept connections on the simnet port.
@ -67,7 +68,7 @@ func Example_newOutboundPeer() {
peerCfg := &peer.Config{
UserAgentName: "peer", // User agent name to advertise.
UserAgentVersion: "1.0.0", // User agent version to advertise.
ChainParams: &dagconfig.SimNetParams,
DAGParams: &dagconfig.SimNetParams,
Services: 0,
Listeners: peer.MessageListeners{
OnVersion: func(p *peer.Peer, msg *wire.MsgVersion) {
@ -77,6 +78,7 @@ func Example_newOutboundPeer() {
verack <- struct{}{}
},
},
Subnetwork: &wire.SubnetworkSupportsAll,
}
p, err := peer.NewOutboundPeer(peerCfg, "127.0.0.1:18555")
if err != nil {

View File

@ -9,6 +9,7 @@ import (
"container/list"
"errors"
"fmt"
"github.com/daglabs/btcd/util/subnetworkid"
"io"
"math/rand"
"net"
@ -247,10 +248,10 @@ type Config struct {
// '/', ':', '(', ')'.
UserAgentComments []string
// ChainParams identifies which chain parameters the peer is associated
// DAGParams identifies which DAG 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.
ChainParams *dagconfig.Params
DAGParams *dagconfig.Params
// Services specifies which services to advertise as supported by the
// local peer. This field can be omitted in which case it will be 0
@ -269,6 +270,9 @@ type Config struct {
// Listeners houses callback functions to be invoked on receiving peer
// messages.
Listeners MessageListeners
// Subnetwork specifies which subnetwork the peer is associated with.
Subnetwork *subnetworkid.SubnetworkID
}
// minUint32 is a helper function to return the minimum of two uint32s.
@ -819,8 +823,10 @@ func (p *Peer) localVersionMsg() (*wire.MsgVersion, error) {
nonce := uint64(rand.Int63())
sentNonces.Add(nonce)
subnetworkID := p.cfg.Subnetwork
// Version message.
msg := wire.NewMsgVersion(ourNA, theirNA, nonce, blockNum)
msg := wire.NewMsgVersion(ourNA, theirNA, nonce, blockNum, subnetworkID)
msg.AddUserAgent(p.cfg.UserAgentName, p.cfg.UserAgentVersion,
p.cfg.UserAgentComments...)
@ -1036,6 +1042,17 @@ func (p *Peer) handleRemoteVersionMsg(msg *wire.MsgVersion) error {
return errors.New(reason)
}
// Disconnect if:
// - we are a full node and the outbound connection we've initiated is a partial node
// - the remote node is partial and our subnetwork doesn't match their subnetwork
isLocalNodeFull := p.cfg.Subnetwork.IsEqual(&wire.SubnetworkSupportsAll)
isRemoteNodeFull := msg.Subnetwork.IsEqual(&wire.SubnetworkSupportsAll)
if (isLocalNodeFull && !isRemoteNodeFull && !p.inbound) ||
(!isRemoteNodeFull && !msg.Subnetwork.IsEqual(p.cfg.Subnetwork)) {
return errors.New("incompatible subnetworks")
}
// Updating a bunch of stats including block based stats, and the
// peer's time offset.
p.statsMtx.Lock()
@ -1105,7 +1122,7 @@ func (p *Peer) handlePongMsg(msg *wire.MsgPong) {
// readMessage reads the next bitcoin message from the peer with logging.
func (p *Peer) readMessage() (wire.Message, []byte, error) {
n, msg, buf, err := wire.ReadMessageN(p.conn,
p.ProtocolVersion(), p.cfg.ChainParams.Net)
p.ProtocolVersion(), p.cfg.DAGParams.Net)
atomic.AddUint64(&p.bytesReceived, uint64(n))
if p.cfg.Listeners.OnRead != nil {
p.cfg.Listeners.OnRead(p, n, msg, err)
@ -1159,7 +1176,7 @@ func (p *Peer) writeMessage(msg wire.Message) error {
log.Tracef("%v", newLogClosure(func() string {
var buf bytes.Buffer
_, err := wire.WriteMessageN(&buf, msg, p.ProtocolVersion(),
p.cfg.ChainParams.Net)
p.cfg.DAGParams.Net)
if err != nil {
return err.Error()
}
@ -1168,7 +1185,7 @@ func (p *Peer) writeMessage(msg wire.Message) error {
// Write the message to the peer.
n, err := wire.WriteMessageN(p.conn, msg,
p.ProtocolVersion(), p.cfg.ChainParams.Net)
p.ProtocolVersion(), p.cfg.DAGParams.Net)
atomic.AddUint64(&p.bytesSent, uint64(n))
if p.cfg.Listeners.OnWrite != nil {
p.cfg.Listeners.OnWrite(p, n, msg, err)
@ -1181,7 +1198,7 @@ func (p *Peer) writeMessage(msg wire.Message) error {
// to send malformed messages without the peer being disconnected.
func (p *Peer) isAllowedReadError(err error) bool {
// Only allow read errors in regression test mode.
if p.cfg.ChainParams.Net != wire.TestNet {
if p.cfg.DAGParams.Net != wire.TestNet {
return false
}
@ -2113,9 +2130,9 @@ func newPeerBase(origCfg *Config, inbound bool) *Peer {
cfg.ProtocolVersion = MaxProtocolVersion
}
// Set the chain parameters to testnet if the caller did not specify any.
if cfg.ChainParams == nil {
cfg.ChainParams = &dagconfig.TestNet3Params
// Set the DAG parameters to testnet if the caller did not specify any.
if cfg.DAGParams == nil {
cfg.DAGParams = &dagconfig.TestNet3Params
}
p := Peer{

View File

@ -226,17 +226,19 @@ func TestPeerConnection(t *testing.T) {
UserAgentName: "peer",
UserAgentVersion: "1.0",
UserAgentComments: []string{"comment"},
ChainParams: &dagconfig.MainNetParams,
DAGParams: &dagconfig.MainNetParams,
ProtocolVersion: wire.RejectVersion, // Configure with older version
Services: 0,
Subnetwork: &wire.SubnetworkSupportsAll,
}
peer2Cfg := &peer.Config{
Listeners: peer1Cfg.Listeners,
UserAgentName: "peer",
UserAgentVersion: "1.0",
UserAgentComments: []string{"comment"},
ChainParams: &dagconfig.MainNetParams,
DAGParams: &dagconfig.MainNetParams,
Services: wire.SFNodeNetwork,
Subnetwork: &wire.SubnetworkSupportsAll,
}
wantStats1 := peerStats{
@ -250,8 +252,8 @@ func TestPeerConnection(t *testing.T) {
wantLastPingNonce: uint64(0),
wantLastPingMicros: int64(0),
wantTimeOffset: int64(0),
wantBytesSent: 167, // 143 version + 24 verack
wantBytesReceived: 167,
wantBytesSent: 187, // 163 version + 24 verack
wantBytesReceived: 187,
}
wantStats2 := peerStats{
wantUserAgent: wire.DefaultUserAgent + "peer:1.0(comment)/",
@ -264,8 +266,8 @@ func TestPeerConnection(t *testing.T) {
wantLastPingNonce: uint64(0),
wantLastPingMicros: int64(0),
wantTimeOffset: int64(0),
wantBytesSent: 167, // 143 version + 24 verack
wantBytesReceived: 167,
wantBytesSent: 187, // 163 version + 24 verack
wantBytesReceived: 187,
}
tests := []struct {
@ -436,8 +438,9 @@ func TestPeerListeners(t *testing.T) {
UserAgentName: "peer",
UserAgentVersion: "1.0",
UserAgentComments: []string{"comment"},
ChainParams: &dagconfig.MainNetParams,
DAGParams: &dagconfig.MainNetParams,
Services: wire.SFNodeBloom,
Subnetwork: &wire.SubnetworkSupportsAll,
}
inConn, outConn := pipe(
&conn{raddr: "10.0.0.1:8333"},
@ -606,8 +609,9 @@ func TestOutboundPeer(t *testing.T) {
UserAgentName: "peer",
UserAgentVersion: "1.0",
UserAgentComments: []string{"comment"},
ChainParams: &dagconfig.MainNetParams,
DAGParams: &dagconfig.MainNetParams,
Services: 0,
Subnetwork: &wire.SubnetworkSupportsAll,
}
r, w := io.Pipe()
@ -695,7 +699,7 @@ func TestOutboundPeer(t *testing.T) {
p1.Disconnect()
// Test regression
peerCfg.ChainParams = &dagconfig.RegressionNetParams
peerCfg.DAGParams = &dagconfig.RegressionNetParams
peerCfg.Services = wire.SFNodeBloom
r2, w2 := io.Pipe()
c2 := &conn{raddr: "10.0.0.1:8333", Writer: w2, Reader: r2}
@ -746,8 +750,9 @@ func TestUnsupportedVersionPeer(t *testing.T) {
UserAgentName: "peer",
UserAgentVersion: "1.0",
UserAgentComments: []string{"comment"},
ChainParams: &dagconfig.MainNetParams,
DAGParams: &dagconfig.MainNetParams,
Services: 0,
Subnetwork: &wire.SubnetworkSupportsAll,
}
localNA := wire.NewNetAddressIPPort(
@ -778,7 +783,7 @@ func TestUnsupportedVersionPeer(t *testing.T) {
_, msg, _, err := wire.ReadMessageN(
remoteConn,
p.ProtocolVersion(),
peerCfg.ChainParams.Net,
peerCfg.DAGParams.Net,
)
if err == io.EOF {
close(outboundMessages)
@ -804,14 +809,14 @@ func TestUnsupportedVersionPeer(t *testing.T) {
}
// Remote peer writes version message advertising invalid protocol version 1
invalidVersionMsg := wire.NewMsgVersion(remoteNA, localNA, 0, 0)
invalidVersionMsg := wire.NewMsgVersion(remoteNA, localNA, 0, 0, &wire.SubnetworkSupportsAll)
invalidVersionMsg.ProtocolVersion = 1
_, err = wire.WriteMessageN(
remoteConn.Writer,
invalidVersionMsg,
uint32(invalidVersionMsg.ProtocolVersion),
peerCfg.ChainParams.Net,
peerCfg.DAGParams.Net,
)
if err != nil {
t.Fatalf("wire.WriteMessageN: unexpected err - %v\n", err)

View File

@ -1812,10 +1812,11 @@ func newPeerConfig(sp *Peer) *peer.Config {
UserAgentName: userAgentName,
UserAgentVersion: userAgentVersion,
UserAgentComments: config.MainConfig().UserAgentComments,
ChainParams: sp.server.DAGParams,
DAGParams: sp.server.DAGParams,
Services: sp.server.services,
DisableRelayTx: config.MainConfig().BlocksOnly,
ProtocolVersion: peer.MaxProtocolVersion,
Subnetwork: config.MainConfig().Subnetwork,
}
}

View File

@ -109,7 +109,7 @@ func NewServer(listenAddrs []string, db database.DB, dagParams *dagconfig.Params
blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy,
s.p2pServer.DAGParams, s.p2pServer.TxMemPool, s.p2pServer.DAG, s.p2pServer.TimeSource, s.p2pServer.SigCache)
s.cpuminer = cpuminer.New(&cpuminer.Config{
ChainParams: dagParams,
DAGParams: dagParams,
BlockTemplateGenerator: blockTemplateGenerator,
MiningAddrs: cfg.MiningAddrs,
ProcessBlock: s.p2pServer.SyncManager.ProcessBlock,

View File

@ -46,7 +46,7 @@ func TestMessage(t *testing.T) {
addrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333}
me := NewNetAddress(addrMe, SFNodeNetwork)
me.Timestamp = time.Time{} // Version message has zero value timestamp.
msgVersion := NewMsgVersion(me, you, 123123, 0)
msgVersion := NewMsgVersion(me, you, 123123, 0, &SubnetworkSupportsAll)
msgVerack := NewMsgVerAck()
msgGetAddr := NewMsgGetAddr()
@ -86,7 +86,7 @@ func TestMessage(t *testing.T) {
btcnet BitcoinNet // Network to use for wire encoding
bytes int // Expected num bytes read/written
}{
{msgVersion, msgVersion, pver, MainNet, 125},
{msgVersion, msgVersion, pver, MainNet, 145},
{msgVerack, msgVerack, pver, MainNet, 24},
{msgGetAddr, msgGetAddr, pver, MainNet, 24},
{msgAddr, msgAddr, pver, MainNet, 25},

View File

@ -7,6 +7,7 @@ package wire
import (
"bytes"
"fmt"
"github.com/daglabs/btcd/util/subnetworkid"
"io"
"strings"
"time"
@ -55,6 +56,9 @@ type MsgVersion struct {
// Don't announce transactions to peer.
DisableRelayTx bool
// The subnetwork of the generator of the version message.
Subnetwork subnetworkid.SubnetworkID
}
// HasService returns whether the specified service is supported by the peer
@ -89,6 +93,11 @@ func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error {
return err
}
err = readElement(buf, &msg.Subnetwork)
if err != nil {
return err
}
err = readNetAddress(buf, pver, &msg.AddrYou, false)
if err != nil {
return err
@ -161,6 +170,11 @@ func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32) error {
return err
}
err = writeElement(w, msg.Subnetwork)
if err != nil {
return err
}
err = writeNetAddress(w, pver, &msg.AddrYou, false)
if err != nil {
return err
@ -221,7 +235,7 @@ func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 {
// Message interface using the passed parameters and defaults for the remaining
// fields.
func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64,
lastBlock int32) *MsgVersion {
lastBlock int32, subnetworkID *subnetworkid.SubnetworkID) *MsgVersion {
// Limit the timestamp to one second precision since the protocol
// doesn't support better.
@ -235,6 +249,7 @@ func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64,
UserAgent: DefaultUserAgent,
LastBlock: lastBlock,
DisableRelayTx: false,
Subnetwork: *subnetworkID,
}
}

View File

@ -32,7 +32,7 @@ func TestVersion(t *testing.T) {
}
// Ensure we get the correct data back out.
msg := NewMsgVersion(me, you, nonce, lastBlock)
msg := NewMsgVersion(me, you, nonce, lastBlock, &SubnetworkSupportsAll)
if msg.ProtocolVersion != int32(pver) {
t.Errorf("NewMsgVersion: wrong protocol version - got %v, want %v",
msg.ProtocolVersion, pver)
@ -266,14 +266,14 @@ func TestVersionWireErrors(t *testing.T) {
// Make a new buffer big enough to hold the base version plus the new
// bytes for the bigger varint to hold the new size of the user agent
// and the new user agent string. Then stich it all together.
// and the new user agent string. Then stitch it all together.
newLen := len(baseVersionEncoded) - len(baseVersion.UserAgent)
newLen = newLen + len(newUAVarIntBuf.Bytes()) - 1 + len(newUA)
exceedUAVerEncoded := make([]byte, newLen)
copy(exceedUAVerEncoded, baseVersionEncoded[0:80])
copy(exceedUAVerEncoded[80:], newUAVarIntBuf.Bytes())
copy(exceedUAVerEncoded[83:], []byte(newUA))
copy(exceedUAVerEncoded[83+len(newUA):], baseVersionEncoded[97:100])
copy(exceedUAVerEncoded, baseVersionEncoded[0:100])
copy(exceedUAVerEncoded[100:], newUAVarIntBuf.Bytes())
copy(exceedUAVerEncoded[103:], []byte(newUA))
copy(exceedUAVerEncoded[103+len(newUA):], baseVersionEncoded[117:120])
tests := []struct {
in *MsgVersion // Value to encode
@ -289,23 +289,25 @@ func TestVersionWireErrors(t *testing.T) {
{baseVersion, baseVersionEncoded, pver, 4, io.ErrShortWrite, io.EOF},
// Force error in timestamp.
{baseVersion, baseVersionEncoded, pver, 12, io.ErrShortWrite, io.EOF},
// Force error in remote address.
// Force error in subnetwork.
{baseVersion, baseVersionEncoded, pver, 20, io.ErrShortWrite, io.EOF},
// Force error in remote address.
{baseVersion, baseVersionEncoded, pver, 40, io.ErrShortWrite, io.EOF},
// Force error in local address.
{baseVersion, baseVersionEncoded, pver, 47, io.ErrShortWrite, io.ErrUnexpectedEOF},
{baseVersion, baseVersionEncoded, pver, 67, io.ErrShortWrite, io.ErrUnexpectedEOF},
// Force error in nonce.
{baseVersion, baseVersionEncoded, pver, 73, io.ErrShortWrite, io.ErrUnexpectedEOF},
{baseVersion, baseVersionEncoded, pver, 93, io.ErrShortWrite, io.ErrUnexpectedEOF},
// Force error in user agent length.
{baseVersion, baseVersionEncoded, pver, 81, io.ErrShortWrite, io.EOF},
{baseVersion, baseVersionEncoded, pver, 101, io.ErrShortWrite, io.EOF},
// Force error in user agent.
{baseVersion, baseVersionEncoded, pver, 82, io.ErrShortWrite, io.ErrUnexpectedEOF},
{baseVersion, baseVersionEncoded, pver, 102, io.ErrShortWrite, io.ErrUnexpectedEOF},
// Force error in last block.
{baseVersion, baseVersionEncoded, pver, 98, io.ErrShortWrite, io.ErrUnexpectedEOF},
{baseVersion, baseVersionEncoded, pver, 118, io.ErrShortWrite, io.ErrUnexpectedEOF},
// Force error in relay tx - no read error should happen since
// it's optional.
{
baseVersionBIP0037, baseVersionBIP0037Encoded,
BIP0037Version, 101, io.ErrShortWrite, nil,
BIP0037Version, 121, io.ErrShortWrite, nil,
},
// Force error due to user agent too big
{exceedUAVer, exceedUAVerEncoded, pver, newLen, wireErr, wireErr},
@ -483,6 +485,9 @@ var baseVersionEncoded = []byte{
0x62, 0xea, 0x00, 0x00, // Protocol version 60002
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork
0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, // Subnetwork SupportsAll
// AddrYou -- No timestamp for NetAddress in version message
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -529,6 +534,9 @@ var baseVersionBIP0037Encoded = []byte{
0x71, 0x11, 0x01, 0x00, // Protocol version 70001
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork
0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, // Subnetwork SupportsAll
// AddrYou -- No timestamp for NetAddress in version message
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,