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

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

            RoundPhase phase = round.Phase;

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

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

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

                int takeBlindCount = round.EstimateBestMixingLevel(alice);

                alice.BlindedOutputScripts    = alice.BlindedOutputScripts.Take(takeBlindCount).ToArray();
                alice.BlindedOutputSignatures = alice.BlindedOutputSignatures.Take(takeBlindCount).ToArray();
                resp.BlindedOutputSignatures  = alice.BlindedOutputSignatures;                                // Do not 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, RoundPhase.ConnectionConfirmation);
                return(Gone($"Participation can be only confirmed from InputRegistration or ConnectionConfirmation phase. Current phase: {phase}."));
            }
            }

            return(Ok(resp));
        }
Ejemplo n.º 2
0
        public async Task <(RoundPhase 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}").ConfigureAwait(false);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                await response.ThrowRequestExceptionFromContentAsync().ConfigureAwait(false);
            }

            ConnectionConfirmationResponse resp = await response.Content.ReadAsJsonAsync <ConnectionConfirmationResponse>().ConfigureAwait(false);

            Logger.LogInfo($"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);
        }
Ejemplo n.º 3
0
        public async Task <IActionResult> PostConfirmationAsync([FromQuery, Required] string uniqueId, [FromQuery, Required] long roundId)
        {
            if (roundId < 0 || !ModelState.IsValid)
            {
                return(BadRequest());
            }

            using (await CoordinatorRound.ConnectionConfirmationLock.LockAsync())
            {
                (CoordinatorRound round, Alice alice) = GetRunningRoundAndAliceOrFailureResponse(roundId, uniqueId, RoundPhase.ConnectionConfirmation, out IActionResult returnFailureResponse);
                if (returnFailureResponse != null)
                {
                    return(returnFailureResponse);
                }

                RoundPhase phase = round.Phase;

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

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

                case RoundPhase.ConnectionConfirmation:
                {
                    resp.BlindedOutputSignatures = await round.ConfirmAliceConnectionAsync(alice);

                    break;
                }

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

                return(Ok(resp));
            }
        }
        public async Task <(RoundPhase currentPhase, IEnumerable <ActiveOutput> activeOutputs)> PostConfirmationAsync()
        {
            using HttpResponseMessage response = await TorClient.SendAsync(HttpMethod.Post, $"/api/v{WasabiClient.ApiVersion}/btc/chaumiancoinjoin/confirmation?uniqueId={UniqueId}&roundId={RoundId}").ConfigureAwait(false);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                await response.ThrowRequestExceptionFromContentAsync().ConfigureAwait(false);
            }

            ConnectionConfirmationResponse resp = await response.Content.ReadAsJsonAsync <ConnectionConfirmationResponse>().ConfigureAwait(false);

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

            var activeOutputs = new List <ActiveOutput>();

            if (resp.BlindedOutputSignatures is { } && resp.BlindedOutputSignatures.Any())
Ejemplo n.º 5
0
        public async Task <IActionResult> PostConfirmationAsync([FromQuery, Required] string uniqueId, [FromQuery, Required] long roundId)
        {
            if (roundId < 0 || !ModelState.IsValid)
            {
                return(BadRequest());
            }

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

            RoundPhase phase = round.Phase;

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

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

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

                int takeBlindCount = round.EstimateBestMixingLevel(alice);

                alice.BlindedOutputScripts    = alice.BlindedOutputScripts[..takeBlindCount];