// TestGetAddr tests the MsgGetAddr API. func TestGetAddr(t *testing.T) { pver := btcwire.ProtocolVersion // Ensure the command is expected value. wantCmd := "getaddr" msg := btcwire.NewMsgGetAddr() if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgGetAddr: wrong command - got %v want %v", cmd, wantCmd) } // Ensure max payload is expected value for latest protocol version. // Num addresses (varInt) + max allowed addresses. wantPayload := uint32(0) 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) } return }
func connHandler(id int, outAddrs chan<- []*btc.NetAddress, outNode chan<- Node, inAddr <-chan *btc.NetAddress) { // A worker that deals with the connection to a single bitcoin node. // It writes the list of nodes reported by node into out. // It also writes a valid node into outNode. // It reads from inAddr everytime it closes a connection for { addr := <-inAddr strA := addressFmt(*addr) threadLog := func(reported LogLevel, msg string) { if reported <= Level { logger.Printf("[%d] %s: %s\n", id, strA, msg) } } connProtoVer := btc.ProtocolVersion write := composeWrite(threadLog, connProtoVer) conn, err := net.DialTimeout("tcp", strA, time.Millisecond*500) if err != nil { threadLog(Log, err.Error()) continue } threadLog(Info, "Connected") ver_m, _ := btc.NewMsgVersionFromConn(conn, genNonce(), 0) ver_m.AddUserAgent("btcmonitor", "0.0.1") write(conn, ver_m) // We are looking for successful addr messages wins := 0 // After 10 seconds we just close the conn and handle errors time.AfterFunc(time.Second*10, func() { conn.Close() }) MessageLoop: for { var resp btc.Message resp, _, err := btc.ReadMessage(conn, connProtoVer, btcnet) if err != nil { threadLog(Log, err.Error()) break MessageLoop } threadLog(Info, resp.Command()) switch resp := resp.(type) { case *btc.MsgVersion: nodePVer := uint32(resp.ProtocolVersion) if nodePVer < connProtoVer { connProtoVer = nodePVer write = composeWrite(threadLog, connProtoVer) } node := convNode(*addr, *resp) outNode <- node verack := btc.NewMsgVerAck() write(conn, verack) getAddr := btc.NewMsgGetAddr() write(conn, getAddr) case *btc.MsgAddr: wins += 1 addrs := resp.AddrList outAddrs <- addrs if wins == 3 { break MessageLoop } case *btc.MsgPing: nonce := resp.Nonce pong := btc.NewMsgPong(nonce) write(conn, pong) } } } }
// TestGetAddrWire tests the MsgGetAddr wire encode and decode for various // protocol versions. func TestGetAddrWire(t *testing.T) { msgGetAddr := btcwire.NewMsgGetAddr() msgGetAddrEncoded := []byte{} tests := []struct { in *btcwire.MsgGetAddr // Message to encode out *btcwire.MsgGetAddr // Expected decoded message buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { msgGetAddr, msgGetAddr, msgGetAddrEncoded, btcwire.ProtocolVersion, }, // Protocol version BIP0035Version. { msgGetAddr, msgGetAddr, msgGetAddrEncoded, btcwire.BIP0035Version, }, // Protocol version BIP0031Version. { msgGetAddr, msgGetAddr, msgGetAddrEncoded, btcwire.BIP0031Version, }, // Protocol version NetAddressTimeVersion. { msgGetAddr, msgGetAddr, msgGetAddrEncoded, btcwire.NetAddressTimeVersion, }, // Protocol version MultipleAddressVersion. { msgGetAddr, msgGetAddr, msgGetAddrEncoded, btcwire.MultipleAddressVersion, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Encode the message to wire format. var buf bytes.Buffer err := test.in.BtcEncode(&buf, test.pver) if err != nil { t.Errorf("BtcEncode #%d error %v", i, err) continue } if !bytes.Equal(buf.Bytes(), test.buf) { t.Errorf("BtcEncode #%d\n got: %s want: %s", i, spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) continue } // Decode the message from wire format. var msg btcwire.MsgGetAddr rbuf := bytes.NewBuffer(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) continue } if !reflect.DeepEqual(&msg, test.out) { t.Errorf("BtcDecode #%d\n got: %s want: %s", i, spew.Sdump(msg), spew.Sdump(test.out)) continue } } }
// handleVersionMsg is invoked when a peer receives a version bitcoin message // and is used to negotiate the protocol version details as well as kick start // the communications. func (p *peer) handleVersionMsg(msg *btcwire.MsgVersion) { // Detect self connections. if msg.Nonce == p.server.nonce { log.Debugf("PEER: Disconnecting peer connected to self %s", p.addr) p.Disconnect() return } // Limit to one version message per peer. if p.versionKnown { p.logError("PEER: Only one version message per peer is allowed %s.", p.addr) p.Disconnect() return } // Negotiate the protocol version. p.protocolVersion = minUint32(p.protocolVersion, uint32(msg.ProtocolVersion)) p.versionKnown = true log.Debugf("PEER: Negotiated protocol version %d for peer %s", p.protocolVersion, p.addr) p.lastBlock = msg.LastBlock // 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 // Inbound connections. if p.inbound { // Send version. err := p.pushVersionMsg() if err != nil { p.logError("PEER: Can't send version message: %v", err) p.Disconnect() return } } // Set up a NetAddress for the peer to be used with AddrManager. na, err := newNetAddress(p.conn.RemoteAddr(), p.services) if err != nil { p.logError("PEER: Can't get remote address: %v", err) p.Disconnect() return } p.na = na // Send verack. p.QueueMessage(btcwire.NewMsgVerAck(), nil) // Outbound connections. if !p.inbound { // TODO(davec): Only do this if not doing the initial block // download and the local address is routable. if !cfg.DisableListen { // Advertise the local address. na, err := newNetAddress(p.conn.LocalAddr(), p.services) if err != nil { p.logError("PEER: Can't advertise local "+ "address: %v", err) p.Disconnect() return } addresses := []*btcwire.NetAddress{na} p.pushAddrMsg(addresses) } // Request known addresses if the server address manager needs // more and the peer has a protocol version new enough to // include a timestamp with addresses. hasTimestamp := p.protocolVersion >= btcwire.NetAddressTimeVersion if p.server.addrManager.NeedMoreAddresses() && hasTimestamp { p.QueueMessage(btcwire.NewMsgGetAddr(), nil) } // Mark the address as a known good address. p.server.addrManager.Good(p.na) } else { // A peer might not be advertising the same address that it // actually connected from. One example of why this can happen // is with NAT. Only add the address to the address manager if // the addresses agree. if NetAddressKey(&msg.AddrMe) == NetAddressKey(p.na) { p.server.addrManager.AddAddress(p.na, p.na) p.server.addrManager.Good(p.na) } } // Signal the block manager this peer is a new sync candidate. p.server.blockManager.NewPeer(p) // TODO: Relay alerts. }
// 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 } } }