示例#1
0
        async Task RetrieveBlocks(IBlocksRetrieverHandler handler)
        {
            var cancellationToken = this.retrieveBlocksCancelSource.Token;
            var height            = await handler.GetBlockHintAsync(cancellationToken);

            while (true)
            {
                // Get block.
                Block block;

                using (var rpc = await this.rpc.CreateChainInformationRpcAsync(cancellationToken))
                {
                    try
                    {
                        block = await rpc.GetBlockAsync(height, cancellationToken);
                    }
                    catch (RPCException ex) when(ex.RPCCode == RPCErrorCode.RPC_INVALID_PARAMETER)
                    {
                        // Invalid block height.
                        await WaitNewBlockAsync(cancellationToken);

                        continue;
                    }
                }

                // Execute handler.
                height = await handler.ProcessBlockAsync(block, height, cancellationToken);
            }
        }
示例#2
0
        async Task RetrieveBlocks(IBlocksRetrieverHandler handler)
        {
            var cancellationToken = this.retrieveBlocksCancelSource.Token;
            var height            = await handler.GetStartBlockAsync(cancellationToken);

            while (true)
            {
                // Get block.
                Block block;

                using (var rpc = await this.rpc.CreateChainInformationRpcAsync(cancellationToken))
                {
                    try
                    {
                        block = await rpc.GetBlockAsync(height, cancellationToken);
                    }
                    catch (RPCException ex) when(ex.RPCCode == RPCErrorCode.RPC_INVALID_PARAMETER)  // Invalid height.
                    {
                        var info = await rpc.GetChainInfoAsync(cancellationToken);

                        var blocks = (int)info.Blocks;

                        if (blocks >= height)
                        {
                            // There is a new block already.
                            continue;
                        }

                        if (blocks == height - 1)
                        {
                            // A block of the target height is not available right now.
                            await WaitNewBlockAsync(cancellationToken);

                            continue;
                        }

                        // There is a re-org happened.
                        await handler.DiscardBlocksAsync(blocks, cancellationToken);

                        height = blocks;
                        continue;
                    }
                }

                // Execute handler.
                height = await handler.ProcessBlockAsync(block, height, cancellationToken);
            }
        }
示例#3
0
        public BlocksRetrieverTests()
        {
            // Start ZeroMQ publisher.
            this.publisher = new PublisherSocket();

            try
            {
                var publisherPort = this.publisher.BindRandomPort("tcp://localhost");

                // Mock config.
                var builder = new ConfigurationBuilder();

                builder.AddInMemoryCollection(new Dictionary <string, string>()
                {
                    { "Zcoin:Rpc:Address", "http://127.0.0.1:8888" },
                    { "Zcoin:Rpc:UserName", "root" },
                    { "Zcoin:Rpc:Password", "abc" },
                    { "Zcoin:ZeroMq:Address", "tcp://localhost:" + publisherPort }
                });

                this.config = builder.Build();

                // Mock RPC.
                this.rpc = new Mock <IChainInformationRpc>();

                this.rpcFactory = new Mock <IRpcFactory>();
                this.rpcFactory.Setup(f => f.CreateChainInformationRpcAsync(It.IsAny <CancellationToken>()))
                .ReturnsAsync(this.rpc.Object);

                // Mock handler.
                this.handler = Substitute.For <IBlocksRetrieverHandler>();

                // Create test subject.
                this.subject = new BlocksRetriever(this.config, this.rpcFactory.Object);
            }
            catch
            {
                this.publisher.Dispose();
                throw;
            }
        }
示例#4
0
        public Task <Task> StartAsync(IBlocksRetrieverHandler handler, CancellationToken cancellationToken)
        {
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            ThrowIfAlreadyDisposed();
            ThrowIfAlreadyRunning();

            Debug.Assert(this.subscriber == null);
            Debug.Assert(this.poller == null);
            Debug.Assert(this.newBlockNotification == null);
            Debug.Assert(this.retrieveBlocksCancelSource == null);
            Debug.Assert(this.retrieveBlocksTask == null);

            // Subscribe to ZeroMQ.
            this.subscriber = new SubscriberSocket();

            try
            {
                this.poller = new NetMQPoller();

                try
                {
                    this.subscriber.ReceiveReady += (sender, e) => NotifyNewBlock();
                    this.subscriber.Connect(this.config.ZeroMq.Address);
                    this.subscriber.Subscribe("hashblock");

                    this.poller.Add(this.subscriber);
                    this.poller.RunAsync();

                    // Start background tasks to retrieve blocks.
                    this.retrieveBlocksCancelSource = new CancellationTokenSource();

                    try
                    {
                        this.retrieveBlocksTask = Task.Run(() => RetrieveBlocks(handler));
                    }
                    catch
                    {
                        this.retrieveBlocksCancelSource.Dispose();
                        this.retrieveBlocksCancelSource = null;
                        throw;
                    }
                }
                catch
                {
                    this.poller.Dispose();
                    this.poller = null;
                    throw;
                }
            }
            catch
            {
                this.subscriber.Dispose();
                this.subscriber = null;
                throw;
            }

            return(Task.FromResult(this.retrieveBlocksTask));
        }