public void Sort() { void PrintBlocks(IEnumerable <BlockPerception> blocks) { foreach (BlockPerception b in blocks) { _output.WriteLine( nameof(BlockPerceptions) + "[{0}]", Array.IndexOf(BlockPerceptions, b) ); } _output.WriteLine(string.Empty); } DateTimeOffset currentTime = DateTimeOffset.FromUnixTimeSeconds(1609426815); TimeSpan outdateAfter = TimeSpan.FromSeconds(15); var comparer = new TotalDifficultyComparer(); BlockPerception[] sorted = BlockPerceptions.OrderBy(e => e, comparer).ToArray(); PrintBlocks(sorted); Assert.True(BlockPerceptions[2].ExcerptEquals(sorted[0])); Assert.True(BlockPerceptions[1].ExcerptEquals(sorted[1])); Assert.True(BlockPerceptions[0].ExcerptEquals(sorted[2])); Assert.True(BlockPerceptions[4].ExcerptEquals(sorted[3])); Assert.True(BlockPerceptions[3].ExcerptEquals(sorted[4])); sorted = BlockPerceptions .Select(p => new BlockPerception(p, currentTime)) .OrderBy(e => e, comparer) .ToArray(); PrintBlocks(sorted); Assert.True(BlockPerceptions[2].ExcerptEquals(sorted[0])); Assert.True(BlockPerceptions[1].ExcerptEquals(sorted[1])); Assert.True(BlockPerceptions[0].ExcerptEquals(sorted[2])); Assert.True(BlockPerceptions[4].ExcerptEquals(sorted[3])); Assert.True(BlockPerceptions[3].ExcerptEquals(sorted[4])); sorted = BlockPerceptions .Select(p => new BlockPerception(p, currentTime - outdateAfter)) .OrderBy(e => e, comparer) .ToArray(); PrintBlocks(sorted); Assert.True(BlockPerceptions[2].ExcerptEquals(sorted[0])); Assert.True(BlockPerceptions[1].ExcerptEquals(sorted[1])); Assert.True(BlockPerceptions[0].ExcerptEquals(sorted[2])); Assert.True(BlockPerceptions[4].ExcerptEquals(sorted[3])); Assert.True(BlockPerceptions[3].ExcerptEquals(sorted[4])); }
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(); } }