public async Task <IActionResult> PostConfirmationAsync([FromQuery, Required] string uniqueId, [FromQuery, Required] long roundId)
        {
            if (roundId < 0 || !ModelState.IsValid)
            {
                return(BadRequest());
            }

            (CcjRound round, Alice alice) = GetRunningRoundAndAliceOrFailureResponse(roundId, uniqueId, CcjRoundPhase.ConnectionConfirmation, out IActionResult returnFailureResponse);
            if (returnFailureResponse != null)
            {
                return(returnFailureResponse);
            }

            CcjRoundPhase phase = round.Phase;

            // Start building the response.
            var resp = new ConnConfResp
            {
                CurrentPhase = phase
            };

            switch (phase)
            {
            case CcjRoundPhase.InputRegistration:
            {
                round.StartAliceTimeout(alice.UniqueId);
                break;
            }

            case CcjRoundPhase.ConnectionConfirmation:
            {
                alice.State = AliceState.ConnectionConfirmed;

                int takeBlindCount = round.EstimateBestMixingLevel(alice);

                var prevBlindCount = alice.BlindedOutputScripts.Length;
                alice.BlindedOutputScripts    = alice.BlindedOutputScripts.Take(takeBlindCount).ToArray();
                alice.BlindedOutputSignatures = alice.BlindedOutputSignatures.Take(takeBlindCount).ToArray();
                resp.BlindedOutputSignatures  = alice.BlindedOutputSignatures;                                // Don't give back more mixing levels than we'll use.

                // Progress round if needed.
                if (round.AllAlices(AliceState.ConnectionConfirmed))
                {
                    await round.ProgressToOutputRegistrationOrFailAsync();
                }

                break;
            }

            default:
            {
                TryLogLateRequest(roundId, CcjRoundPhase.ConnectionConfirmation);
                return(Gone($"Participation can be only confirmed from InputRegistration or ConnectionConfirmation phase. Current phase: {phase}."));
            }
            }

            return(Ok(resp));
        }
        public async Task <(CcjRoundPhase currentPhase, IEnumerable <ActiveOutput> activeOutputs)> PostConfirmationAsync()
        {
            using (HttpResponseMessage response = await TorClient.SendAsync(HttpMethod.Post, $"/api/v{Helpers.Constants.BackendMajorVersion}/btc/chaumiancoinjoin/confirmation?uniqueId={UniqueId}&roundId={RoundId}"))
            {
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    await response.ThrowRequestExceptionFromContentAsync();
                }

                ConnConfResp resp = await response.Content.ReadAsJsonAsync <ConnConfResp>();

                Logger.LogInfo <AliceClient>($"Round ({RoundId}), Alice ({UniqueId}): Confirmed connection. Phase: {resp.CurrentPhase}.");

                var activeOutputs = new List <ActiveOutput>();
                if (resp.BlindedOutputSignatures != null && resp.BlindedOutputSignatures.Any())
                {
                    var unblindedSignatures = new List <UnblindedSignature>();
                    var blindedSignatures   = resp.BlindedOutputSignatures.ToArray();
                    for (int i = 0; i < blindedSignatures.Length; i++)
                    {
                        uint256            blindedSignature   = blindedSignatures[i];
                        Requester          requester          = Requesters[i];
                        UnblindedSignature unblindedSignature = requester.UnblindSignature(blindedSignature);

                        var address = RegisteredAddresses[i];

                        uint256 outputScriptHash = new uint256(Hashes.SHA256(address.ScriptPubKey.ToBytes()));
                        PubKey  signerPubKey     = SchnorrPubKeys[i].SignerPubKey;
                        if (!VerifySignature(outputScriptHash, unblindedSignature, signerPubKey))
                        {
                            throw new NotSupportedException($"Coordinator did not sign the blinded output properly for level: {i}.");
                        }

                        unblindedSignatures.Add(unblindedSignature);
                    }

                    for (int i = 0; i < Math.Min(unblindedSignatures.Count, RegisteredAddresses.Length); i++)
                    {
                        var sig  = unblindedSignatures[i];
                        var addr = RegisteredAddresses[i];
                        var lvl  = i;

                        var actOut = new ActiveOutput(addr, sig, lvl);
                        activeOutputs.Add(actOut);
                    }
                }

                return(resp.CurrentPhase, activeOutputs);
            }
        }