Implement `output` post request
MODIFY
HiddenWallet.ChaumianTumbler/Controllers/TumblerController.cs
HiddenWallet.ChaumianTumbler/Controllers/TumblerController.cs
@@ -230,12 +230,17 @@ namespace HiddenWallet.ChaumianTumbler.Controllers
alice.State = AliceState.ConnectionConfirmed;
+ try
+ {
+ return new ObjectResult(new SuccessResponse());
+ }
+ finally
+ {
if (Global.StateMachine.Alices.All(x => x.State == AliceState.ConnectionConfirmed))
{
Global.StateMachine.UpdatePhase(TumblerPhase.OutputRegistration);
}
-
- return new ObjectResult(new SuccessResponse());
+ }
}
catch (Exception ex)
{
@@ -254,9 +259,30 @@ namespace HiddenWallet.ChaumianTumbler.Controllers
return new ObjectResult(new FailureResponse { Message = "Wrong phase", Details = "" });
}
- if (request.SignedOutput == null) return new BadRequestResult();
+ if (request.Output == null) return new BadRequestResult();
+ if (request.Signature == null) return new BadRequestResult();
+
+ var output = new BitcoinWitPubKeyAddress(request.Output, expectedNetwork: Global.Config.Network);
- throw new NotImplementedException();
+ if(Global.RsaKey.PubKey.Verify(HexHelpers.GetBytes(request.Signature), HexHelpers.GetBytes(request.Output)))
+ {
+ try
+ {
+ Global.StateMachine.Bobs.Add(new Bob { Output = output });
+ return new ObjectResult(new SuccessResponse());
+ }
+ finally
+ {
+ if (Global.StateMachine.Alices.Count == Global.StateMachine.Bobs.Count)
+ {
+ Global.StateMachine.UpdatePhase(TumblerPhase.OutputRegistration);
+ }
+ }
+ }
+ else
+ {
+ throw new ArgumentException("Bad output");
+ }
}
catch (Exception ex)
{

MODIFY
HiddenWallet.ChaumianTumbler/Models/OutputRequest.cs
HiddenWallet.ChaumianTumbler/Models/OutputRequest.cs
@@ -7,6 +7,7 @@ namespace HiddenWallet.ChaumianTumbler.Models
{
public class OutputRequest
{
- public string SignedOutput { get; set; }
+ public string Output { get; set; }
+ public string Signature { get; set; }
}
}

MODIFY
HiddenWallet.ChaumianTumbler/TumblerStateMachine.cs
HiddenWallet.ChaumianTumbler/TumblerStateMachine.cs
@@ -30,6 +30,7 @@ namespace HiddenWallet.ChaumianTumbler
private SmartBitClient SmartBitClient { get; }
public ConcurrentHashSet<Alice> Alices { get; internal set; }
+ public ConcurrentHashSet<Bob> Bobs { get; internal set; }
private TumblerPhaseBroadcaster _broadcaster = TumblerPhaseBroadcaster.Instance;
@@ -71,6 +72,7 @@ namespace HiddenWallet.ChaumianTumbler
case TumblerPhase.InputRegistration:
{
Alices = new ConcurrentHashSet<Alice>();
+ Bobs = new ConcurrentHashSet<Bob>();
var denominationTask = SetDenominationAsync(cancel);
var feeTask = SetFeesAsync(cancel);
CalculateAnonymitySet();
@@ -117,6 +119,9 @@ namespace HiddenWallet.ChaumianTumbler
{
await Task.Delay(TimeSpan.FromSeconds((int)Global.Config.OutputRegistrationPhaseTimeoutInSeconds), cts.Token).ContinueWith(t => { });
}
+ // Output registration never falls back
+ // We don't know which Alice to ban
+ // Therefore proceed to signing, and whichever Alice doesn't sign ban
UpdatePhase(TumblerPhase.Signing);
break;
}

Implement `output` post request