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(); } }
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(); } }