public async Task <IEnumerable <Alice> > RemoveAlicesIfInputsSpentAsync() { var alicesRemoved = new List <Alice>(); using (RoundSyncronizerLock.Lock()) { if ((Phase != CcjRoundPhase.InputRegistration && Phase != CcjRoundPhase.ConnectionConfirmation) || Status != CcjRoundStatus.Running) { throw new InvalidOperationException("Removing Alice is only allowed in InputRegistration and ConnectionConfirmation phases."); } foreach (Alice alice in Alices) { foreach (OutPoint input in alice.Inputs.Select(y => y.OutPoint)) { GetTxOutResponse getTxOutResponse = await RpcClient.GetTxOutAsync(input.Hash, (int)input.N, includeMempool : true); // Check if inputs are unspent. if (getTxOutResponse == null) { alicesRemoved.Add(alice); Alices.Remove(alice); } } } } foreach (var alice in alicesRemoved) { Logger.LogInfo <CcjRound>($"Round ({RoundId}): Alice ({alice.UniqueId}) removed."); } return(alicesRemoved); }
public void StartAliceTimeout(Guid uniqueId) { // 1. Find Alice and set its LastSeen propery. var foundAlice = false; var started = DateTimeOffset.UtcNow; using (RoundSyncronizerLock.Lock()) { if (Phase != CcjRoundPhase.InputRegistration || Status != CcjRoundStatus.Running) { return; // Then no need to timeout alice. } Alice alice = Alices.SingleOrDefault(x => x.UniqueId == uniqueId); foundAlice = alice != default(Alice); if (foundAlice) { alice.LastSeen = started; } } if (foundAlice) { Task.Run(async() => { // 2. Delay asyncronously to the requested timeout await Task.Delay(AliceRegistrationTimeout); using (await RoundSyncronizerLock.LockAsync()) { // 3. If the round is still running and the phase is still InputRegistration if (Status == CcjRoundStatus.Running && Phase == CcjRoundPhase.InputRegistration) { Alice alice = Alices.SingleOrDefault(x => x.UniqueId == uniqueId); if (alice != default(Alice)) { // 4. If LastSeen isn't changed by then, remove Alice. if (alice.LastSeen == started) { Alices.Remove(alice); Logger.LogInfo <CcjRound>($"Round ({RoundId}): Alice ({alice.UniqueId}) timed out."); } } } } }); } }