示例#1
0
 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);
 }
示例#2
0
 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;
 }
示例#3
0
 /// <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();
 }
示例#4
0
 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!
        }
示例#6
0
 /// <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);
 }
示例#7
0
 /// <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;
     }
 }