Add phase logic
MODIFY
HiddenWallet.ChaumianTumbler/Global.cs
HiddenWallet.ChaumianTumbler/Global.cs
@@ -8,6 +8,8 @@ namespace HiddenWallet.ChaumianTumbler
{
public static class Global
{
+ public static Config Config;
+
public static TumblerStateMachine StateMachine;
private static string _dataDir = null;

MODIFY
HiddenWallet.ChaumianTumbler/Program.cs
HiddenWallet.ChaumianTumbler/Program.cs
@@ -17,12 +17,28 @@ namespace HiddenWallet.ChaumianTumbler
public static async Task Main(string[] args)
#pragma warning restore IDE1006 // Naming Styles
{
+ var configFilePath = Path.Combine(Global.DataDir, "Config.json");
+ if (File.Exists(configFilePath))
+ {
+ Global.Config = await Config.CreateFromFileAsync(configFilePath, CancellationToken.None);
+ }
+ else
+ {
+ Global.Config = new Config(
+ inputRegistrationPhaseTimeoutInSeconds: 86400, // one day
+ inputConfirmationPhaseTimeoutInSeconds: 60,
+ outputRegistrationPhaseTimeoutInSeconds: 60,
+ signingPhaseTimeoutInSeconds: 60);
+ await Global.Config.ToFileAsync(configFilePath, CancellationToken.None);
+ Console.WriteLine($"Config file did not exist. Created at path: {configFilePath}");
+ }
+
using (var host = WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build())
using (var ctsSource = new CancellationTokenSource())
+ using (Global.StateMachine = new TumblerStateMachine())
{
- Global.StateMachine = new TumblerStateMachine();
var stateMachineTask = Global.StateMachine.StartAsync(ctsSource.Token);
await host.RunAsync();
ctsSource.Cancel();

MODIFY
HiddenWallet.ChaumianTumbler/TumblerStateMachine.cs
HiddenWallet.ChaumianTumbler/TumblerStateMachine.cs
@@ -8,9 +8,53 @@ using System.Threading.Tasks;
namespace HiddenWallet.ChaumianTumbler
{
- public class TumblerStateMachine
+ public class TumblerStateMachine : IDisposable
{
public string Phase { get; private set; } = TumblerPhase.InputRegistration;
+
+ private CancellationTokenSource _ctsSourcePhaseCancel = new CancellationTokenSource();
+
+ public void UpdatePhase(string phase)
+ {
+ if (phase == Phase) return;
+
+ Phase = phase;
+ _ctsSourcePhaseCancel.Cancel();
+ _ctsSourcePhaseCancel = new CancellationTokenSource();
+ Console.WriteLine($"NEW PHASE: {phase}");
+ }
+
+ public void AdvancePhase()
+ {
+ switch (Phase)
+ {
+ case TumblerPhase.InputRegistration:
+ {
+ UpdatePhase(TumblerPhase.InputConfirmation);
+ break;
+ }
+ case TumblerPhase.InputConfirmation:
+ {
+ UpdatePhase(TumblerPhase.OutputRegistration);
+ break;
+ }
+ case TumblerPhase.OutputRegistration:
+ {
+ UpdatePhase(TumblerPhase.Signing);
+ break;
+ }
+ case TumblerPhase.Signing:
+ {
+ UpdatePhase(TumblerPhase.InputRegistration);
+ break;
+ }
+ default:
+ {
+ throw new NotSupportedException("This should never happen");
+ }
+ }
+ }
+
public async Task StartAsync(CancellationToken cancel)
{
while (true)
@@ -23,18 +67,38 @@ namespace HiddenWallet.ChaumianTumbler
{
case TumblerPhase.InputRegistration:
{
+ using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancel, _ctsSourcePhaseCancel.Token))
+ {
+ await Task.Delay(TimeSpan.FromSeconds(Global.Config.InputRegistrationPhaseTimeoutInSeconds), cts.Token).ContinueWith(t => { }); ;
+ }
+ AdvancePhase();
break;
}
case TumblerPhase.InputConfirmation:
{
+ using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancel, _ctsSourcePhaseCancel.Token))
+ {
+ await Task.Delay(TimeSpan.FromSeconds(Global.Config.InputRegistrationPhaseTimeoutInSeconds), cts.Token).ContinueWith(t => { }); ;
+ }
+ AdvancePhase();
break;
}
case TumblerPhase.OutputRegistration:
{
+ using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancel, _ctsSourcePhaseCancel.Token))
+ {
+ await Task.Delay(TimeSpan.FromSeconds(Global.Config.InputRegistrationPhaseTimeoutInSeconds), cts.Token).ContinueWith(t => { }); ;
+ }
+ AdvancePhase();
break;
}
case TumblerPhase.Signing:
{
+ using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancel, _ctsSourcePhaseCancel.Token))
+ {
+ await Task.Delay(TimeSpan.FromSeconds(Global.Config.InputRegistrationPhaseTimeoutInSeconds), cts.Token).ContinueWith(t => { }); ;
+ }
+ AdvancePhase();
break;
}
default:
@@ -45,9 +109,44 @@ namespace HiddenWallet.ChaumianTumbler
}
catch (Exception ex)
{
- Debug.WriteLine($"Ignoring {nameof(TumblerStateMachine)} exception: {ex}");
+ Console.WriteLine($"Ignoring {nameof(TumblerStateMachine)} exception: {ex}");
+ }
}
}
+
+ #region IDisposable Support
+ private bool _disposedValue = false; // To detect redundant calls
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposedValue)
+ {
+ if (disposing)
+ {
+ _ctsSourcePhaseCancel?.Dispose();
+ }
+
+ // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
+ // TODO: set large fields to null.
+
+ _disposedValue = true;
+ }
+ }
+
+ // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
+ // ~TumblerStateMachine() {
+ // // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
+ // Dispose(false);
+ // }
+
+ // This code added to correctly implement the disposable pattern.
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
+ Dispose(true);
+ // TODO: uncomment the following line if the finalizer is overridden above.
+ // GC.SuppressFinalize(this);
}
+ #endregion
}
}

Add phase logic