public async Task GetMaturedBlockDeposits_Fails_When_Block_Not_In_Chain_Async()
        {
            FederationGatewayController controller = this.CreateController();

            ChainedHeader tip = ChainedHeadersHelper.CreateConsecutiveHeaders(3, null, true)[2];

            this.consensusManager.Tip.Returns(tip);

            IActionResult result = await controller.GetMaturedBlockDepositsAsync(new MaturedBlockRequestModel(1, 1000)).ConfigureAwait(false);

            result.Should().BeOfType <ErrorResult>();

            var error = result as ErrorResult;

            error.Should().NotBeNull();

            var errorResponse = error.Value as ErrorResponse;

            errorResponse.Should().NotBeNull();
            errorResponse.Errors.Should().HaveCount(1);

            errorResponse.Errors.Should().Contain(
                e => e.Status == (int)HttpStatusCode.BadRequest);

            errorResponse.Errors.Should().Contain(
                e => e.Message.Contains("Unable to get deposits for block at height"));
        }
        public async Task GetMaturedBlockDeposits_Gets_All_Matured_Block_Deposits_Async()
        {
            ChainedHeader tip = ChainedHeadersHelper.CreateConsecutiveHeaders(10, null, true).Last();

            this.consensusManager.Tip.Returns(tip);

            FederationGatewayController controller = this.CreateController();

            ChainedHeader earlierBlock = tip.GetAncestor(2);

            int minConfirmations = 2;

            this.depositExtractor.MinimumDepositConfirmations.Returns((uint)minConfirmations);

            int depositExtractorCallCount = 0;

            this.depositExtractor.ExtractBlockDeposits(Arg.Any <ChainedHeaderBlock>()).Returns(new MaturedBlockDepositsModel(null, null));
            this.depositExtractor.When(x => x.ExtractBlockDeposits(Arg.Any <ChainedHeaderBlock>())).Do(info =>
            {
                depositExtractorCallCount++;
            });

            IActionResult result = await controller.GetMaturedBlockDepositsAsync(new MaturedBlockRequestModel(earlierBlock.Height, 1000)).ConfigureAwait(false);

            result.Should().BeOfType <JsonResult>();

            // If the minConfirmations == 0 and this.chain.Height == earlierBlock.Height then expectedCallCount must be 1.
            int expectedCallCount = (tip.Height - minConfirmations) - earlierBlock.Height + 1;

            depositExtractorCallCount.Should().Be(expectedCallCount);
        }
示例#3
0
        public void GetMaturedBlockDeposits_Fails_When_Block_Height_Greater_Than_Minimum_Deposit_Confirmations_Async()
        {
            ChainedHeader tip = ChainedHeadersHelper.CreateConsecutiveHeaders(5, null, true).Last();

            this.consensusManager.Tip.Returns(tip);

            FederationGatewayController controller = this.CreateController();

            // Minimum deposit confirmations : 2
            this.depositExtractor.MinimumDepositConfirmations.Returns((uint)2);

            int maturedHeight = (int)(tip.Height - this.depositExtractor.MinimumDepositConfirmations);

            // Back online at block height : 3
            // 0 - 1 - 2 - 3
            ChainedHeader earlierBlock = tip.GetAncestor(maturedHeight + 1);

            // Mature height = 2 (Chain header height (4) - Minimum deposit confirmations (2))
            IActionResult result = controller.GetMaturedBlockDeposits(new MaturedBlockRequestModel(earlierBlock.Height, 1000));

            // Block height (3) > Mature height (2) - returns error message
            var maturedBlockDepositsResult = (result as JsonResult).Value as SerializableResult <List <MaturedBlockDepositsModel> >;

            maturedBlockDepositsResult.Should().NotBeNull();
            maturedBlockDepositsResult.IsSuccess.Should().Be(false);
            maturedBlockDepositsResult.Message.Should().Be(string.Format(MaturedBlocksProvider.RetrieveBlockHeightHigherThanMaturedTipMessage, earlierBlock.Height, maturedHeight));
        }
        public void ReceiveCurrentBlockTip_Should_Call_LeaderProdvider_Update()
        {
            var controller = new FederationGatewayController(
                this.loggerFactory,
                this.maturedBlockReceiver,
                this.maturedBlocksRequester,
                this.leaderProvider,
                this.chain,
                GetMaturedBlocksProvider(),
                this.depositExtractor,
                this.leaderReceiver);

            var model = new BlockTipModel(TestingValues.GetUint256(), TestingValues.GetPositiveInt(), TestingValues.GetPositiveInt());

            var leaderProviderCallCount = 0;

            this.leaderProvider.When(x => x.Update(Arg.Any <BlockTipModel>())).Do(info =>
            {
                leaderProviderCallCount++;
            });

            IActionResult result = controller.ReceiveCurrentBlockTip(model);

            result.Should().BeOfType <OkResult>();
            leaderProviderCallCount.Should().Be(1);
        }
        public void ReceiveMaturedBlock_Should_Call_ReceivedMatureBlockDeposits()
        {
            var controller = new FederationGatewayController(
                this.loggerFactory,
                this.maturedBlockReceiver,
                this.maturedBlocksRequester,
                this.leaderProvider,
                this.chain,
                GetMaturedBlocksProvider(),
                this.depositExtractor,
                this.leaderReceiver);

            HashHeightPair hashHeightPair = TestingValues.GetHashHeightPair();
            var            deposits       = new MaturedBlockDepositsModel(new MaturedBlockModel()
            {
                BlockHash = hashHeightPair.Hash, BlockHeight = hashHeightPair.Height
            },
                                                                          new[] { new Deposit(0, Money.COIN * 10000, "TTMM7qGGxD5c77pJ8puBg7sTLAm2zZNBwK",
                                                                                              hashHeightPair.Height, hashHeightPair.Hash) });

            var callCount = 0;

            this.maturedBlockReceiver.When(x => x.ReceiveMaturedBlockDeposits(Arg.Any <IMaturedBlockDeposits[]>())).Do(info =>
            {
                callCount++;
            });

            controller.ReceiveMaturedBlock(deposits);
            callCount.Should().Be(1);
        }
        public async Task GetMaturedBlockDeposits_Fails_When_Block_Height_Greater_Than_Minimum_Deposit_Confirmations_Async()
        {
            ChainedHeader tip = ChainedHeadersHelper.CreateConsecutiveHeaders(5, null, true).Last();

            this.consensusManager.Tip.Returns(tip);

            // Minimum deposit confirmations : 2
            IFederatedPegSettings federatedPegSettings = Substitute.For <IFederatedPegSettings>();

            federatedPegSettings.MinimumConfirmationsNormalDeposits.Returns(2);
            FederationGatewayController controller = this.CreateController(federatedPegSettings);

            int maturedHeight = (int)(tip.Height - 2);

            // Back online at block height : 3
            // 0 - 1 - 2 - 3
            ChainedHeader earlierBlock = tip.GetAncestor(maturedHeight + 1);

            // Mature height = 2 (Chain header height (4) - Minimum deposit confirmations (2))
            IActionResult result = await controller.GetMaturedBlockDepositsAsync(earlierBlock.Height);

            // Block height (3) > Mature height (2) - returns error message
            var maturedBlockDepositsResult = (result as JsonResult).Value as SerializableResult <List <MaturedBlockDepositsModel> >;

            maturedBlockDepositsResult.Should().NotBeNull();
            maturedBlockDepositsResult.Value.Count().Should().Be(0);
            Assert.NotNull(maturedBlockDepositsResult.Message);
        }
        public void GetMaturedBlockDeposits_Fails_When_Block_Height_Greater_Than_Minimum_Deposit_Confirmations_Async()
        {
            ChainedHeader tip = ChainedHeadersHelper.CreateConsecutiveHeaders(5, null, true).Last();

            this.consensusManager.Tip.Returns(tip);

            // Minimum deposit confirmations : 2
            IFederatedPegSettings federatedPegSettings = Substitute.For <IFederatedPegSettings>();

            federatedPegSettings.MinimumConfirmationsNormalDeposits.Returns(2);
            FederationGatewayController controller = this.CreateController(federatedPegSettings);

            int maturedHeight = (int)(tip.Height - 2);

            // Back online at block height : 3
            // 0 - 1 - 2 - 3
            ChainedHeader earlierBlock = tip.GetAncestor(maturedHeight + 1);

            // Mature height = 2 (Chain header height (4) - Minimum deposit confirmations (2))
            IActionResult result = controller.GetMaturedBlockDeposits(earlierBlock.Height);

            // Block height (3) > Mature height (2) - returns error message
            var maturedBlockDepositsResult = (result as JsonResult).Value as SerializableResult <List <MaturedBlockDepositsModel> >;

            maturedBlockDepositsResult.Should().NotBeNull();
            maturedBlockDepositsResult.Value.Count().Should().Be(0);
            maturedBlockDepositsResult.Message.Should().Contain(string.Format("The submitted block height of {0} is not mature enough for '{1}' deposits, blocks below {2} can be returned.", earlierBlock.Height, DepositRetrievalType.Normal, maturedHeight));
        }
        private FederationGatewayController CreateController(IFederatedPegSettings federatedPegSettings)
        {
            var controller = new FederationGatewayController(
                this.loggerFactory,
                this.GetMaturedBlocksProvider(federatedPegSettings),
                this.federatedPegSettings,
                this.federationWalletManager,
                this.federationManager);

            return(controller);
        }
示例#9
0
        public void Call_Mainchain_Gateway_Get_Info()
        {
            var federation = new Federation(new[]
            {
                new PubKey("02fad5f3c4fdf4c22e8be4cfda47882fff89aaa0a48c1ccad7fa80dc5fee9ccec3"),
                new PubKey("02503f03243d41c141172465caca2f5cef7524f149e965483be7ce4e44107d7d35"),
                new PubKey("03be943c3a31359cd8e67bedb7122a0898d2c204cf2d0119e923ded58c429ef97c")
            });

            Network sideChainNetwork = new TestNetwork(federation);

            string redeemScript = PayToFederationTemplate.Instance.GenerateScriptPubKey(federation.Id).ToString();

            string federationIps  = "127.0.0.1:36201,127.0.0.1:36202,127.0.0.1:36203";
            string multisigPubKey = federation.GetFederationDetails().transactionSigningKeys.TakeLast(1).First().ToHex();

            string[] args         = new[] { "-mainchain", "-testnet", $"-federationips={federationIps}", $"-redeemscript={redeemScript}", $"-publickey={multisigPubKey}", "-mincoinmaturity=1", "-mindepositconfirmations=1" };
            var      nodeSettings = new NodeSettings(sideChainNetwork, ProtocolVersion.ALT_PROTOCOL_VERSION, args: args);

            this.federationWalletManager.IsFederationWalletActive().Returns(true);

            var settings = new FederatedPegSettings(nodeSettings, new CounterChainNetworkWrapper(KnownNetworks.StraxRegTest));

            var controller = new FederationGatewayController(
                Substitute.For <IAsyncProvider>(),
                new ChainIndexer(),
                Substitute.For <IConnectionManager>(),
                this.crossChainTransferStore,
                this.GetMaturedBlocksProvider(settings),
                this.network,
                settings,
                this.federationWalletManager,
                Substitute.For <IFullNode>(),
                Substitute.For <IPeerBanning>(),
                this.federationManager);

            IActionResult result = controller.GetInfo();

            result.Should().BeOfType <JsonResult>();
            ((JsonResult)result).Value.Should().BeOfType <FederationGatewayInfoModel>();

            var model = ((JsonResult)result).Value as FederationGatewayInfoModel;

            model.IsMainChain.Should().BeTrue();
            model.FederationMiningPubKeys.Should().BeNull();
            model.MiningPublicKey.Should().BeNull();
            model.MultiSigRedeemScript.Should().Be(redeemScript);
            string.Join(",", model.FederationNodeIpEndPoints).Should().Be(federationIps);
            model.IsActive.Should().BeTrue();
            model.MinimumDepositConfirmationsSmallDeposits.Should().Be(25);
            model.MinimumDepositConfirmationsNormalDeposits.Should().Be(80);
            model.MultisigPublicKey.Should().Be(multisigPubKey);
        }
        private FederationGatewayController CreateController(IFederatedPegSettings federatedPegSettings)
        {
            var controller = new FederationGatewayController(
                this.crossChainTransferStore,
                this.loggerFactory,
                this.GetMaturedBlocksProvider(federatedPegSettings),
                this.network,
                this.federatedPegSettings,
                this.federationWalletManager,
                this.signedMultisigTransactionBroadcaster,
                this.federationManager);

            return(controller);
        }
        private FederationGatewayController CreateController()
        {
            var controller = new FederationGatewayController(
                this.loggerFactory,
                this.network,
                this.leaderProvider,
                this.GetMaturedBlocksProvider(),
                this.leaderReceiver,
                this.federationGatewaySettings,
                this.federationWalletManager,
                this.federationManager);

            return(controller);
        }
示例#12
0
        public void GetMaturedBlockDeposits_Gets_All_Matured_Block_Deposits()
        {
            ChainedHeader tip = ChainedHeadersHelper.CreateConsecutiveHeaders(10, null, true).Last();

            this.consensusManager.Tip.Returns(tip);

            int minConfirmations = 2;

            // Minimum deposit confirmations : 2
            IFederatedPegSettings federatedPegSettings = Substitute.For <IFederatedPegSettings>();

            federatedPegSettings.MinimumConfirmationsNormalDeposits.Returns(minConfirmations);
            FederationGatewayController controller = this.CreateController(federatedPegSettings);

            ChainedHeader earlierBlock = tip.GetAncestor(minConfirmations);

            int depositExtractorCallCount = 0;

            this.depositExtractor.ExtractDepositsFromBlock(Arg.Any <Block>(), Arg.Any <int>(), Arg.Any <DepositRetrievalType[]>()).Returns(new List <IDeposit>());
            this.depositExtractor.When(x => x.ExtractDepositsFromBlock(Arg.Any <Block>(), Arg.Any <int>(), Arg.Any <DepositRetrievalType[]>())).Do(info =>
            {
                depositExtractorCallCount++;
            });

            this.consensusManager.GetBlocksAfterBlock(Arg.Any <ChainedHeader>(), MaturedBlocksProvider.MaturedBlocksBatchSize, Arg.Any <CancellationTokenSource>()).Returns(delegate(CallInfo info)
            {
                var chainedHeader = (ChainedHeader)info[0];
                var blocks        = new List <ChainedHeaderBlock>();

                int startHeight = (chainedHeader == null) ? 0 : (chainedHeader.Height + 1);

                for (int i = startHeight; i <= this.consensusManager.Tip.Height; i++)
                {
                    blocks.Add(new ChainedHeaderBlock(new Block(), tip.GetAncestor(i)));
                }

                return(blocks);
            });

            IActionResult result = controller.GetMaturedBlockDeposits(earlierBlock.Height);

            result.Should().BeOfType <JsonResult>();
            var maturedBlockDepositsResult = (result as JsonResult).Value as SerializableResult <List <MaturedBlockDepositsModel> >;

            maturedBlockDepositsResult.Should().NotBeNull();
            maturedBlockDepositsResult.Message.Should().Be(string.Empty);

            // Heights 0 to 10.
            depositExtractorCallCount.Should().Be(11);
        }
        private FederationGatewayController CreateController(IFederatedPegSettings federatedPegSettings)
        {
            var controller = new FederationGatewayController(
                Substitute.For <IAsyncProvider>(),
                new ChainIndexer(),
                Substitute.For <IConnectionManager>(),
                this.crossChainTransferStore,
                this.GetMaturedBlocksProvider(federatedPegSettings),
                this.network,
                this.federatedPegSettings,
                this.federationWalletManager,
                Substitute.For <IFullNode>(),
                this.federationManager);

            return(controller);
        }
        public async void GetMaturedBlockDeposits_Fails_When_Block_Height_Greater_Than_Minimum_Deposit_Confirmations_Async()
        {
            // Chain header height : 4
            // 0 - 1 - 2 - 3 - 4
            this.chain = this.BuildChain(5);

            var controller = new FederationGatewayController(
                this.loggerFactory,
                this.maturedBlockReceiver,
                this.maturedBlocksRequester,
                this.leaderProvider,
                this.chain,
                this.GetMaturedBlocksProvider(),
                this.depositExtractor,
                this.leaderReceiver);

            // Minimum deposit confirmations : 2
            this.depositExtractor.MinimumDepositConfirmations.Returns((uint)2);

            int maturedHeight = (int)(this.chain.Tip.Height - this.depositExtractor.MinimumDepositConfirmations);

            // Back online at block height : 3
            // 0 - 1 - 2 - 3
            ChainedHeader earlierBlock = this.chain.GetBlock(maturedHeight + 1);

            // Mature height = 2 (Chain header height (4) - Minimum deposit confirmations (2))
            IActionResult result = await controller.GetMaturedBlockDepositsAsync(new MaturedBlockRequestModel(earlierBlock.Height)).ConfigureAwait(false);

            // Block height (3) > Mature height (2) - returns error message
            result.Should().BeOfType <ErrorResult>();

            var error = result as ErrorResult;

            error.Should().NotBeNull();

            var errorResponse = error.Value as ErrorResponse;

            errorResponse.Should().NotBeNull();
            errorResponse.Errors.Should().HaveCount(1);

            errorResponse.Errors.Should().Contain(
                e => e.Status == (int)HttpStatusCode.BadRequest);

            errorResponse.Errors.Should().Contain(
                e => e.Message.Contains($"Block height {earlierBlock.Height} submitted is not mature enough. Blocks less than a height of {maturedHeight} can be processed."));
        }
        public void ReceiveCurrentBlockTip_Should_Call_LeaderProdvider_Update()
        {
            FederationGatewayController controller = this.CreateController();

            var model = new BlockTipModel(TestingValues.GetUint256(), TestingValues.GetPositiveInt(), TestingValues.GetPositiveInt());

            int leaderProviderCallCount = 0;

            this.leaderProvider.When(x => x.Update(Arg.Any <BlockTipModel>())).Do(info =>
            {
                leaderProviderCallCount++;
            });

            IActionResult result = controller.PushCurrentBlockTip(model);

            result.Should().BeOfType <OkResult>();
            leaderProviderCallCount.Should().Be(1);
        }
        public void GetMaturedBlockDeposits_Gets_All_Matured_Block_Deposits()
        {
            ChainedHeader tip = ChainedHeadersHelper.CreateConsecutiveHeaders(10, null, true).Last();

            this.consensusManager.Tip.Returns(tip);

            int minConfirmations = 2;

            // Minimum deposit confirmations : 2
            IFederatedPegSettings federatedPegSettings = Substitute.For <IFederatedPegSettings>();

            federatedPegSettings.MinimumConfirmationsNormalDeposits.Returns(minConfirmations);
            FederationGatewayController controller = this.CreateController(federatedPegSettings);

            ChainedHeader earlierBlock = tip.GetAncestor(minConfirmations);

            int depositExtractorCallCount = 0;

            this.depositExtractor.ExtractBlockDeposits(Arg.Any <ChainedHeaderBlock>(), DepositRetrievalType.Normal).Returns(new MaturedBlockDepositsModel(null, null));
            this.depositExtractor.When(x => x.ExtractBlockDeposits(Arg.Any <ChainedHeaderBlock>(), DepositRetrievalType.Normal)).Do(info =>
            {
                depositExtractorCallCount++;
            });

            this.consensusManager.GetBlockData(Arg.Any <List <uint256> >()).ReturnsForAnyArgs((x) =>
            {
                List <uint256> hashes = x.ArgAt <List <uint256> >(0);
                return(hashes.Select((h) => new ChainedHeaderBlock(new Block(), earlierBlock)).ToArray());
            });

            IActionResult result = controller.GetMaturedBlockDeposits(earlierBlock.Height);

            result.Should().BeOfType <JsonResult>();
            var maturedBlockDepositsResult = (result as JsonResult).Value as SerializableResult <List <MaturedBlockDepositsModel> >;

            maturedBlockDepositsResult.Should().NotBeNull();
            maturedBlockDepositsResult.Message.Should().Be(string.Empty);

            // If the minConfirmations == 0 and this.chain.Height == earlierBlock.Height then expectedCallCount must be 1.
            int expectedCallCount = (tip.Height - minConfirmations) - earlierBlock.Height + 1;

            depositExtractorCallCount.Should().Be(expectedCallCount);
        }
        public void Call_Sidechain_Gateway_Get_Info()
        {
            string redeemScript   = "2 02fad5f3c4fdf4c22e8be4cfda47882fff89aaa0a48c1ccad7fa80dc5fee9ccec3 02503f03243d41c141172465caca2f5cef7524f149e965483be7ce4e44107d7d35 03be943c3a31359cd8e67bedb7122a0898d2c204cf2d0119e923ded58c429ef97c 3 OP_CHECKMULTISIG";
            string federationIps  = "127.0.0.1:36201,127.0.0.1:36202,127.0.0.1:36203";
            string multisigPubKey = "03be943c3a31359cd8e67bedb7122a0898d2c204cf2d0119e923ded58c429ef97c";

            string[]     args         = new[] { "-sidechain", "-regtest", $"-federationips={federationIps}", $"-redeemscript={redeemScript}", $"-publickey={multisigPubKey}", "-mincoinmaturity=1", "-mindepositconfirmations=1" };
            NodeSettings nodeSettings = new NodeSettings(FederatedPegNetwork.NetworksSelector.Regtest(), ProtocolVersion.ALT_PROTOCOL_VERSION, args: args);

            this.federationWalletManager.IsFederationActive().Returns(true);

            this.federationManager.Initialize();

            FederationGatewaySettings settings = new FederationGatewaySettings(nodeSettings);

            var controller = new FederationGatewayController(
                this.loggerFactory,
                this.network,
                this.leaderProvider,
                this.GetMaturedBlocksProvider(),
                this.leaderReceiver,
                settings,
                this.federationWalletManager,
                this.federationManager);

            IActionResult result = controller.GetInfo();

            result.Should().BeOfType <JsonResult>();
            ((JsonResult)result).Value.Should().BeOfType <FederationGatewayInfoModel>();

            FederationGatewayInfoModel model = ((JsonResult)result).Value as FederationGatewayInfoModel;

            model.IsMainChain.Should().BeFalse();
            model.FederationMiningPubKeys.Should().Equal(((PoAConsensusOptions)FederatedPegNetwork.NetworksSelector.Regtest().Consensus.Options).GenesisFederationPublicKeys.Select(keys => keys.ToString()));
            model.MultiSigRedeemScript.Should().Be(redeemScript);
            string.Join(",", model.FederationNodeIpEndPoints).Should().Be(federationIps);
            model.IsActive.Should().BeTrue();
            model.MinCoinMaturity.Should().Be(1);
            model.MinimumDepositConfirmations.Should().Be(1);
            model.MultisigPublicKey.Should().Be(multisigPubKey);
        }
        public async Task GetMaturedBlockDeposits_Fails_When_Block_Height_Greater_Than_Minimum_Deposit_Confirmations_Async()
        {
            ChainedHeader tip = ChainedHeadersHelper.CreateConsecutiveHeaders(5, null, true).Last();

            this.consensusManager.Tip.Returns(tip);

            FederationGatewayController controller = this.CreateController();

            // Minimum deposit confirmations : 2
            this.depositExtractor.MinimumDepositConfirmations.Returns((uint)2);

            int maturedHeight = (int)(tip.Height - this.depositExtractor.MinimumDepositConfirmations);

            // Back online at block height : 3
            // 0 - 1 - 2 - 3
            ChainedHeader earlierBlock = tip.GetAncestor(maturedHeight + 1);

            // Mature height = 2 (Chain header height (4) - Minimum deposit confirmations (2))
            IActionResult result = await controller.GetMaturedBlockDepositsAsync(new MaturedBlockRequestModel(earlierBlock.Height, 1000)).ConfigureAwait(false);

            // Block height (3) > Mature height (2) - returns error message
            result.Should().BeOfType <ErrorResult>();

            var error = result as ErrorResult;

            error.Should().NotBeNull();

            var errorResponse = error.Value as ErrorResponse;

            errorResponse.Should().NotBeNull();
            errorResponse.Errors.Should().HaveCount(1);

            errorResponse.Errors.Should().Contain(
                e => e.Status == (int)HttpStatusCode.BadRequest);

            errorResponse.Errors.Should().Contain(
                e => e.Message.Contains($"Block height {earlierBlock.Height} submitted is not mature enough. Blocks less than a height of {maturedHeight} can be processed."));
        }
        public async void GetMaturedBlockDeposits_Gets_All_Matured_Block_Deposits_Async()
        {
            this.chain = this.BuildChain(10);

            var controller = new FederationGatewayController(
                this.loggerFactory,
                this.maturedBlockReceiver,
                this.maturedBlocksRequester,
                this.leaderProvider,
                this.chain,
                GetMaturedBlocksProvider(),
                this.depositExtractor,
                this.leaderReceiver);

            ChainedHeader earlierBlock = this.chain.GetBlock(2);

            var minConfirmations = 2;

            this.depositExtractor.MinimumDepositConfirmations.Returns((uint)minConfirmations);

            var depositExtractorCallCount = 0;

            this.depositExtractor.ExtractBlockDeposits(Arg.Any <ChainedHeader>()).Returns(new MaturedBlockDepositsModel(null, null));
            this.depositExtractor.When(x => x.ExtractBlockDeposits(Arg.Any <ChainedHeader>())).Do(info =>
            {
                depositExtractorCallCount++;
            });

            IActionResult result = await controller.GetMaturedBlockDepositsAsync(new MaturedBlockRequestModel(earlierBlock.Height)).ConfigureAwait(false);

            result.Should().BeOfType <JsonResult>();

            // If the minConfirmations == 0 and this.chain.Height == earlierBlock.Height then expectedCallCount must be 1.
            var expectedCallCount = (this.chain.Height - minConfirmations) - earlierBlock.Height + 1;

            depositExtractorCallCount.Should().Be(expectedCallCount);
        }
        public async void GetMaturedBlockDeposits_Fails_When_Block_Not_In_Chain_Async()
        {
            this.chain = Substitute.For <ConcurrentChain>();

            var controller = new FederationGatewayController(
                this.loggerFactory,
                this.maturedBlockReceiver,
                this.maturedBlocksRequester,
                this.leaderProvider,
                this.chain,
                this.GetMaturedBlocksProvider(),
                this.depositExtractor,
                this.leaderReceiver);

            ChainedHeader chainedHeader = this.BuildChain(3).GetBlock(2);

            this.chain.Tip.Returns(chainedHeader);

            IActionResult result = await controller.GetMaturedBlockDepositsAsync(new MaturedBlockRequestModel(1)).ConfigureAwait(false);

            result.Should().BeOfType <ErrorResult>();

            var error = result as ErrorResult;

            error.Should().NotBeNull();

            var errorResponse = error.Value as ErrorResponse;

            errorResponse.Should().NotBeNull();
            errorResponse.Errors.Should().HaveCount(1);

            errorResponse.Errors.Should().Contain(
                e => e.Status == (int)HttpStatusCode.BadRequest);

            errorResponse.Errors.Should().Contain(
                e => e.Message.Contains("was not found on the block chain"));
        }