Refactor inputs to coins:
MODIFY
WalletWasabi.Backend/Controllers/ChaumianCoinJoinController.cs
WalletWasabi.Backend/Controllers/ChaumianCoinJoinController.cs
@@ -132,13 +132,13 @@ namespace WalletWasabi.Backend.Controllers
return BadRequest($"Invalid ChangeOutputAddress. Details: {ex.Message}");
}
- var inputs = new HashSet<(OutPoint OutPoint, TxOut Output)>();
+ var inputs = new HashSet<Coin>();
var alicesToRemove = new HashSet<Guid>();
foreach (InputProofModel inputProof in request.Inputs)
{
- if (inputs.Any(x => x.OutPoint == inputProof.Input))
+ if (inputs.Any(x => x.Outpoint == inputProof.Input))
{
return BadRequest("Cannot register an input twice.");
}
@@ -222,11 +222,11 @@ namespace WalletWasabi.Backend.Controllers
return BadRequest("Provided proof is invalid.");
}
- inputs.Add((inputProof.Input.ToOutPoint(), txout));
+ inputs.Add(new Coin(inputProof.Input.ToOutPoint(), txout));
}
// Check if inputs have enough coins.
- Money inputSum = inputs.Select(x => x.Output.Value).Sum();
+ Money inputSum = inputs.Sum(x => x.Amount);
Money networkFeeToPay = (inputs.Count() * round.FeePerInputs) + (2 * round.FeePerOutputs);
Money changeAmount = inputSum - (round.Denomination + networkFeeToPay);
if (changeAmount < Money.Zero)
@@ -338,7 +338,7 @@ namespace WalletWasabi.Backend.Controllers
if (alicesToBan.Any())
{
- await Coordinator.UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, alicesToBan.SelectMany(x => x.Inputs).Select(y => y.OutPoint).ToArray());
+ await Coordinator.UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, alicesToBan.SelectMany(x => x.Inputs).Select(y => y.Outpoint).ToArray());
}
int aliceCountAfterConnectionConfirmationTimeout = round.CountAlices();
@@ -630,9 +630,8 @@ namespace WalletWasabi.Backend.Controllers
cjCopy.Inputs[index].WitScript = witness;
// 3. Convert the current input to IndexedTxIn.
IndexedTxIn currentIndexedInput = cjCopy.Inputs.AsIndexedInputs().Skip(index).First();
- // 4. Find the corresponding registered input and convert it to Coin.
- (OutPoint OutPoint, TxOut Output) registeredInput = alice.Inputs.Single(x => x.OutPoint == cjCopy.Inputs[index].PrevOut);
- Coin registeredCoin = new Coin(registeredInput.OutPoint, registeredInput.Output);
+ // 4. Find the corresponding registered input.
+ Coin registeredCoin = alice.Inputs.Single(x => x.Outpoint == cjCopy.Inputs[index].PrevOut);
// 5. Verify if currentIndexedInput is correctly signed, if not, return the specific error.
if (!currentIndexedInput.VerifyScript(registeredCoin, out ScriptError error))
{

MODIFY
WalletWasabi/Models/ChaumianCoinJoin/Alice.cs
WalletWasabi/Models/ChaumianCoinJoin/Alice.cs
@@ -18,7 +18,7 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
public Money OutputSumWithoutCoordinatorFeeAndDenomination { get; }
- public IEnumerable<(OutPoint OutPoint, TxOut Output)> Inputs { get; }
+ public IEnumerable<Coin> Inputs { get; }
public BitcoinAddress ChangeOutputAddress { get; }
@@ -28,7 +28,7 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
public AliceState State { get; set; }
- public Alice(IEnumerable<(OutPoint OutPoint, TxOut Output)> inputs, Money networkFeeToPay, BitcoinAddress changeOutputAddress, string blindedOutputScriptHex)
+ public Alice(IEnumerable<Coin> inputs, Money networkFeeToPay, BitcoinAddress changeOutputAddress, string blindedOutputScriptHex)
{
Inputs = Guard.NotNullOrEmpty(nameof(inputs), inputs);
NetworkFeeToPay = Guard.NotNull(nameof(networkFeeToPay), networkFeeToPay);
@@ -39,7 +39,7 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
UniqueId = Guid.NewGuid();
- InputSum = inputs.Select(x => x.Output.Value).Sum();
+ InputSum = inputs.Sum(x => x.Amount);
OutputSumWithoutCoordinatorFeeAndDenomination = InputSum - NetworkFeeToPay;

MODIFY
WalletWasabi/Models/ChaumianCoinJoin/CcjRound.cs
WalletWasabi/Models/ChaumianCoinJoin/CcjRound.cs
@@ -225,7 +225,7 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
return;
}
- RoundHash = NBitcoinHelpers.HashOutpoints(Alices.SelectMany(x => x.Inputs).Select(y => y.OutPoint));
+ RoundHash = NBitcoinHelpers.HashOutpoints(Alices.SelectMany(x => x.Inputs).Select(y => y.Outpoint));
Phase = CcjRoundPhase.ConnectionConfirmation;
}
@@ -274,8 +274,8 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
{
foreach (var input in alice.Inputs)
{
- transaction.Inputs.Add(new TxIn(input.OutPoint));
- spentCoins.Add(new Coin(input.OutPoint, input.Output));
+ transaction.Inputs.Add(new TxIn(input.Outpoint));
+ spentCoins.Add(input);
}
Money changeAmount = alice.GetChangeAmount(newDenomination, coordinatorFeePerAlice);
if (changeAmount > Money.Zero) // If the coordinator fee would make change amount to be negative or zero then no need to pay it.
@@ -458,7 +458,7 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
IEnumerable<Alice> alicesToBan1 = GetAlicesBy(AliceState.InputsRegistered);
IEnumerable<Alice> alicesToBan2 = await RemoveAlicesIfInputsSpentAsync(); // So ban only those who confirmed participation, yet spent their inputs.
- IEnumerable<OutPoint> inputsToBan = alicesToBan1.SelectMany(x => x.Inputs).Select(y => y.OutPoint).Concat(alicesToBan2.SelectMany(x => x.Inputs).Select(y => y.OutPoint)).Distinct();
+ IEnumerable<OutPoint> inputsToBan = alicesToBan1.SelectMany(x => x.Inputs).Select(y => y.Outpoint).Concat(alicesToBan2.SelectMany(x => x.Inputs).Select(y => y.Outpoint)).Distinct();
if (inputsToBan.Any())
{
@@ -499,7 +499,7 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
{
if (alice.State != AliceState.SignedCoinJoin)
{
- outpointsToBan.AddRange(alice.Inputs.Select(x => x.OutPoint));
+ outpointsToBan.AddRange(alice.Inputs.Select(x => x.Outpoint));
}
}
}
@@ -612,7 +612,7 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
{
foreach (Alice alice in Alices)
{
- if (alice.Inputs.Any(x => x.OutPoint == input))
+ if (alice.Inputs.Any(x => x.Outpoint == input))
{
alices.Add(alice);
}
@@ -723,7 +723,7 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
try
{
- Coin[] spentCoins = Alices.SelectMany(x => x.Inputs.Select(y => new Coin(y.OutPoint, y.Output))).ToArray();
+ Coin[] spentCoins = Alices.SelectMany(x => x.Inputs).ToArray();
Money networkFee = SignedCoinJoin.GetFee(spentCoins);
Logger.LogInfo<CcjRound>($"Round ({RoundId}): Network Fee: {networkFee.ToString(false, false)} BTC.");
Logger.LogInfo<CcjRound>($"Round ({RoundId}): Coordinator Fee: {SignedCoinJoin.Outputs.SingleOrDefault(x => x.ScriptPubKey == Constants.GetCoordinatorAddress(Network).ScriptPubKey)?.Value?.ToString(false, false) ?? "0"} BTC.");
@@ -831,7 +831,7 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
foreach (Alice alice in Alices)
{
- foreach (OutPoint input in alice.Inputs.Select(y => y.OutPoint))
+ foreach (OutPoint input in alice.Inputs.Select(y => y.Outpoint))
{
GetTxOutResponse getTxOutResponse = await RpcClient.GetTxOutAsync(input.Hash, (int)input.N, includeMempool: true);
@@ -883,7 +883,7 @@ namespace WalletWasabi.Models.ChaumianCoinJoin
{
throw new InvalidOperationException("Removing Alice is only allowed in InputRegistration and ConnectionConfirmation phases.");
}
- numberOfRemovedAlices = Alices.RemoveAll(x => x.Inputs.Any(y => y.OutPoint == input));
+ numberOfRemovedAlices = Alices.RemoveAll(x => x.Inputs.Any(y => y.Outpoint == input));
}
Logger.LogInfo<CcjRound>($"Round ({RoundId}): {numberOfRemovedAlices} alices are removed.");

MODIFY
WalletWasabi/Services/CcjCoordinator.cs
WalletWasabi/Services/CcjCoordinator.cs
@@ -211,7 +211,7 @@ namespace WalletWasabi.Services
foreach (Alice alice in round.GetAlicesByNot(AliceState.SignedCoinJoin, syncLock: false)) // Because the event sometimes is raised from inside the lock.
{
// If its from any coinjoin, then don't ban.
- IEnumerable<OutPoint> utxosToBan = alice.Inputs.Select(x => x.OutPoint);
+ IEnumerable<OutPoint> utxosToBan = alice.Inputs.Select(x => x.Outpoint);
await UtxoReferee.BanUtxosAsync(1, DateTimeOffset.UtcNow, utxosToBan.ToArray());
}
}

Refactor inputs to coins: https://github.com/zkSNACKs/WalletWasabi/issues/716#issuecomment-433697113