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); } }