예제 #1
0
        public async Task CanGetTx()
        {
            Swarm swarmA = _swarms[0];
            Swarm swarmB = _swarms[1];

            BlockChain <BaseAction> chainA = _blockchains[0];
            BlockChain <BaseAction> chainB = _blockchains[1];

            Transaction <BaseAction> tx = Transaction <BaseAction> .Make(
                new PrivateKey(),
                new PrivateKey().PublicKey.ToAddress(),
                new BaseAction[] { },
                DateTimeOffset.UtcNow
                );

            chainB.StageTransactions(new[] { tx }.ToHashSet());
            chainB.MineBlock(_fx1.Address1);

            try
            {
                await StartAsync(swarmA, chainA);
                await StartAsync(swarmB, chainB);

                Assert.Throws <PeerNotFoundException>(
                    () => swarmB.GetTxsAsync <BaseAction>(
                        swarmA.AsPeer, new[] { tx.Id }));

                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer });

                List <Transaction <BaseAction> > txs =
                    await swarmA.GetTxsAsync <BaseAction>(
                        swarmB.AsPeer, new[] { tx.Id }
                        ).ToListAsync();

                Assert.Equal(new[] { tx }, txs);
            }
            finally
            {
                await Task.WhenAll(
                    swarmA.StopAsync(),
                    swarmB.StopAsync());
            }
        }
예제 #2
0
        public async Task InitialBlockDownloadStates()
        {
            Swarm <DumbAction> minerSwarm    = _swarms[0];
            Swarm <DumbAction> receiverSwarm = _swarms[1];

            BlockChain <DumbAction> minerChain    = _blockchains[0];
            BlockChain <DumbAction> receiverChain = _blockchains[1];

            var key     = new PrivateKey();
            var address = key.ToAddress();

            minerChain.MakeTransaction(key, new[] { new DumbAction(address, "foo") });
            await minerChain.MineBlock(_fx1.Address1);

            minerChain.MakeTransaction(key, new[] { new DumbAction(address, "bar") });
            await minerChain.MineBlock(_fx1.Address1);

            minerChain.MakeTransaction(key, new[] { new DumbAction(address, "baz") });
            await minerChain.MineBlock(_fx1.Address1);

            try
            {
                await StartAsync(minerSwarm);

                await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);

                var trustedStateValidators = new[] { minerSwarm.Address }.ToImmutableHashSet();

                await receiverSwarm.PreloadAsync(trustedStateValidators : trustedStateValidators);

                await receiverSwarm.PreloadAsync();

                var state = receiverChain.GetState(address);

                Assert.Equal((Text)"foo,bar,baz", state);
                Assert.Equal(minerChain.BlockHashes, receiverChain.BlockHashes);
            }
            finally
            {
                await StopAsync(minerSwarm);
            }
        }
예제 #3
0
        public async Task BroadcastIgnoreFromDifferentGenesisHash()
        {
            var receiverKey = new PrivateKey();
            Swarm <DumbAction>      receiverSwarm = CreateSwarm(receiverKey);
            BlockChain <DumbAction> receiverChain = receiverSwarm.BlockChain;
            var seedStateStore = new TrieStateStore(new MemoryKeyValueStore());
            IBlockPolicy <DumbAction> policy            = receiverChain.Policy;
            Block <DumbAction>        mismatchedGenesis = new BlockContent <DumbAction>
            {
                PublicKey = receiverKey.PublicKey,
                Timestamp = DateTimeOffset.MinValue,
            }
            .Mine(policy.GetHashAlgorithm(0))
            .Evaluate(receiverKey, policy.BlockAction, seedStateStore);
            BlockChain <DumbAction> seedChain = MakeBlockChain(
                policy,
                new MemoryStore(),
                seedStateStore,
                genesisBlock: mismatchedGenesis);
            var seedMiner = new PrivateKey();
            Swarm <DumbAction> seedSwarm = CreateSwarm(seedChain, seedMiner);

            try
            {
                await StartAsync(receiverSwarm);
                await StartAsync(seedSwarm);

                await receiverSwarm.AddPeersAsync(new[] { seedSwarm.AsPeer }, null);

                Block <DumbAction> block = await seedChain.MineBlock(seedMiner);

                seedSwarm.BroadcastBlock(block);
                Assert.NotEqual(seedChain.Tip, receiverChain.Tip);
            }
            finally
            {
                await StopAsync(seedSwarm);
                await StopAsync(receiverSwarm);

                seedSwarm.Dispose();
            }
        }
예제 #4
0
        public async Task ExchangeWithIceServer()
        {
            Uri    turnUrl  = FactOnlyTurnAvailable.TurnUri;
            string username = FactOnlyTurnAvailable.Username;
            string password = FactOnlyTurnAvailable.Password;

            IEnumerable <IceServer> iceServers = new[]
            {
                new IceServer(
                    urls: new[] { turnUrl },
                    username: username,
                    credential: password),
            };

            var seed   = new Swarm(new PrivateKey(), 1, host: "localhost");
            var swarmA = new Swarm(new PrivateKey(), 1, iceServers: iceServers);
            var swarmB = new Swarm(new PrivateKey(), 1, iceServers: iceServers);

            try
            {
                await StartAsync(seed, _blockchains[0]);
                await StartAsync(swarmA, _blockchains[1]);
                await StartAsync(swarmB, _blockchains[2]);

                await swarmA.AddPeersAsync(new[] { seed.AsPeer });

                await swarmB.AddPeersAsync(new[] { seed.AsPeer });

                await EnsureExchange(swarmA, swarmB);

                Assert.Contains(swarmA.AsPeer, swarmB);
                Assert.Contains(swarmB.AsPeer, swarmA);
            }
            finally
            {
                await Task.WhenAll(
                    seed.StopAsync(),
                    swarmA.StopAsync(),
                    swarmB.StopAsync());
            }
        }
예제 #5
0
        public async Task HandleDifferentAppProtocolVersion()
        {
            var isCalled = false;

            void GameHandler(object sender, DifferentProtocolVersionEventArgs e)
            {
                isCalled = true;
            }

            BlockChain <DumbAction> chain = _blockchains[0];

            var a = new Swarm <DumbAction>(
                chain,
                new PrivateKey(),
                host: IPAddress.Loopback.ToString(),
                appProtocolVersion: 2,
                differentVersionPeerEncountered: GameHandler);
            var b = new Swarm <DumbAction>(
                chain,
                new PrivateKey(),
                host: IPAddress.Loopback.ToString(),
                appProtocolVersion: 3);

            try
            {
                await StartAsync(a);
                await StartAsync(b);

                await a.AddPeersAsync(new[] { b.AsPeer });

                Assert.True(isCalled);
            }
            finally
            {
                await a.StopAsync();

                await b.StopAsync();
            }
        }
        private async Task CheckStaticPeersAsync(
            IEnumerable <Peer> peers,
            CancellationToken cancellationToken)
        {
            var peerArray = peers as Peer[] ?? peers.ToArray();

            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken);

                    Log.Warning("Checking static peers. {Peers}", peerArray);
                    var peersToAdd = peerArray.Where(peer => !Swarm.Peers.Contains(peer)).ToArray();
                    if (peersToAdd.Any())
                    {
                        Log.Warning("Some of peers are not in routing table. {Peers}", peersToAdd);
                        await Swarm.AddPeersAsync(
                            peersToAdd,
                            TimeSpan.FromSeconds(5),
                            cancellationToken);
                    }
                }
                catch (OperationCanceledException e)
                {
                    Log.Warning(e, $"{nameof(CheckStaticPeersAsync)}() is cancelled.");
                    throw;
                }
                catch (Exception e)
                {
                    var msg = "Unexpected exception occurred during " +
                              $"{nameof(CheckStaticPeersAsync)}(): {{0}}";
                    Log.Warning(e, msg, e);
                }
            }
        }
예제 #7
0
        public async Task TxStagedNotToBroadcast()
        {
            Swarm <DumbAction> swarmA = _swarms[0];
            Swarm <DumbAction> swarmB = _swarms[1];

            BlockChain <DumbAction> chainA = _blockchains[0];
            BlockChain <DumbAction> chainB = _blockchains[1];

            Transaction <DumbAction> txA = chainA.MakeTransaction(
                new PrivateKey(),
                new DumbAction[] { },
                broadcast: true);
            Transaction <DumbAction> txB = chainA.MakeTransaction(
                new PrivateKey(),
                new DumbAction[] { },
                broadcast: false);

            try
            {
                await StartAsync(swarmA);
                await StartAsync(swarmB);

                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer });

                await swarmB.TxReceived.WaitAsync();

                Assert.Equal(txA, chainB.Transactions[txA.Id]);
                Assert.False(chainB.Transactions.ContainsKey(txB.Id));
            }
            finally
            {
                await Task.WhenAll(
                    swarmA.StopAsync(),
                    swarmB.StopAsync());
            }
        }
예제 #8
0
        public async Task StopGracefullyWhileStarting()
        {
            Swarm <DumbAction> a = _swarms[0];
            Swarm <DumbAction> b = _swarms[1];

            await StartAsync(b);

            await a.AddPeersAsync(new[] { b.AsPeer });

            Task t = await StartAsync(a);

            bool canceled = false;

            try
            {
                await Task.WhenAll(a.StopAsync(), t);
            }
            catch (OperationCanceledException)
            {
                canceled = true;
            }

            Assert.True(canceled);
        }
예제 #9
0
        public async Task CanGetBlock()
        {
            Swarm swarmA = _swarms[0];
            Swarm swarmB = _swarms[1];

            BlockChain <BaseAction> chainA = _blockchains[0];
            BlockChain <BaseAction> chainB = _blockchains[1];

            Block <BaseAction> genesis = chainA.MineBlock(_fx1.Address1);

            chainB.Append(genesis); // chainA and chainB shares genesis block.
            Block <BaseAction> block1 = chainA.MineBlock(_fx1.Address1);
            Block <BaseAction> block2 = chainA.MineBlock(_fx1.Address1);

            try
            {
                await StartAsync(swarmA, chainA);
                await StartAsync(swarmB, chainA);

                await Assert.ThrowsAsync <PeerNotFoundException>(
                    async() => await swarmB.GetBlockHashesAsync(
                        swarmA.AsPeer,
                        new BlockLocator(new[] { genesis.Hash }),
                        null));

                await swarmB.AddPeersAsync(new[] { swarmA.AsPeer });

                IEnumerable <HashDigest <SHA256> > inventories1 =
                    await swarmB.GetBlockHashesAsync(
                        swarmA.AsPeer,
                        new BlockLocator(new[] { genesis.Hash }),
                        null);

                Assert.Equal(
                    new[] { genesis.Hash, block1.Hash, block2.Hash },
                    inventories1);

                IEnumerable <HashDigest <SHA256> > inventories2 =
                    await swarmB.GetBlockHashesAsync(
                        swarmA.AsPeer,
                        new BlockLocator(new[] { genesis.Hash }),
                        block1.Hash);

                Assert.Equal(
                    new[] { genesis.Hash, block1.Hash },
                    inventories2);

                List <Block <BaseAction> > receivedBlocks =
                    await swarmB.GetBlocksAsync <BaseAction>(
                        swarmA.AsPeer, inventories1
                        ).ToListAsync();

                Assert.Equal(
                    new[] { genesis, block1, block2 },
                    receivedBlocks);
            }
            finally
            {
                await Task.WhenAll(
                    swarmA.StopAsync(),
                    swarmB.StopAsync());
            }
        }
예제 #10
0
        public async Task CanBroadcastWhlieMining()
        {
            Swarm a = _swarms[0];
            Swarm b = _swarms[1];

            BlockChain <BaseAction> chainA = _blockchains[0];
            BlockChain <BaseAction> chainB = _blockchains[1];

            Task CreateMiner(
                Swarm swarm,
                BlockChain <BaseAction> chain,
                int delay,
                CancellationToken cancellationToken
                )
            {
                return(Task.Run(async() =>
                {
                    while (!cancellationToken.IsCancellationRequested)
                    {
                        var block = chain.MineBlock(_fx1.Address1);
                        Log.Debug(
                            $"Block mined. " +
                            $"[Swarm: {swarm.Address}, Block: {block.Hash}]");
                        await swarm.BroadcastBlocksAsync(new[] { block });
                        await Task.Delay(delay);
                    }

                    await swarm.BroadcastBlocksAsync(new[] { chain.Last() });
                    Log.Debug("Mining complete.");
                }));
            }

            var  minerCanceller = new CancellationTokenSource();
            Task miningA        = CreateMiner(a, chainA, 5000, minerCanceller.Token);
            Task miningB        = CreateMiner(b, chainB, 8000, minerCanceller.Token);

            try
            {
                await StartAsync(a, chainA);
                await StartAsync(b, chainB);

                await b.AddPeersAsync(new[] { a.AsPeer });
                await EnsureExchange(a, b);

                await Task.Delay(10000);

                minerCanceller.Cancel();

                await Task.WhenAll(miningA, miningB);

                await Task.Delay(5000);
            }
            finally
            {
                await a.StopAsync();

                await b.StopAsync();
            }

            Log.Debug($"chainA: {string.Join(",", chainA)}");
            Log.Debug($"chainB: {string.Join(",", chainB)}");

            Assert.Subset(
                chainA.AsEnumerable().ToHashSet(),
                chainB.AsEnumerable().ToHashSet());
        }
예제 #11
0
        public async Task WorksAsExpected()
        {
            Swarm a = _swarms[0];
            Swarm b = _swarms[1];
            Swarm c = _swarms[2];

            Blockchain <BaseAction> chain = _blockchains[0];

            DateTime lastDistA;
            Peer     aAsPeer;

            try
            {
                await b.InitContextAsync();

                await c.InitContextAsync();

                try
                {
                    await a.InitContextAsync();

                    var at = Task.Run(async() => await a.RunAsync(chain, 250));
                    await b.AddPeersAsync(new[] { a.AsPeer });

                    var bt = Task.Run(async() => await b.RunAsync(chain, 250));
                    await EnsureExchange(a, b);

                    Assert.Equal(new[] { b.AsPeer }.ToImmutableHashSet(), a.ToImmutableHashSet());
                    Assert.Equal(new[] { a.AsPeer }.ToImmutableHashSet(), b.ToImmutableHashSet());

                    await c.AddPeersAsync(new[] { a.AsPeer });

                    var ct = Task.Run(async() => await c.RunAsync(chain, 250));
                    await EnsureExchange(a, c);
                    await EnsureExchange(a, b);

                    Assert.Equal(new[] { b.AsPeer, c.AsPeer }.ToImmutableHashSet(), a.ToImmutableHashSet());
                    Assert.Equal(new[] { a.AsPeer, c.AsPeer }.ToImmutableHashSet(), b.ToImmutableHashSet());
                    Assert.Equal(new[] { a.AsPeer, b.AsPeer }.ToImmutableHashSet(), c.ToImmutableHashSet());

                    lastDistA = a.LastDistributed;
                    aAsPeer   = a.AsPeer;
                }
                finally
                {
                    await a.DisposeAsync();
                }

                Assert.True(lastDistA < a.LastDistributed);

                await EnsureRecvAsync(b, aAsPeer, a.LastDistributed);
                await EnsureRecvAsync(c, aAsPeer, a.LastDistributed);
                await EnsureExchange(b, c);

                Assert.Equal(new[] { c.AsPeer }.ToImmutableHashSet(), b.ToImmutableHashSet());
                Assert.Equal(new[] { b.AsPeer }.ToImmutableHashSet(), c.ToImmutableHashSet());
            }
            finally
            {
                await b.DisposeAsync();

                await c.DisposeAsync();
            }
        }
예제 #12
0
        public async Task BroadcastWhileMining()
        {
            var minerA           = new PrivateKey();
            var minerB           = new PrivateKey();
            Swarm <DumbAction> a = CreateSwarm(minerA);
            Swarm <DumbAction> b = CreateSwarm(minerB);

            BlockChain <DumbAction> chainA = a.BlockChain;
            BlockChain <DumbAction> chainB = b.BlockChain;

            Task CreateMiner(
                PrivateKey miner,
                Swarm <DumbAction> swarm,
                BlockChain <DumbAction> chain,
                int delay,
                CancellationToken cancellationToken
                )
            {
                return(Task.Run(async() =>
                {
                    while (!cancellationToken.IsCancellationRequested)
                    {
                        try
                        {
                            var block = await chain.MineBlock(miner);

                            Log.Debug(
                                "Block mined. [Node: {0}, Block: {1}]",
                                swarm.Address,
                                block.Hash);
                            swarm.BroadcastBlock(block);
                        }
                        catch (OperationCanceledException)
                        {
                            continue;
                        }
                        finally
                        {
                            await Task.Delay(delay);
                        }
                    }

                    swarm.BroadcastBlock(chain[-1]);
                    Log.Debug("Mining complete.");
                }));
            }

            try
            {
                await StartAsync(a);
                await StartAsync(b);

                await a.AddPeersAsync(new[] { b.AsPeer }, null);

                var  minerCanceller = new CancellationTokenSource();
                Task miningA        = CreateMiner(minerA, a, chainA, 5000, minerCanceller.Token);
                Task miningB        = CreateMiner(minerB, b, chainB, 8000, minerCanceller.Token);

                await Task.Delay(10000);

                minerCanceller.Cancel();

                await Task.WhenAll(miningA, miningB);

                await Task.Delay(5000);
            }
            finally
            {
                await StopAsync(a);
                await StopAsync(b);
            }

            _logger.CompareBothChains(LogEventLevel.Debug, "A", chainA, "B", chainB);
            Assert.Equal(chainA.BlockHashes, chainB.BlockHashes);
        }
예제 #13
0
        public async Task PreloadFromNominer()
        {
            Swarm <DumbAction> minerSwarm    = _swarms[0];
            Swarm <DumbAction> receiverSwarm = _swarms[1];
            var fxForNominers = new StoreFixture[2];

            fxForNominers[0] = new DefaultStoreFixture(memory: true);
            fxForNominers[1] = new DefaultStoreFixture(memory: true);
            var policy = new BlockPolicy <DumbAction>();
            var blockChainsForNominers = new[]
            {
                TestUtils.MakeBlockChain(policy, fxForNominers[0].Store),
                TestUtils.MakeBlockChain(policy, fxForNominers[1].Store),
            };
            var nominerSwarm0 = CreateSwarm(blockChainsForNominers[0]);
            var nominerSwarm1 = CreateSwarm(blockChainsForNominers[1]);

            BlockChain <DumbAction> minerChain    = _blockchains[0];
            BlockChain <DumbAction> receiverChain = _blockchains[1];

            foreach (int i in Enumerable.Range(0, 10))
            {
                await minerChain.MineBlock(_fx1.Address1);
            }

            var actualStates = new List <PreloadState>();
            var progress     = new Progress <PreloadState>(state =>
            {
                lock (actualStates)
                {
                    actualStates.Add(state);
                }
            });

            try
            {
                await StartAsync(minerSwarm);
                await StartAsync(nominerSwarm0);
                await StartAsync(nominerSwarm1);

                minerSwarm.FindNextHashesChunkSize    = 2;
                nominerSwarm0.FindNextHashesChunkSize = 2;
                nominerSwarm1.FindNextHashesChunkSize = 2;

                await nominerSwarm0.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);

                await nominerSwarm0.PreloadAsync();

                await nominerSwarm1.AddPeersAsync(new[] { nominerSwarm0.AsPeer }, null);

                await nominerSwarm1.PreloadAsync();

                await receiverSwarm.AddPeersAsync(new[] { nominerSwarm1.AsPeer }, null);

                await receiverSwarm.PreloadAsync(TimeSpan.FromSeconds(15), progress);

                // Await 1 second to make sure all progresses is reported.
                await Task.Delay(1000);

                Assert.Equal(minerChain.BlockHashes, receiverChain.BlockHashes);

                var expectedStates = new List <PreloadState>();

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var state = new BlockHashDownloadState
                    {
                        EstimatedTotalBlockHashCount = 10,
                        ReceivedBlockHashCount       = i,
                        SourcePeer = nominerSwarm1.AsPeer as BoundPeer,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var state = new BlockDownloadState
                    {
                        ReceivedBlockHash  = minerChain[i].Hash,
                        TotalBlockCount    = 10,
                        ReceivedBlockCount = i,
                        SourcePeer         = nominerSwarm1.AsPeer as BoundPeer,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var state = new BlockVerificationState
                    {
                        VerifiedBlockHash  = minerChain[i].Hash,
                        TotalBlockCount    = 10,
                        VerifiedBlockCount = i,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var state = new ActionExecutionState
                    {
                        ExecutedBlockHash  = minerChain[i].Hash,
                        TotalBlockCount    = 10,
                        ExecutedBlockCount = i,
                    };
                    expectedStates.Add(state);
                }

                // FIXME: this test does not ensures block download in order
                Assert.Equal(
                    expectedStates.ToHashSet(),
                    actualStates.ToHashSet()
                    );
            }
            finally
            {
                await StopAsync(minerSwarm);
                await StopAsync(nominerSwarm0);
                await StopAsync(nominerSwarm1);
                await StopAsync(receiverSwarm);

                nominerSwarm0.Dispose();
                nominerSwarm1.Dispose();

                fxForNominers[0].Dispose();
                fxForNominers[1].Dispose();
            }
        }
예제 #14
0
        public async Task Preload()
        {
            Swarm <DumbAction> minerSwarm    = _swarms[0];
            Swarm <DumbAction> receiverSwarm = _swarms[1];

            BlockChain <DumbAction> minerChain    = _blockchains[0];
            BlockChain <DumbAction> receiverChain = _blockchains[1];

            var blocks = new List <Block <DumbAction> >();

            foreach (int i in Enumerable.Range(0, 11))
            {
                blocks.Add(TestUtils.MineNext(
                               previousBlock: i == 0 ? minerChain.Genesis : blocks[i - 1],
                               difficulty: 1024));
                if (i != 10)
                {
                    minerChain.Append(blocks[i]);
                }
            }

            var actualStates = new List <PreloadState>();
            var progress     = new Progress <PreloadState>(state =>
            {
                _logger.Information("Received a progress event: {@State}", state);
                lock (actualStates)
                {
                    actualStates.Add(state);

                    if (actualStates.Count == 9)
                    {
                        minerChain.Append(blocks[10]);
                    }
                }
            });

            try
            {
                await StartAsync(minerSwarm);

                await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);

                _logger.Verbose("Both chains before synchronization:");
                _logger.CompareBothChains(
                    LogEventLevel.Verbose,
                    "Miner chain",
                    minerChain,
                    "Receiver chain",
                    receiverChain
                    );

                minerSwarm.FindNextHashesChunkSize = 2;
                await receiverSwarm.PreloadAsync(TimeSpan.FromSeconds(15), progress);

                // Await 1 second to make sure all progresses is reported.
                await Task.Delay(1000);

                _logger.Verbose(
                    $"Both chains after synchronization ({nameof(receiverSwarm.PreloadAsync)}):"
                    );
                _logger.CompareBothChains(
                    LogEventLevel.Verbose,
                    "Miner chain",
                    minerChain,
                    "Receiver chain",
                    receiverChain
                    );
                Assert.Equal(minerChain.BlockHashes, receiverChain.BlockHashes);

                var expectedStates = new List <PreloadState>();

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var b     = minerChain[i];
                    var state = new BlockHashDownloadState
                    {
                        EstimatedTotalBlockHashCount = 10,
                        ReceivedBlockHashCount       = 1,
                        SourcePeer = minerSwarm.AsPeer as BoundPeer,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var b     = minerChain[i];
                    var state = new BlockDownloadState
                    {
                        ReceivedBlockHash  = b.Hash,
                        TotalBlockCount    = i == 9 || i == 10 ? 11 : 10,
                        ReceivedBlockCount = i,
                        SourcePeer         = minerSwarm.AsPeer as BoundPeer,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var b     = minerChain[i];
                    var state = new BlockVerificationState
                    {
                        VerifiedBlockHash  = b.Hash,
                        TotalBlockCount    = i == 9 || i == 10 ? 11 : 10,
                        VerifiedBlockCount = i,
                    };
                    expectedStates.Add(state);
                }

                for (var i = 1; i < minerChain.Count; i++)
                {
                    var b     = minerChain[i];
                    var state = new ActionExecutionState
                    {
                        ExecutedBlockHash  = b.Hash,
                        TotalBlockCount    = 11,
                        ExecutedBlockCount = i,
                    };
                    expectedStates.Add(state);
                }

                _logger.Debug("Expected preload states: {@expectedStates}", expectedStates);
                _logger.Debug("Actual preload states: {@actualStates}", actualStates);

                Assert.Equal(expectedStates.Count, actualStates.Count);
                foreach (var states in expectedStates.Zip(actualStates, ValueTuple.Create))
                {
                    Assert.Equal(states.Item1, states.Item2);
                }
            }
            finally
            {
                await StopAsync(minerSwarm);
                await StopAsync(receiverSwarm);
            }
        }
예제 #15
0
        public async Task BroadcastBlockToReconnectedPeer()
        {
            var miner      = new PrivateKey();
            var policy     = new NullBlockPolicy <DumbAction>();
            var fx         = new MemoryStoreFixture(policy.BlockAction);
            var minerChain = MakeBlockChain(policy, fx.Store, fx.StateStore);

            foreach (int i in Enumerable.Range(0, 10))
            {
                await minerChain.MineBlock(miner);
            }

            Swarm <DumbAction> seed = CreateSwarm(
                miner,
                policy: policy,
                genesis: minerChain.Genesis
                );
            BlockChain <DumbAction> seedChain = seed.BlockChain;

            var privateKey            = new PrivateKey();
            Swarm <DumbAction> swarmA = CreateSwarm(
                privateKey: privateKey,
                policy: policy,
                genesis: minerChain.Genesis
                );
            Swarm <DumbAction> swarmB = CreateSwarm(
                privateKey: privateKey,
                policy: policy,
                genesis: minerChain.Genesis
                );

            foreach (BlockHash blockHash in minerChain.BlockHashes.Skip(1).Take(4))
            {
                seedChain.Append(minerChain[blockHash]);
            }

            try
            {
                await StartAsync(seed);
                await StartAsync(swarmA);
                await StartAsync(swarmB);

                Assert.Equal(swarmA.AsPeer, swarmB.AsPeer);

                await swarmA.AddPeersAsync(new[] { seed.AsPeer }, null);
                await StopAsync(swarmA);

                await seed.PeerDiscovery.RefreshTableAsync(
                    TimeSpan.Zero,
                    default(CancellationToken));

                Assert.DoesNotContain(swarmA.AsPeer, seed.Peers);

                foreach (BlockHash blockHash in minerChain.BlockHashes.Skip(5))
                {
                    seedChain.Append(minerChain[blockHash]);
                }

                await swarmB.AddPeersAsync(new[] { seed.AsPeer }, null);

                // This is added for context switching.
                await Task.Delay(100);

                Assert.Contains(swarmB.AsPeer, seed.Peers);
                Assert.Contains(seed.AsPeer, swarmB.Peers);

                seed.BroadcastBlock(seedChain.Tip);

                await swarmB.BlockAppended.WaitAsync();

                Assert.NotEqual(seedChain.BlockHashes, swarmA.BlockChain.BlockHashes);
                Assert.Equal(seedChain.BlockHashes, swarmB.BlockChain.BlockHashes);
            }
            finally
            {
                await StopAsync(seed);
                await StopAsync(swarmA);
                await StopAsync(swarmB);

                seed.Dispose();
                swarmA.Dispose();
                swarmB.Dispose();
            }
        }
예제 #16
0
        public async Task CanExchangePeer()
        {
            BlockChain <DumbAction> chain = _blockchains[0];

            var a = new Swarm <DumbAction>(
                chain,
                new PrivateKey(),
                1,
                host: IPAddress.Loopback.ToString());
            var b = new Swarm <DumbAction>(
                chain,
                new PrivateKey(),
                1,
                host: IPAddress.Loopback.ToString());
            var c = new Swarm <DumbAction>(
                chain,
                new PrivateKey(),
                1,
                host: IPAddress.Loopback.ToString());

            DateTimeOffset lastDistA;
            Peer           aAsPeer;

            try
            {
                try
                {
                    await StartAsync(a);
                    await StartAsync(b);
                    await StartAsync(c);

                    await b.AddPeersAsync(new[] { a.AsPeer });
                    await EnsureExchange(a, b);

                    Assert.Equal(
                        new[] { b.AsPeer }.ToImmutableHashSet(),
                        a.Peers.ToImmutableHashSet());
                    Assert.Equal(
                        new[] { a.AsPeer }.ToImmutableHashSet(),
                        b.Peers.ToImmutableHashSet());

                    await c.AddPeersAsync(new[] { a.AsPeer });
                    await EnsureExchange(a, c);
                    await EnsureExchange(a, b);

                    Assert.Equal(
                        new[] { b.AsPeer, c.AsPeer }.ToImmutableHashSet(),
                        a.Peers.ToImmutableHashSet()
                        );
                    Assert.Equal(
                        new[] { a.AsPeer, c.AsPeer }.ToImmutableHashSet(),
                        b.Peers.ToImmutableHashSet()
                        );
                    Assert.Equal(
                        new[] { a.AsPeer, b.AsPeer }.ToImmutableHashSet(),
                        c.Peers.ToImmutableHashSet()
                        );

                    lastDistA = a.LastDistributed;
                    aAsPeer   = a.AsPeer;
                }
                finally
                {
                    await a.StopAsync();
                }

                Assert.True(lastDistA < a.LastDistributed);

                await EnsureRecvAsync(b, aAsPeer, a.LastDistributed);
                await EnsureRecvAsync(c, aAsPeer, a.LastDistributed);
                await EnsureExchange(b, c);

                Assert.Equal(new[] { c.AsPeer }.ToImmutableHashSet(), b.Peers.ToImmutableHashSet());
                Assert.Equal(new[] { b.AsPeer }.ToImmutableHashSet(), c.Peers.ToImmutableHashSet());
            }
            finally
            {
                await b.StopAsync();

                await c.StopAsync();
            }
        }
예제 #17
0
        public async Task Preload()
        {
            Swarm <DumbAction> minerSwarm    = _swarms[0];
            Swarm <DumbAction> receiverSwarm = _swarms[1];

            BlockChain <DumbAction> minerChain    = _blockchains[0];
            BlockChain <DumbAction> receiverChain = _blockchains[1];

            foreach (int i in Enumerable.Range(0, 10))
            {
                minerChain.MineBlock(_fx1.Address1);
            }

            var actualStates = new List <PreloadState>();
            var progress     = new Progress <PreloadState>(state =>
            {
                lock (actualStates)
                {
                    actualStates.Add(state);

                    if (actualStates.Count == 8)
                    {
                        minerChain.MineBlock(_fx1.Address1);
                    }
                }
            });

            try
            {
                await StartAsync(minerSwarm);

                await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer });

                minerChain.FindNextHashesChunkSize = 2;
                await receiverSwarm.PreloadAsync(progress);

                Assert.Equal(minerChain.AsEnumerable(), receiverChain.AsEnumerable());

                PreloadState[] expectedStates = minerChain.Select((b, i) =>
                {
                    return(new BlockDownloadState
                    {
                        ReceivedBlockHash = b.Hash,
                        TotalBlockCount = 10,
                        ReceivedBlockCount = i + 1,
                    });
                }).ToArray();
                (expectedStates[10] as BlockDownloadState).TotalBlockCount = 11;

                expectedStates = expectedStates.Concat(minerChain.Select(
                                                           (b, i) => new ActionExecutionState()
                {
                    ExecutedBlockHash  = b.Hash,
                    TotalBlockCount    = 11,
                    ExecutedBlockCount = i + 1,
                })).ToArray();

                Assert.True(expectedStates.ToImmutableHashSet()
                            .SetEquals(actualStates.ToImmutableHashSet()));
            }
            finally
            {
                await Task.WhenAll(
                    minerSwarm.StopAsync(),
                    receiverSwarm.StopAsync());
            }
        }
예제 #18
0
        public async Task PreloadAsyncCancellation(int cancelAfter)
        {
            Swarm <DumbAction> minerSwarm    = CreateSwarm();
            Swarm <DumbAction> receiverSwarm = CreateSwarm();

            Log.Logger.Information("Miner:    {0}", minerSwarm.Address);
            Log.Logger.Information("Receiver: {0}", receiverSwarm.Address);

            BlockChain <DumbAction> minerChain    = minerSwarm.BlockChain;
            BlockChain <DumbAction> receiverChain = receiverSwarm.BlockChain;

            Guid receiverChainId = receiverChain.Id;

            (Address address, IEnumerable <Block <DumbAction> > blocks) =
                await MakeFixtureBlocksForPreloadAsyncCancellationTest();

            var blockArray = blocks.ToArray();

            foreach (Block <DumbAction> block in blockArray)
            {
                minerChain.Append(block);
            }

            receiverChain.Append(blockArray[0]);

            Assert.NotNull(minerChain.Tip);

            minerSwarm.FindNextHashesChunkSize = 2;
            await StartAsync(minerSwarm);

            await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }, null);

            CancellationTokenSource cts = new CancellationTokenSource();

            cts.CancelAfter(cancelAfter);
            bool canceled = true;

            try
            {
                await receiverSwarm.PreloadAsync(cancellationToken : cts.Token);

                canceled = false;
                Log.Logger.Debug($"{nameof(receiverSwarm.PreloadAsync)}() normally finished.");
            }
            catch (OperationCanceledException)
            {
                Log.Logger.Debug($"{nameof(receiverSwarm.PreloadAsync)}() aborted.");
            }
            catch (AggregateException ae) when(ae.InnerException is TaskCanceledException)
            {
                Log.Logger.Debug($"{nameof(receiverSwarm.PreloadAsync)}() aborted.");
            }

            cts.Dispose();

            Assert.InRange(receiverChain.Store.ListChainIds().Count(), 0, 1);

            if (canceled)
            {
                Assert.Equal(receiverChainId, receiverChain.Id);
                Assert.Equal(
                    (blockArray[0].Index, blockArray[0].Hash),
                    (receiverChain.Tip.Index, receiverChain.Tip.Hash)
                    );
                Assert.Equal(blockArray[0], receiverChain.Tip);
                Assert.Equal(
                    (Text)string.Join(",", Enumerable.Range(0, 5).Select(j => $"Item0.{j}")),
                    receiverChain.GetState(address)
                    );
            }
            else
            {
                Assert.NotEqual(receiverChainId, receiverChain.Id);
                Assert.Equal(minerChain.Tip, receiverChain.Tip);
                Assert.Equal(
                    (Text)string.Join(
                        ",",
                        Enumerable.Range(0, 20).Select(i =>
                                                       string.Join(",", Enumerable.Range(0, 5).Select(j => $"Item{i}.{j}"))
                                                       )
                        ),
                    receiverChain.GetState(address)
                    );
            }
        }
예제 #19
0
        public async Task CanBroadcastBlock()
        {
            Swarm swarmA = _swarms[0];
            Swarm swarmB = _swarms[1];
            Swarm swarmC = _swarms[2];

            BlockChain <BaseAction> chainA = _blockchains[0];
            BlockChain <BaseAction> chainB = _blockchains[1];
            BlockChain <BaseAction> chainC = _blockchains[2];

            // chainA, chainB and chainC shares genesis block.
            Block <BaseAction> genesis = chainA.MineBlock(_fx1.Address1);

            chainB.Append(genesis);
            chainC.Append(genesis);

            foreach (int i in Enumerable.Range(0, 10))
            {
                chainA.MineBlock(_fx1.Address1);
                await Task.Delay(100);
            }

            foreach (int i in Enumerable.Range(0, 3))
            {
                chainB.MineBlock(_fx2.Address1);
                await Task.Delay(100);
            }

            try
            {
                await StartAsync(swarmA, chainA);
                await StartAsync(swarmB, chainB);
                await StartAsync(swarmC, chainC);

                await swarmA.AddPeersAsync(new[] { swarmB.AsPeer });

                await swarmA.AddPeersAsync(new[] { swarmC.AsPeer });

                await EnsureExchange(swarmA, swarmB);
                await EnsureExchange(swarmA, swarmC);
                await EnsureExchange(swarmB, swarmC);

                await swarmB.BroadcastBlocksAsync(new[] { chainB.Last() });

                await swarmC.BlockReceived.WaitAsync();

                await swarmA.BlockReceived.WaitAsync();

                Assert.Equal(chainB.AsEnumerable(), chainC);

                // chainB doesn't applied to chainA since chainB is shorter
                // than chainA
                Assert.NotEqual(chainB.AsEnumerable(), chainA);

                await swarmA.BroadcastBlocksAsync(new[] { chainA.Last() });

                await swarmB.BlockReceived.WaitAsync();

                await swarmC.BlockReceived.WaitAsync();

                Assert.Equal(chainA.AsEnumerable(), chainB);
                Assert.Equal(chainA.AsEnumerable(), chainC);
            }
            finally
            {
                await Task.WhenAll(
                    swarmA.StopAsync(),
                    swarmB.StopAsync(),
                    swarmC.StopAsync());
            }
        }
예제 #20
0
        public async Task GetMultipleBlocksAtOnce()
        {
            var privateKey = new PrivateKey();

            BlockChain <DumbAction> chainA = _blockchains[0];
            BlockChain <DumbAction> chainB = _blockchains[1];

            Swarm <DumbAction> swarmA = _swarms[0];
            Swarm <DumbAction> swarmB = new Swarm <DumbAction>(
                chainB,
                privateKey,
                1,
                host: IPAddress.Loopback.ToString());

            Block <DumbAction> genesis = chainA.MineBlock(_fx1.Address1);

            chainB.Append(genesis); // chainA and chainB shares genesis block.
            chainA.MineBlock(_fx1.Address1);
            chainA.MineBlock(_fx1.Address1);

            try
            {
                await StartAsync(swarmA);
                await StartAsync(swarmB);

                var peer = swarmA.AsPeer;

                await swarmB.AddPeersAsync(new[] { peer });

                IEnumerable <HashDigest <SHA256> > hashes =
                    await swarmB.GetBlockHashesAsync(
                        peer,
                        new BlockLocator(new[] { genesis.Hash }),
                        null);

                var netMQAddress = $"tcp://{peer.EndPoint.Host}:{peer.EndPoint.Port}";
                using (var socket = new DealerSocket(netMQAddress))
                {
                    var request = new GetBlocks(hashes, 2);
                    await socket.SendMultipartMessageAsync(
                        request.ToNetMQMessage(privateKey));

                    NetMQMessage response = await socket.ReceiveMultipartMessageAsync();

                    Message parsedMessage = Message.Parse(response, true);
                    Libplanet.Net.Messages.Blocks blockMessage =
                        (Libplanet.Net.Messages.Blocks)parsedMessage;

                    Assert.Equal(2, blockMessage.Payloads.Count);

                    response = await socket.ReceiveMultipartMessageAsync();

                    parsedMessage = Message.Parse(response, true);
                    blockMessage  = (Libplanet.Net.Messages.Blocks)parsedMessage;

                    Assert.Single(blockMessage.Payloads);
                }
            }
            finally
            {
                await Task.WhenAll(
                    swarmA.StopAsync(),
                    swarmB.StopAsync());
            }
        }