public void PresentDifferentChains_AlternativeChainWithMoreChainWorkShouldAlwaysBeMarkedForDownload()
        {
            // Chain header tree setup.
            var ctx = new TestContext();
            ChainedHeaderTree cht             = ctx.CreateChainedHeaderTree();
            ChainedHeader     initialChainTip = ctx.ExtendAChain(5);

            cht.Initialize(initialChainTip, true);
            ctx.ConsensusSettings.UseCheckpoints = false;

            // Chains A and B setup.
            const int          commonChainSize          = 4;
            const int          chainAExtension          = 4;
            const int          chainBExtension          = 2;
            ChainedHeader      commonChainTip           = ctx.ExtendAChain(commonChainSize, initialChainTip); // ie. h1=h2=h3=h4
            ChainedHeader      chainATip                = ctx.ExtendAChain(chainAExtension, commonChainTip);  // ie. (h1=h2=h3=h4)=a5=a6=a7=a8
            ChainedHeader      chainBTip                = ctx.ExtendAChain(chainBExtension, commonChainTip);  // ie. (h1=h2=h3=h4)=b5=b6
            List <BlockHeader> listOfChainABlockHeaders = ctx.ChainedHeaderToList(chainATip, commonChainSize + chainAExtension);
            List <BlockHeader> listOfChainBBlockHeaders = ctx.ChainedHeaderToList(chainBTip, commonChainSize + chainBExtension);

            // Chain A is presented by peer 1. DownloadTo should be chain A tip.
            ConnectNewHeadersResult connectNewHeadersResult = cht.ConnectNewHeaders(1, listOfChainABlockHeaders);
            ChainedHeader           chainedHeaderTo         = connectNewHeadersResult.DownloadTo;

            chainedHeaderTo.HashBlock.Should().Be(chainATip.HashBlock);

            // Set chain A tip as a consensus tip.
            cht.ConsensusTipChanged(chainATip);

            // Chain B is presented by peer 2. DownloadTo should be not set, as chain
            // B has less chain work.
            connectNewHeadersResult = cht.ConnectNewHeaders(2, listOfChainBBlockHeaders);
            connectNewHeadersResult.DownloadTo.Should().BeNull();

            // Add more chain work and blocks into chain B.
            const int chainBAdditionalBlocks = 4;

            chainBTip = ctx.ExtendAChain(chainBAdditionalBlocks, chainBTip); // ie. (h1=h2=h3=h4)=b5=b6=b7=b8=b9=b10
            listOfChainBBlockHeaders = ctx.ChainedHeaderToList(chainBTip, commonChainSize + chainBExtension + chainBAdditionalBlocks);
            List <BlockHeader> listOfNewChainBBlockHeaders = listOfChainBBlockHeaders.TakeLast(chainBAdditionalBlocks).ToList();

            // Chain B is presented by peer 2 again.
            // DownloadTo should now be chain B as B has more chain work than chain A.
            // DownloadFrom should be the block where split occurred.
            // h1=h2=h3=h4=(b5)=b6=b7=b8=b9=(b10) - from b5 to b10.
            connectNewHeadersResult = cht.ConnectNewHeaders(2, listOfNewChainBBlockHeaders);

            ChainedHeader chainedHeaderFrom  = connectNewHeadersResult.DownloadFrom;
            BlockHeader   expectedHeaderFrom = listOfChainBBlockHeaders[commonChainSize];

            chainedHeaderFrom.Header.GetHash().Should().Be(expectedHeaderFrom.GetHash());

            chainedHeaderTo = connectNewHeadersResult.DownloadTo;
            chainedHeaderTo.HashBlock.Should().Be(chainBTip.HashBlock);
        }
Beispiel #2
0
        internal void SwitchToChain(ChainedHeaderTree cht, ChainedHeader chainTip, ChainedHeader consumedHeader, int extensionSize)
        {
            ChainedHeader[] consumedHeaders = consumedHeader.ToArray(extensionSize);

            for (int i = 0; i < extensionSize; i++)
            {
                ChainedHeader currentConsumedCh = consumedHeaders[i];
                cht.BlockDataDownloaded(currentConsumedCh, chainTip.GetAncestor(currentConsumedCh.Height).Block);
                cht.PartialValidationSucceeded(currentConsumedCh, out bool fullValidationRequired);
                cht.ConsensusTipChanged(currentConsumedCh);
            }
        }