// pushVersionMsg sends a version message to the connected peer using the // current state. func (p *peer) pushVersionMsg() error { _, blockNum, err := p.server.db.NewestSha() if err != nil { return 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 cfg.Proxy != "" { proxyaddress, _, err := net.SplitHostPort(cfg.Proxy) // invalid proxy means poorly configured, be on the safe side. if err != nil || p.na.IP.String() == proxyaddress { theirNa = &btcwire.NetAddress{ Timestamp: time.Now(), IP: net.IP([]byte{0, 0, 0, 0}), } } } // Version message. msg := btcwire.NewMsgVersion( p.server.addrManager.getBestLocalAddress(p.na), theirNa, p.server.nonce, userAgent, int32(blockNum)) // 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 = btcwire.SFNodeNetwork // Advertise that we're a full node. msg.Services = btcwire.SFNodeNetwork p.QueueMessage(msg, nil) return nil }
// pushVersionMsg sends a version message to the connected peer using the // current state. func (p *peer) pushVersionMsg() error { _, blockNum, err := p.server.db.NewestSha() if err != nil { return err } // Create a NetAddress for the local IP. Don't assume any services // until we know otherwise. naMe, err := newNetAddress(p.conn.LocalAddr(), 0) if err != nil { return err } // Create a NetAddress for the remote IP. Don't assume any services // until we know otherwise. naYou, err := newNetAddress(p.conn.RemoteAddr(), 0) if err != nil { return err } // Version message. msg := btcwire.NewMsgVersion(naMe, naYou, p.server.nonce, userAgent, int32(blockNum)) // 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 = btcwire.SFNodeNetwork // Advertise that we're a full node. msg.Services = btcwire.SFNodeNetwork p.QueueMessage(msg, nil) return nil }
func (peer *Peer) SendVersionMsg() error { me, err := NewNetAddress(peer.conn.LocalAddr(), 0) if err != nil { return err } you, err := NewNetAddress(peer.conn.RemoteAddr(), 0) if err != nil { return err } msg := btcwire.NewMsgVersion(me, you, 1, "mscd", int32(peer.server.db.LastBlock())) msg.AddrYou.Services = btcwire.SFNodeNetwork msg.Services = btcwire.SFNodeNetwork peer.QueueMsg(msg) return nil }
// TestVersion tests the MsgVersion API. func TestVersion(t *testing.T) { pver := btcwire.ProtocolVersion // Create version message data. userAgent := "/btcdtest:0.0.1/" lastBlock := int32(234234) tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} me, err := btcwire.NewNetAddress(tcpAddrMe, btcwire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } tcpAddrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333} you, err := btcwire.NewNetAddress(tcpAddrYou, btcwire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } nonce, err := btcwire.RandomUint64() if err != nil { t.Errorf("RandomUint64: error generating nonce: %v", err) } // Ensure we get the correct data back out. msg := btcwire.NewMsgVersion(me, you, nonce, userAgent, lastBlock) if msg.ProtocolVersion != int32(pver) { t.Errorf("NewMsgVersion: wrong protocol version - got %v, want %v", msg.ProtocolVersion, pver) } if !reflect.DeepEqual(&msg.AddrMe, me) { t.Errorf("NewMsgVersion: wrong me address - got %v, want %v", spew.Sdump(&msg.AddrMe), spew.Sdump(me)) } if !reflect.DeepEqual(&msg.AddrYou, you) { t.Errorf("NewMsgVersion: wrong you address - got %v, want %v", spew.Sdump(&msg.AddrYou), spew.Sdump(you)) } if msg.Nonce != nonce { t.Errorf("NewMsgVersion: wrong nonce - got %v, want %v", msg.Nonce, nonce) } if msg.UserAgent != userAgent { t.Errorf("NewMsgVersion: wrong user agent - got %v, want %v", msg.UserAgent, userAgent) } if msg.LastBlock != lastBlock { t.Errorf("NewMsgVersion: wrong last block - got %v, want %v", msg.LastBlock, lastBlock) } // Version message should not have any services set by default. if msg.Services != 0 { t.Errorf("NewMsgVersion: wrong default services - got %v, want %v", msg.Services, 0) } if msg.HasService(btcwire.SFNodeNetwork) { t.Errorf("HasService: SFNodeNetwork service is set") } // Ensure the command is expected value. wantCmd := "version" if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgVersion: wrong command - got %v want %v", cmd, wantCmd) } // Ensure max payload is expected value. // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + // remote and local net addresses + nonce 8 bytes + length of user agent // (varInt) + max allowed user agent length + last block 4 bytes. wantPayload := uint32(2101) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { t.Errorf("MaxPayloadLength: wrong max payload length for "+ "protocol version %d - got %v, want %v", pver, maxPayload, wantPayload) } // Ensure adding the full service node flag works. msg.AddService(btcwire.SFNodeNetwork) if msg.Services != btcwire.SFNodeNetwork { t.Errorf("AddService: wrong services - got %v, want %v", msg.Services, btcwire.SFNodeNetwork) } if !msg.HasService(btcwire.SFNodeNetwork) { t.Errorf("HasService: SFNodeNetwork service not set") } // Use a fake connection. conn := &fakeConn{localAddr: tcpAddrMe, remoteAddr: tcpAddrYou} msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, userAgent, lastBlock) if err != nil { t.Errorf("NewMsgVersionFromConn: %v", err) } // Ensure we get the correct connection data back out. if !msg.AddrMe.IP.Equal(tcpAddrMe.IP) { t.Errorf("NewMsgVersionFromConn: wrong me ip - got %v, want %v", msg.AddrMe.IP, tcpAddrMe.IP) } if !msg.AddrYou.IP.Equal(tcpAddrYou.IP) { t.Errorf("NewMsgVersionFromConn: wrong you ip - got %v, want %v", msg.AddrYou.IP, tcpAddrYou.IP) } // Use a fake connection with local UDP addresses to force a failure. conn = &fakeConn{ localAddr: &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333}, remoteAddr: tcpAddrYou, } msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, userAgent, lastBlock) if err != btcwire.ErrInvalidNetAddr { t.Errorf("NewMsgVersionFromConn: expected error not received "+ "- got %v, want %v", err, btcwire.ErrInvalidNetAddr) } // Use a fake connection with remote UDP addresses to force a failure. conn = &fakeConn{ localAddr: tcpAddrMe, remoteAddr: &net.UDPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333}, } msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, userAgent, lastBlock) if err != btcwire.ErrInvalidNetAddr { t.Errorf("NewMsgVersionFromConn: expected error not received "+ "- got %v, want %v", err, btcwire.ErrInvalidNetAddr) } return }
// TestVersion tests the MsgVersion API. func TestVersion(t *testing.T) { pver := btcwire.ProtocolVersion // Create version message data. lastBlock := int32(234234) tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} me, err := btcwire.NewNetAddress(tcpAddrMe, btcwire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } tcpAddrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333} you, err := btcwire.NewNetAddress(tcpAddrYou, btcwire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } nonce, err := btcwire.RandomUint64() if err != nil { t.Errorf("RandomUint64: error generating nonce: %v", err) } // Ensure we get the correct data back out. msg := btcwire.NewMsgVersion(me, you, nonce, lastBlock) if msg.ProtocolVersion != int32(pver) { t.Errorf("NewMsgVersion: wrong protocol version - got %v, want %v", msg.ProtocolVersion, pver) } if !reflect.DeepEqual(&msg.AddrMe, me) { t.Errorf("NewMsgVersion: wrong me address - got %v, want %v", spew.Sdump(&msg.AddrMe), spew.Sdump(me)) } if !reflect.DeepEqual(&msg.AddrYou, you) { t.Errorf("NewMsgVersion: wrong you address - got %v, want %v", spew.Sdump(&msg.AddrYou), spew.Sdump(you)) } if msg.Nonce != nonce { t.Errorf("NewMsgVersion: wrong nonce - got %v, want %v", msg.Nonce, nonce) } if msg.UserAgent != btcwire.DefaultUserAgent { t.Errorf("NewMsgVersion: wrong user agent - got %v, want %v", msg.UserAgent, btcwire.DefaultUserAgent) } if msg.LastBlock != lastBlock { t.Errorf("NewMsgVersion: wrong last block - got %v, want %v", msg.LastBlock, lastBlock) } if msg.DisableRelayTx != false { t.Errorf("NewMsgVersion: disable relay tx is not false by "+ "default - got %v, want %v", msg.DisableRelayTx, false) } msg.AddUserAgent("myclient", "1.2.3", "optional", "comments") customUserAgent := btcwire.DefaultUserAgent + "myclient:1.2.3(optional; comments)/" if msg.UserAgent != customUserAgent { t.Errorf("AddUserAgent: wrong user agent - got %s, want %s", msg.UserAgent, customUserAgent) } msg.AddUserAgent("mygui", "3.4.5") customUserAgent += "mygui:3.4.5/" if msg.UserAgent != customUserAgent { t.Errorf("AddUserAgent: wrong user agent - got %s, want %s", msg.UserAgent, customUserAgent) } // accounting for ":", "/" err = msg.AddUserAgent(strings.Repeat("t", btcwire.MaxUserAgentLen-len(customUserAgent)-2+1), "") if _, ok := err.(*btcwire.MessageError); !ok { t.Errorf("AddUserAgent: expected error not received "+ "- got %v, want %T", err, btcwire.MessageError{}) } // Version message should not have any services set by default. if msg.Services != 0 { t.Errorf("NewMsgVersion: wrong default services - got %v, want %v", msg.Services, 0) } if msg.HasService(btcwire.SFNodeNetwork) { t.Errorf("HasService: SFNodeNetwork service is set") } // Ensure the command is expected value. wantCmd := "version" if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgVersion: wrong command - got %v want %v", cmd, wantCmd) } // Ensure max payload is expected value. // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + // remote and local net addresses + nonce 8 bytes + length of user agent // (varInt) + max allowed user agent length + last block 4 bytes + // relay transactions flag 1 byte. wantPayload := uint32(2102) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { t.Errorf("MaxPayloadLength: wrong max payload length for "+ "protocol version %d - got %v, want %v", pver, maxPayload, wantPayload) } // Ensure adding the full service node flag works. msg.AddService(btcwire.SFNodeNetwork) if msg.Services != btcwire.SFNodeNetwork { t.Errorf("AddService: wrong services - got %v, want %v", msg.Services, btcwire.SFNodeNetwork) } if !msg.HasService(btcwire.SFNodeNetwork) { t.Errorf("HasService: SFNodeNetwork service not set") } // Use a fake connection. conn := &fakeConn{localAddr: tcpAddrMe, remoteAddr: tcpAddrYou} msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, lastBlock) if err != nil { t.Errorf("NewMsgVersionFromConn: %v", err) } // Ensure we get the correct connection data back out. if !msg.AddrMe.IP.Equal(tcpAddrMe.IP) { t.Errorf("NewMsgVersionFromConn: wrong me ip - got %v, want %v", msg.AddrMe.IP, tcpAddrMe.IP) } if !msg.AddrYou.IP.Equal(tcpAddrYou.IP) { t.Errorf("NewMsgVersionFromConn: wrong you ip - got %v, want %v", msg.AddrYou.IP, tcpAddrYou.IP) } // Use a fake connection with local UDP addresses to force a failure. conn = &fakeConn{ localAddr: &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333}, remoteAddr: tcpAddrYou, } msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, lastBlock) if err != btcwire.ErrInvalidNetAddr { t.Errorf("NewMsgVersionFromConn: expected error not received "+ "- got %v, want %v", err, btcwire.ErrInvalidNetAddr) } // Use a fake connection with remote UDP addresses to force a failure. conn = &fakeConn{ localAddr: tcpAddrMe, remoteAddr: &net.UDPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333}, } msg, err = btcwire.NewMsgVersionFromConn(conn, nonce, lastBlock) if err != btcwire.ErrInvalidNetAddr { t.Errorf("NewMsgVersionFromConn: expected error not received "+ "- got %v, want %v", err, btcwire.ErrInvalidNetAddr) } return }
// TestMessage tests the Read/WriteMessage API. func TestMessage(t *testing.T) { pver := btcwire.ProtocolVersion // Create the various types of messages to test. // MsgVersion. addrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333} you, err := btcwire.NewNetAddress(addrYou, btcwire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } you.Timestamp = time.Time{} // Version message has zero value timestamp. addrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} me, err := btcwire.NewNetAddress(addrMe, btcwire.SFNodeNetwork) if err != nil { t.Errorf("NewNetAddress: %v", err) } me.Timestamp = time.Time{} // Version message has zero value timestamp. msgVersion := btcwire.NewMsgVersion(me, you, 123123, "/test:0.0.1/", 0) msgVerack := btcwire.NewMsgVerAck() msgGetAddr := btcwire.NewMsgGetAddr() msgAddr := btcwire.NewMsgAddr() msgGetBlocks := btcwire.NewMsgGetBlocks(&btcwire.ShaHash{}) msgBlock := &blockOne msgInv := btcwire.NewMsgInv() msgGetData := btcwire.NewMsgGetData() msgNotFound := btcwire.NewMsgNotFound() msgTx := btcwire.NewMsgTx() msgPing := btcwire.NewMsgPing(123123) msgPong := btcwire.NewMsgPong(123123) msgGetHeaders := btcwire.NewMsgGetHeaders() msgHeaders := btcwire.NewMsgHeaders() msgAlert := btcwire.NewMsgAlert("payload", "signature") msgMemPool := btcwire.NewMsgMemPool() tests := []struct { in btcwire.Message // Value to encode out btcwire.Message // Expected decoded value pver uint32 // Protocol version for wire encoding btcnet btcwire.BitcoinNet // Network to use for wire encoding }{ {msgVersion, msgVersion, pver, btcwire.MainNet}, {msgVerack, msgVerack, pver, btcwire.MainNet}, {msgGetAddr, msgGetAddr, pver, btcwire.MainNet}, {msgAddr, msgAddr, pver, btcwire.MainNet}, {msgGetBlocks, msgGetBlocks, pver, btcwire.MainNet}, {msgBlock, msgBlock, pver, btcwire.MainNet}, {msgInv, msgInv, pver, btcwire.MainNet}, {msgGetData, msgGetData, pver, btcwire.MainNet}, {msgNotFound, msgNotFound, pver, btcwire.MainNet}, {msgTx, msgTx, pver, btcwire.MainNet}, {msgPing, msgPing, pver, btcwire.MainNet}, {msgPong, msgPong, pver, btcwire.MainNet}, {msgGetHeaders, msgGetHeaders, pver, btcwire.MainNet}, {msgHeaders, msgHeaders, pver, btcwire.MainNet}, {msgAlert, msgAlert, pver, btcwire.MainNet}, {msgMemPool, msgMemPool, pver, btcwire.MainNet}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Encode to wire format. var buf bytes.Buffer err := btcwire.WriteMessage(&buf, test.in, test.pver, test.btcnet) if err != nil { t.Errorf("WriteMessage #%d error %v", i, err) continue } // Decode from wire format. rbuf := bytes.NewBuffer(buf.Bytes()) msg, _, err := btcwire.ReadMessage(rbuf, test.pver, test.btcnet) if err != nil { t.Errorf("ReadMessage #%d error %v, msg %v", i, err, spew.Sdump(msg)) continue } if !reflect.DeepEqual(msg, test.out) { t.Errorf("ReadMessage #%d\n got: %v want: %v", i, spew.Sdump(msg), spew.Sdump(test.out)) continue } } }