public void TestPeerAddressRoundtrip() { // copied verbatim from https://en.bitcoin.it/wiki/Protocol_specification#Network_address const string fromSpec = "010000000000000000000000000000000000ffff0a000001208d"; var pa = new PeerAddress(NetworkParameters.ProdNet(), Hex.Decode(fromSpec), 0, 0); var reserialized = Utils.BytesToHexString(pa.BitcoinSerialize()); Assert.AreEqual(reserialized, fromSpec); }
public VersionMessage(NetworkParameters networkParameters, uint newBestHeight) : base(networkParameters) { ClientVersion = NetworkParameters.ProtocolVersion; LocalServices = 0; Time = SystemTime.UnixNow(); // Note that the official client doesn't do anything with these, and finding out your own external IP address // is kind of tricky anyway, so we just put nonsense here for now. MyAddress = new PeerAddress(IPAddress.Loopback, networkParameters.Port, 0); TheirAddress = new PeerAddress(IPAddress.Loopback, networkParameters.Port, 0); SubVersion = LIBRARY_SUBVER; BestHeight = newBestHeight; }
/// <exception cref="ProtocolException"/> protected override void Parse() { ClientVersion = ReadUint32(); LocalServices = ReadUint64(); Time = ReadUint64(); MyAddress = new PeerAddress(NetworkParameters, Bytes, Cursor, 0); Cursor += MyAddress.MessageSize; TheirAddress = new PeerAddress(NetworkParameters, Bytes, Cursor, 0); Cursor += TheirAddress.MessageSize; // uint64 localHostNonce (random data) // We don't care about the localhost nonce. It's used to detect connecting back to yourself in cases where // there are NATs and proxies in the way. However we don't listen for inbound connections so it's irrelevant. _localHostNonce = ReadUint64(); // string subVer (currently "") SubVersion = ReadString(); // int bestHeight (size of known block chain). BestHeight = ReadUint32(); }
public void TestBitcoinSerialize() { var pa = new PeerAddress(IPAddress.Loopback, 8333, 0); Assert.AreEqual("000000000000000000000000000000000000ffff7f000001208d", Utils.BytesToHexString(pa.BitcoinSerialize())); }
/// <summary> /// Connect to the given IP address using the port specified as part of the network parameters. Once construction /// is complete a functioning network channel is set up and running. /// </summary> /// <param name="peerAddress">IP address to connect to. IPv6 is not currently supported by BitCoin. If port is not positive the default port from params is used.</param> /// <param name="networkParameters">Defines which network to connect to and details of the protocol.</param> /// <param name="bestHeight">How many blocks are in our best chain</param> /// <param name="connectTimeout">Timeout in milliseconds when initially connecting to peer</param> /// <exception cref="IOException">If there is a network related failure.</exception> /// <exception cref="ProtocolException">If the version negotiation failed.</exception> public NetworkConnection(PeerAddress peerAddress, NetworkParameters networkParameters, uint bestHeight, int connectTimeout = 60000) { _networkParameters = networkParameters; _remoteIp = peerAddress.IpAddress; var port = (peerAddress.Port > 0) ? peerAddress.Port : networkParameters.Port; var address = new IPEndPoint(_remoteIp, port); _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _socket.Connect(address); _socket.SendTimeout = _socket.ReceiveTimeout = connectTimeout; _outputStream = new NetworkStream(_socket, FileAccess.Write); _inputStream = new NetworkStream(_socket, FileAccess.Read); // the version message never uses check-summing. Update check-summing property after version is read. _serializer = new BitcoinSerializer(networkParameters); // Announce ourselves. This has to come first to connect to clients beyond v0.30.20.2 which wait to hear // from us until they send their version message back. var versionMessage = new VersionMessage(networkParameters, bestHeight); //Log.DebugFormat("Version Message: {0}", versionMessage); WriteMessage(versionMessage); //Log.Debug("Sent version message. Now we should read the ack from the peer."); VersionMessage versionMessageFromPeer; while ((versionMessage = ReadMessage() as VersionMessage)==null) { } Log.Info("WE HAVE A VERSION MESSAGE!"); // When connecting, the remote peer sends us a version message with various bits of // useful data in it. We need to know the peer protocol version before we can talk to it. _versionMessage = (VersionMessage) versionMessage; //Log.Debug("read message of type version."); Log.Debug(_versionMessage); // Now it's our turn ... // Send an ACK message stating we accept the peers protocol version. WriteMessage(new VersionAckMessage()); // And get one back ... ReadMessage(); // Switch to the new protocol version. var peerVersion = _versionMessage.ClientVersion; Log.InfoFormat("Connected to peer: version={0}, subVer='{1}', services=0x{2:X}, time={3}, blocks={4}", peerVersion, _versionMessage.SubVersion, _versionMessage.LocalServices, UnixTime.FromUnixTime(_versionMessage.Time), _versionMessage.BestHeight ); // BitcoinSharp is a client mode implementation. That means there's not much point in us talking to other client // mode nodes because we can't download the data from them we need to find/verify transactions. if (!_versionMessage.HasBlockChain()) { // Shut down the socket try { Shutdown(); } catch (IOException) { // ignore exceptions while aborting } throw new ProtocolException("Peer does not have a copy of the block chain."); } // Handshake is done! }
/// <summary> /// Depending on the environment, this should normally be between 1 and 10, default is 4. /// </summary> /// <summary> /// Add an address to the list of potential peers to connect to. /// </summary> public void AddAddress(PeerAddress peerAddress) { // TODO(miron) consider de-duplication _inactives.Add(peerAddress); }
/// <exception cref="ProtocolException" /> protected override void Parse() { var numAddresses = ReadVarInt(); // Guard against ultra large messages that will crash us. if (numAddresses > MaxAddresses) throw new ProtocolException("ipAddress message too large."); Addresses = new List<PeerAddress>((int) numAddresses); for (var i = 0UL; i < numAddresses; i++) { var peerAddress = new PeerAddress(NetworkParameters, Bytes, Cursor, ProtocolVersion); Addresses.Add(peerAddress); Cursor += peerAddress.MessageSize; } }