Methods to serialize and de-serialize messages to the BitCoin network format as defined in the BitCoin protocol specification at https://en.bitcoin.it/wiki/Protocol_specification
To be able to serialize and deserialize new Message subclasses the following criteria needs to be met.
  • The proper Class instance needs to be mapped to it's message name in the names variable below
  • There needs to be a constructor matching: NetworkParameters params, byte[] payload
  • Message.bitcoinSerializeToStream() needs to be properly subclassed
예제 #1
0
        /// <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="params">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 @params, uint bestHeight, int connectTimeout)
        {
            _params   = @params;
            _remoteIp = peerAddress.Addr;

            var port = (peerAddress.Port > 0) ? peerAddress.Port : @params.Port;

            var address = new IPEndPoint(_remoteIp, port);

            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.Connect(address);
            _socket.SendTimeout = _socket.ReceiveTimeout = connectTimeout;

            _out = new NetworkStream(_socket, FileAccess.Write);
            _in  = new NetworkStream(_socket, FileAccess.Read);

            // the version message never uses check-summing. Update check-summing property after version is read.
            _serializer = new BitcoinSerializer(@params, false);

            // 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.
            WriteMessage(new VersionMessage(@params, bestHeight));
            // 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)ReadMessage();
            // Now it's our turn ...
            // Send an ACK message stating we accept the peers protocol version.
            WriteMessage(new VersionAck());
            // 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.SubVer,
                            _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.");
            }
            // newer clients use check-summing
            _serializer.UseChecksumming(peerVersion >= 209);
            // Handshake is done!
        }
        /// <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="params">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 @params, uint bestHeight, int connectTimeout)
        {
            _params = @params;
            _remoteIp = peerAddress.Addr;

            var port = (peerAddress.Port > 0) ? peerAddress.Port : @params.Port;

            var address = new IPEndPoint(_remoteIp, port);
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.Connect(address);
            _socket.SendTimeout = _socket.ReceiveTimeout = connectTimeout;

            _out = new NetworkStream(_socket, FileAccess.Write);
            _in = new NetworkStream(_socket, FileAccess.Read);

            // the version message never uses check-summing. Update check-summing property after version is read.
            _serializer = new BitcoinSerializer(@params, false);

            // 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.
            WriteMessage(new VersionMessage(@params, bestHeight));
            // 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) ReadMessage();
            // Now it's our turn ...
            // Send an ACK message stating we accept the peers protocol version.
            WriteMessage(new VersionAck());
            // 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.SubVer,
                            _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.");
            }
            // newer clients use check-summing
            _serializer.UseChecksumming(peerVersion >= 209);
            // Handshake is done!
        }