public void OnNodeConnected(BitcoinEndpoint endpoint)
        {
            BlockLocator locator = null;

            lock (lockObject)
            {
                endpoints.Add(endpoint, new EndpointState(endpoint));
                if (requiredBlocks.Any())
                {
                    int minRequiredBlockHeight = requiredBlocks.Values.Min(b => b.Height);
                    int locatorHeight = minRequiredBlockHeight - 1;
                    List<StoredBlock> parentBlocks = node.Blockchain.GetBlocksByHeight(BlockLocator.GetRequiredBlockHeights(locatorHeight));
                    locator = new BlockLocator();
                    foreach (StoredBlock block in parentBlocks)
                    {
                        locator.AddHash(block.Height, block.Hash);
                    }
                }
            }

            if (locator != null)
            {
                endpoint.WriteMessage(new GetBlocksMessage(endpoint.ProtocolVersion, locator.GetHashes(), new byte[32]));
            }
        }
        private void ProcessHeadersMessage(BitcoinEndpoint endpoint, HeadersMessage message)
        {
            List<StoredBlock> storedBlocks = node.Blockchain.AddHeaders(message.Headers);

            //todo: save blockLocator per node between requests?
            BlockLocator blockLocator = new BlockLocator();

            //todo: what should happen if message contains headers from different branchas?
            bool hasSavedHeaders = false;
            foreach (StoredBlock block in storedBlocks)
            {
                if (block.Height >= 0)
                {
                    //todo: this code assumes that blocks in storedBlocks collections are in order of ascending height and belong to one branch
                    blockLocator.AddHash(block.Height, block.Hash);
                    hasSavedHeaders = true;
                }
            }

            //todo: review this condition
            if (hasSavedHeaders)
            {
                RequestHeaders(endpoint, blockLocator);
            }
        }
        public void TestTruncation()
        {
            BlockLocator locator = new BlockLocator();

            for (int i = 1; i <= 20; i++)
            {
                locator.AddHash(i, BitConverter.GetBytes(i));
            }

            Assert.That(locator.GetHashes().Select(val => BitConverter.ToInt32(val, 0)), Is.EqualTo(new int[]
            {
                20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 8, 4
            }));

            locator.AddHash(16, BitConverter.GetBytes(10016));

            Assert.That(locator.GetHashes().Select(val => BitConverter.ToInt32(val, 0)), Is.EqualTo(new int[]
            {
                10016, 15, 14, 13, 12, 11, 8, 4
            }));
        }
 private static void RequestHeaders(BitcoinEndpoint endpoint, BlockLocator blockLocator)
 {
     endpoint.WriteMessage(new GetHeadersMessage(endpoint.ProtocolVersion, blockLocator.GetHashes(), new byte[32]));
 }
        private void TestSet(int from, int to)
        {
            BlockLocator locator = new BlockLocator();

            for (int i = from; i <= to; i++)
            {
                locator.AddHash(i, BitConverter.GetBytes(i));
            }

            Assert.That(
                locator.GetHashes().Select(val => BitConverter.ToInt32(val, 0)).ToList(),
                Is.EqualTo(CalculateExpectedHeights(from, to)),
                $"Testing set from {from} to {to}.");
        }