public async Task PullBlocksByDifficulty()
        {
            var policy = new BlockPolicy <DumbAction>(new MinerReward(1));
            var chain1 = MakeBlockChain(
                policy,
                new MemoryStore(),
                new TrieStateStore(new MemoryKeyValueStore()));
            var chain2 = MakeBlockChain(
                policy,
                new MemoryStore(),
                new TrieStateStore(new MemoryKeyValueStore()));

            var key1 = new PrivateKey();
            var key2 = new PrivateKey();

            var miner1 = CreateSwarm(chain1, key1);
            var miner2 = CreateSwarm(chain2, key2);

            await chain1.MineBlock(key1);

            await chain1.MineBlock(key2);

            long nextDifficulty =
                (long)chain1.Tip.TotalDifficulty + policy.GetNextBlockDifficulty(chain2);
            Block <DumbAction> block = MineNext(
                chain2.Tip,
                policy.GetHashAlgorithm,
                miner: ChainPrivateKey.PublicKey,
                difficulty: nextDifficulty,
                blockInterval: TimeSpan.FromMilliseconds(1)
                ).Evaluate(ChainPrivateKey, chain2);

            chain2.Append(block);

            Assert.True(chain1.Tip.Index > chain2.Tip.Index);
            Assert.True(chain1.Tip.TotalDifficulty < chain2.Tip.TotalDifficulty);

            try
            {
                await StartAsync(miner1);
                await StartAsync(miner2);

                await BootstrapAsync(miner2, miner1.AsPeer);

                await miner1.PullBlocksAsync(TimeSpan.FromSeconds(5), int.MaxValue, default);

                await miner1.BlockAppended.WaitAsync();

                Assert.Equal(miner2.BlockChain.Count, miner1.BlockChain.Count);
                Assert.Equal(miner2.BlockChain.Tip, miner1.BlockChain.Tip);
            }
            finally
            {
                await StopAsync(miner1);
                await StopAsync(miner2);

                miner1.Dispose();
                miner2.Dispose();
            }
        }
        public async Task PreloadWithFailedActions()
        {
            var policy        = new BlockPolicy <ThrowException>();
            var fx1           = new DefaultStoreFixture(memory: true);
            var fx2           = new DefaultStoreFixture(memory: true);
            var minerChain    = TestUtils.MakeBlockChain(policy, fx1.Store, fx1.StateStore);
            var receiverChain = TestUtils.MakeBlockChain(policy, fx2.Store, fx2.StateStore);

            var minerKey = new PrivateKey();

            Swarm <ThrowException> minerSwarm    = CreateSwarm(minerChain, minerKey);
            Swarm <ThrowException> receiverSwarm = CreateSwarm(receiverChain);

            foreach (var unused in Enumerable.Range(0, 10))
            {
                await minerSwarm.BlockChain.MineBlock(minerKey);
            }

            try
            {
                await StartAsync(minerSwarm);

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

                await receiverSwarm.PreloadAsync(TimeSpan.FromSeconds(1));

                var action = new ThrowException {
                    ThrowOnExecution = true
                };

                var chainId = receiverChain.Id;
                Transaction <ThrowException> tx = Transaction <ThrowException> .Create(
                    0,
                    new PrivateKey(),
                    minerSwarm.BlockChain.Genesis.Hash,
                    new[] { action },
                    ImmutableHashSet <Address> .Empty,
                    DateTimeOffset.UtcNow
                    );

                Block <ThrowException> block = TestUtils.MineNext(
                    minerChain.Tip,
                    minerChain.Policy.GetHashAlgorithm,
                    new[] { tx },
                    miner: TestUtils.ChainPrivateKey.PublicKey,
                    difficulty: policy.GetNextBlockDifficulty(minerChain),
                    blockInterval: TimeSpan.FromSeconds(1)
                    ).Evaluate(TestUtils.ChainPrivateKey, minerChain);
                minerSwarm.BlockChain.Append(block, false, true, false);

                await receiverSwarm.PreloadAsync(TimeSpan.FromSeconds(1));

                // Preloading should succeed even if action throws exception.
                Assert.Equal(minerChain.Tip, receiverChain.Tip);
            }
            finally
            {
                await StopAsync(minerSwarm);
            }
        }
        public async Task DetermineCanonicalChain(short canonComparerType)
        {
            IComparer <IBlockExcerpt> canonComparer;

            switch (canonComparerType)
            {
            default:
                canonComparer = new TotalDifficultyComparer();
                break;

            case 1:
                canonComparer = new AnonymousComparer <IBlockExcerpt>((a, b) =>
                                                                      string.Compare(
                                                                          a.Hash.ToString(),
                                                                          b.Hash.ToString(),
                                                                          StringComparison.Ordinal
                                                                          )
                                                                      );
                break;
            }

            var policy = new BlockPolicy <DumbAction>(
                new MinerReward(1),
                canonicalChainComparer: canonComparer
                );
            BlockChain <DumbAction> chain1 = TestUtils.MakeBlockChain(
                policy,
                new DefaultStore(null),
                new TrieStateStore(new MemoryKeyValueStore())
                );
            BlockChain <DumbAction> chain2 = TestUtils.MakeBlockChain(
                policy,
                new DefaultStore(null),
                new TrieStateStore(new MemoryKeyValueStore())
                );

            var key1 = new PrivateKey();
            var key2 = new PrivateKey();

            Swarm <DumbAction> miner1 = CreateSwarm(chain1, key1);
            Swarm <DumbAction> miner2 = CreateSwarm(chain2, key2);

            await chain1.MineBlock(key1);

            await chain1.MineBlock(key2);

            Block <DumbAction> bestBlock;

            switch (canonComparerType)
            {
            default:
                long nextDifficulty =
                    (long)chain1.Tip.TotalDifficulty + policy.GetNextBlockDifficulty(chain2);
                bestBlock = TestUtils.MineNext(
                    chain2.Tip,
                    policy.GetHashAlgorithm,
                    difficulty: nextDifficulty,
                    blockInterval: TimeSpan.FromMilliseconds(1),
                    miner: TestUtils.ChainPrivateKey.PublicKey
                    ).Evaluate(TestUtils.ChainPrivateKey, chain2);
                _output.WriteLine("chain1's total difficulty: {0}", chain1.Tip.TotalDifficulty);
                _output.WriteLine("chain2's total difficulty: {0}", bestBlock.TotalDifficulty);
                break;

            case 1:
                string chain1TipHash = chain1.Tip.Hash.ToString();
                string hashStr;
                do
                {
                    bestBlock = TestUtils.MineNext(
                        chain2.Tip,
                        policy.GetHashAlgorithm,
                        difficulty: policy.GetNextBlockDifficulty(chain2),
                        blockInterval: TimeSpan.FromMilliseconds(1),
                        miner: TestUtils.ChainPrivateKey.PublicKey
                        ).Evaluate(TestUtils.ChainPrivateKey, chain2);
                    hashStr = bestBlock.Hash.ToString();
                    _output.WriteLine("chain1's tip hash: {0}", chain1.Tip.Hash);
                    _output.WriteLine("chain2's tip hash: {0}", bestBlock.Hash);
                    _output.WriteLine(string.Empty);
                }while (string.Compare(chain1TipHash, hashStr, StringComparison.Ordinal) >= 0);
                break;
            }

            Assert.True(
                canonComparer.Compare(
                    new BlockPerception(bestBlock),
                    chain1.PerceiveBlock(chain1.Tip)
                    ) > 0
                );
            chain2.Append(bestBlock);

            try
            {
                await StartAsync(miner1);
                await StartAsync(miner2);

                await BootstrapAsync(miner2, miner1.AsPeer);

                miner2.BroadcastBlock(bestBlock);
                _output.WriteLine("miner1 is waiting for a new block...");
                await miner1.BlockReceived.WaitAsync();

                Assert.Equal(miner1.BlockChain.Tip, bestBlock);
                Assert.Equal(miner2.BlockChain.Tip, bestBlock);
            }
            finally
            {
                await StopAsync(miner1);
                await StopAsync(miner2);

                miner1.Dispose();
                miner2.Dispose();
            }
        }
示例#4
0
        public async Task BroadcastBlockWithSkip()
        {
            var policy           = new BlockPolicy <DumbAction>(new MinerReward(1));
            var fx1              = new DefaultStoreFixture(memory: true);
            var blockChain       = TestUtils.MakeBlockChain(policy, fx1.Store, fx1.StateStore);
            var privateKey       = new PrivateKey();
            var minerSwarm       = CreateSwarm(blockChain, privateKey);
            var fx2              = new DefaultStoreFixture(memory: true);
            var receiverRenderer = new RecordingActionRenderer <DumbAction>();
            var loggedRenderer   = new LoggedActionRenderer <DumbAction>(
                receiverRenderer,
                _logger);
            var receiverChain = TestUtils.MakeBlockChain(
                policy,
                fx2.Store,
                fx2.StateStore,
                renderers: new[] { loggedRenderer });
            Swarm <DumbAction> receiverSwarm = CreateSwarm(receiverChain);

            int renderCount = 0;

            receiverRenderer.RenderEventHandler += (_, a) => renderCount += a is DumbAction ? 1 : 0;

            Transaction <DumbAction>[] transactions =
            {
                fx1.MakeTransaction(
                    new[]
                {
                    new DumbAction(fx1.Address2, "foo"),
                    new DumbAction(fx1.Address2, "bar"),
                },
                    timestamp: DateTimeOffset.MinValue,
                    nonce: 0,
                    privateKey: privateKey),
                fx1.MakeTransaction(
                    new[]
                {
                    new DumbAction(fx1.Address2, "baz"),
                    new DumbAction(fx1.Address2, "qux"),
                },
                    timestamp: DateTimeOffset.MinValue.AddSeconds(5),
                    nonce: 1,
                    privateKey: privateKey),
            };

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

                await BootstrapAsync(receiverSwarm, minerSwarm.AsPeer);

                Block <DumbAction> block1 = TestUtils.MineNext(
                    blockChain.Genesis,
                    policy.GetHashAlgorithm,
                    new[] { transactions[0] },
                    null,
                    policy.GetNextBlockDifficulty(blockChain),
                    miner: TestUtils.GenesisMiner.PublicKey
                    ).Evaluate(TestUtils.GenesisMiner, blockChain);
                blockChain.Append(block1, true, true, false);
                Block <DumbAction> block2 = TestUtils.MineNext(
                    block1,
                    policy.GetHashAlgorithm,
                    new[] { transactions[1] },
                    null,
                    policy.GetNextBlockDifficulty(blockChain),
                    miner: TestUtils.GenesisMiner.PublicKey
                    ).Evaluate(TestUtils.GenesisMiner, blockChain);
                blockChain.Append(block2, true, true, false);
                Log.Debug("Ready to broadcast blocks.");
                minerSwarm.BroadcastBlock(block2);
                await receiverSwarm.BlockAppended.WaitAsync();

                Assert.Equal(3, receiverChain.Count);
                Assert.Equal(4, renderCount);
            }
            finally
            {
                await StopAsync(minerSwarm);
                await StopAsync(receiverSwarm);

                fx1.Dispose();
                minerSwarm.Dispose();
            }
        }