public async Task Does_not_do_full_sync_when_not_needed_with_split()
        {
            BlockTree            minerTree = Build.A.BlockTree(_genesisBlock).OfChainLength(6).TestObject;
            ISynchronizationPeer miner1    = new SynchronizationPeerMock(minerTree);

            AutoResetEvent resetEvent = new AutoResetEvent(false);

            _manager.SyncEvent += (sender, args) =>
            {
                if (args.SyncStatus == SyncStatus.Completed || args.SyncStatus == SyncStatus.Failed)
                {
                    resetEvent.Set();
                }
            };

            _manager.Start();

            Task addMiner1Task = _manager.AddPeer(miner1);
            await Task.WhenAll(addMiner1Task);

            resetEvent.WaitOne(_standardTimeoutUnit);

            Assert.AreEqual(minerTree.BestSuggested.Hash, _blockTree.BestSuggested.Hash, "client agrees with miner before split");

            Block newBlock = Build.A.Block.WithParent(minerTree.Head).TestObject;

            minerTree.SuggestBlock(newBlock);
            minerTree.UpdateMainChain(newBlock);

            ISynchronizationPeer miner2 = Substitute.For <ISynchronizationPeer>();

            miner2.GetHeadBlockNumber(Arg.Any <CancellationToken>()).Returns(miner1.GetHeadBlockNumber(CancellationToken.None));
            miner2.GetHeadBlockHash(Arg.Any <CancellationToken>()).Returns(miner1.GetHeadBlockHash(CancellationToken.None));
            miner2.NodeId.Returns(new NodeId(TestObject.PublicKeyB));

            Assert.AreEqual(newBlock.Number, await miner2.GetHeadBlockNumber(Arg.Any <CancellationToken>()), "number as expected");
            Assert.AreEqual(newBlock.Hash, await miner2.GetHeadBlockHash(default(CancellationToken)), "hash as expected");

            await _manager.AddPeer(miner2);

            resetEvent.WaitOne(_standardTimeoutUnit);

            await miner2.Received().GetBlockHeaders(6, 1, 0, default(CancellationToken));
        }
        private async Task InitPeerInfo(ISynchronizationPeer peer, CancellationToken token)
        {
            if (_logger.IsTrace)
            {
                _logger.Trace($"Requesting head block info from {peer.NodeId}");
            }
            Task <Keccak>  getHashTask   = peer.GetHeadBlockHash(token);
            Task <UInt256> getNumberTask = peer.GetHeadBlockNumber(token);
//            Task<UInt256> getDifficultyTask = peer.GetHeadDifficulty(token);

            await Task.WhenAny(Task.WhenAll(getHashTask, getNumberTask), Task.Delay(10000, token)).ContinueWith(
                t =>
            {
                if (t.IsFaulted)
                {
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"InitPeerInfo failed for node: {peer.NodeId}{Environment.NewLine}{t.Exception}");
                    }
                    RemovePeer(peer);
                    SyncEvent?.Invoke(this, new SyncEventArgs(peer, SyncStatus.InitFailed));
                }
                else if (t.IsCanceled)
                {
                    RemovePeer(peer);
                    SyncEvent?.Invoke(this, new SyncEventArgs(peer, SyncStatus.InitCancelled));
                    token.ThrowIfCancellationRequested();
                }
                else
                {
                    if (_logger.IsTrace)
                    {
                        _logger.Trace($"Received head block info from {peer.NodeId} with head block numer {getNumberTask.Result}");
                    }
                    SyncEvent?.Invoke(
                        this,
                        new SyncEventArgs(peer, SyncStatus.InitCompleted)
                    {
                        NodeBestBlockNumber = getNumberTask.Result,
                        OurBestBlockNumber  = _blockTree.BestSuggested.Number
                    });

                    bool result = _peers.TryGetValue(peer.NodeId, out PeerInfo peerInfo);
                    if (!result)
                    {
                        _logger.Error($"Initializing PeerInfo failed for {peer.NodeId}");
                        throw new EthSynchronizationException($"Initializing peer info failed for {peer.NodeId.ToString()}");
                    }

                    peerInfo.NumberAvailable = getNumberTask.Result;
//                        peerInfo.Difficulty = getDifficultyTask.Result;
                    peerInfo.NumberReceived = _blockTree.BestSuggested.Number;
                    peerInfo.IsInitialized  = true;
                }
            }, token);
        }
        private async Task InitPeerInfo(ISynchronizationPeer peer, CancellationToken token)
        {
            Task <Keccak> getHashTask = peer.GetHeadBlockHash();

            if (_logger.IsDebugEnabled)
            {
                _logger.Debug($"Requesting head block info from {peer.NodeId}");
            }

            Task <BigInteger> getNumberTask = peer.GetHeadBlockNumber(token);
            await Task.WhenAll(getHashTask, getNumberTask).ContinueWith(
                t =>
            {
                if (t.IsFaulted)
                {
                    if (_logger.IsErrorEnabled)
                    {
                        if (t.Exception != null && t.Exception.InnerExceptions.Any(x => x is TimeoutException))
                        {
                            _logger.Warn($"InitPeerInfo failed for node: {peer.NodeId}. {t.Exception?.Message}");
                        }
                        else
                        {
                            _logger.Error($"InitPeerInfo failedf or node: {peer.NodeId}.", t.Exception);
                        }
                    }

                    SyncFailed?.Invoke(this, new SyncEventArgs(peer));
                }
                else if (t.IsCanceled)
                {
                    token.ThrowIfCancellationRequested();
                }
            }, token);

            if (_logger.IsDebugEnabled)
            {
                _logger.Info($"Received head block info from {peer.NodeId} with head block numer {getNumberTask.Result}");
            }

            bool addResult = _peers.TryAdd(peer.NodeId, new PeerInfo(peer, getNumberTask.Result)
            {
                NumberReceived = BlockTree.BestSuggested.Number
            });                                                                                                                                        // TODO: cheating now with assumign the consistency of the chains

            if (!addResult)
            {
                _logger.Error($"Adding {nameof(PeerInfo)} failed for {peer.NodeId}");
            }
        }
Esempio n. 4
0
        public async Task Does_not_do_full_sync_when_not_needed_with_split()
        {
            BlockTree            minerTree = Build.A.BlockTree(_genesisBlock).OfChainLength(6).TestObject;
            ISynchronizationPeer miner1    = new SynchronizationPeerMock(minerTree);

            ManualResetEvent resetEvent = new ManualResetEvent(false);

            _manager.SyncEvent += (sender, args) => { resetEvent.Set(); };

            Task addMiner1Task = _manager.AddPeer(miner1);

            await Task.WhenAll(addMiner1Task);

            resetEvent.WaitOne(TimeSpan.FromSeconds(1));

            Assert.AreEqual(minerTree.BestSuggested.Hash, _blockTree.BestSuggested.Hash, "client agrees with miner before split");

            Block newBlock = Build.A.Block.WithParent(minerTree.Head).TestObject;

            minerTree.SuggestBlock(newBlock);
            minerTree.MarkAsProcessed(newBlock.Hash);
            minerTree.MoveToMain(newBlock.Hash);

            ISynchronizationPeer miner2 = Substitute.For <ISynchronizationPeer>();

            miner2.GetHeadBlockNumber(Arg.Any <CancellationToken>()).Returns(miner1.GetHeadBlockNumber(Arg.Any <CancellationToken>()));
            miner2.GetHeadBlockHash(Arg.Any <CancellationToken>()).Returns(miner1.GetHeadBlockHash(default(CancellationToken)));
            miner2.NodeId.Returns(new NodeId(TestObject.PublicKeyB));

            Assert.AreEqual(newBlock.Number, await miner2.GetHeadBlockNumber(Arg.Any <CancellationToken>()), "number as expected");
            Assert.AreEqual(newBlock.Hash, await miner2.GetHeadBlockHash(default(CancellationToken)), "hash as expected");

            await _manager.AddPeer(miner2);

            await miner2.Received().GetBlockHeaders(6, 1, 0, default(CancellationToken));
        }