<commit_before>﻿using System;
using System.IO;
using System.Net;
using System.Threading;

namespace BitcoinUtilities.P2P
{
    /// <summary>
    /// Provides a P2P Bitcoin network endpoint that listens for incoming messages and provides means for sending messages.
    /// </summary>
    /// <remarks>
    /// Specifications:<br/>
    /// https://en.bitcoin.it/wiki/Protocol_documentation <br/>
    /// https://bitcoin.org/en/developer-reference#p2p-network
    /// </remarks>
    public class BitcoinEndpoint : IDisposable
    {
        private static readonly DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

        private const string UserAgent = "/BitcoinUtilities:0.0.1/";
        private readonly int protocolVersion = 70002;
        private const ulong Services = 0;
        private const bool AcceptBroadcasts = false;
        private const int StartHeight = 0;
        private const ulong Nonce = 0; // todo: support Nonce

        private readonly BitcoinMessageHandler messageHandler;

        private BitcoinConnection conn;
        private Thread thread;
        private volatile bool running;

        public BitcoinEndpoint(BitcoinMessageHandler messageHandler)
        {
            this.messageHandler = messageHandler;
        }

        public void Dispose()
        {
            //todo: shutdown gracefully
            running = false;
            if (conn != null)
            {
                conn.Dispose();
            }
        }

        public int ProtocolVersion
        {
            get { return protocolVersion; }
        }

        public void Connect(string host, int port)
        {
            if (conn != null)
            {
                throw new Exception("Connection is already established.");
            }

            conn = new BitcoinConnection();
            conn.Connect(host, port);

            Start();
        }

        public void Connect(BitcoinConnection connection)
        {
            if (conn != null)
            {
                throw new Exception("Connection is already established.");
            }

            conn = connection;

            Start();
        }

        private void Start()
        {
            BitcoinMessage outVersionMessage = CreateVersionMessage();
            conn.WriteMessage(outVersionMessage);

            BitcoinMessage incVersionMessage = conn.ReadMessage();
            if (incVersionMessage.Command != BitcoinCommands.Version)
            {
                //todo: handle correctly
                throw new Exception("Remote endpoind did not send Version message.");
            }

            //todo: check minimal peer protocol version

            BitcoinMessage outVerAckMessage = new BitcoinMessage(BitcoinCommands.VerAck, new byte[0]);
            conn.WriteMessage(outVerAckMessage);

            BitcoinMessage incVerAckMessage = conn.ReadMessage();
            conn.WriteMessage(outVerAckMessage);

            if (incVerAckMessage.Command != BitcoinCommands.VerAck)
            {
                //todo: handle correctly
                throw new Exception("Remote endpoind did not send VerAck message.");
            }

            running = true;

            thread = new Thread(Listen);
            thread.IsBackground = true; //todo: ??? should it be background?
            thread.Start();
        }

        private void Listen()
        {
            while (running)
            {
                BitcoinMessage message = conn.ReadMessage();<commit_msg>Removed extra verack message in BitcoinEndpoint connection sequence.<commit_after>﻿using System;
using System.IO;
using System.Net;
using System.Threading;

namespace BitcoinUtilities.P2P
{
    /// <summary>
    /// Provides a P2P Bitcoin network endpoint that listens for incoming messages and provides means for sending messages.
    /// </summary>
    /// <remarks>
    /// Specifications:<br/>
    /// https://en.bitcoin.it/wiki/Protocol_documentation <br/>
    /// https://bitcoin.org/en/developer-reference#p2p-network
    /// </remarks>
    public class BitcoinEndpoint : IDisposable
    {
        private static readonly DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

        private const string UserAgent = "/BitcoinUtilities:0.0.1/";
        private readonly int protocolVersion = 70002;
        private const ulong Services = 0;
        private const bool AcceptBroadcasts = false;
        private const int StartHeight = 0;
        private const ulong Nonce = 0; // todo: support Nonce

        private readonly BitcoinMessageHandler messageHandler;

        private BitcoinConnection conn;
        private Thread thread;
        private volatile bool running;

        public BitcoinEndpoint(BitcoinMessageHandler messageHandler)
        {
            this.messageHandler = messageHandler;
        }

        public void Dispose()
        {
            //todo: shutdown gracefully
            running = false;
            if (conn != null)
            {
                conn.Dispose();
            }
        }

        public int ProtocolVersion
        {
            get { return protocolVersion; }
        }

        public void Connect(string host, int port)
        {
            if (conn != null)
            {
                throw new Exception("Connection is already established.");
            }

            conn = new BitcoinConnection();
            conn.Connect(host, port);

            Start();
        }

        public void Connect(BitcoinConnection connection)
        {
            if (conn != null)
            {
                throw new Exception("Connection is already established.");
            }

            conn = connection;

            Start();
        }

        private void Start()
        {
            BitcoinMessage outVersionMessage = CreateVersionMessage();
            conn.WriteMessage(outVersionMessage);

            BitcoinMessage incVersionMessage = conn.ReadMessage();
            if (incVersionMessage.Command != BitcoinCommands.Version)
            {
                //todo: handle correctly
                throw new Exception("Remote endpoind did not send Version message.");
            }

            //todo: check minimal peer protocol version

            BitcoinMessage outVerAckMessage = new BitcoinMessage(BitcoinCommands.VerAck, new byte[0]);
            conn.WriteMessage(outVerAckMessage);

            BitcoinMessage incVerAckMessage = conn.ReadMessage();
            if (incVerAckMessage.Command != BitcoinCommands.VerAck)
            {
                //todo: handle correctly
                throw new Exception("Remote endpoind did not send VerAck message.");
            }

            running = true;

            thread = new Thread(Listen);
            thread.IsBackground = true; //todo: ??? should it be background?
            thread.Start();
        }

        private void Listen()
        {
            while (running)
            {
                BitcoinMessage message = conn.ReadMessage();
{'fraction_non_alphanumeric': 0.084248039914469, 'fraction_numerical': 0.00684248039914469, 'mean_word_length': 1.755695208169678, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6330524', 'n_tokens_mistral': 1701, 'n_tokens_neox': 1629, 'n_words': 479}