Fix blame output fee.
First, someone has to pay for the common overhead, otherwise all the math is wrong.
Second, the balance and effective feerate were not taking the shared overhead into account.
MODIFY
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
@@ -554,7 +554,8 @@ public partial class Arena : PeriodicRunner
{
// If timeout we must fill up the outputs to build a reasonable transaction.
// This won't be signed by the alice who failed to provide output, so we know who to ban.
- var diffMoney = coinjoin.Balance - round.Parameters.MiningFeeRate.GetFee(blameScript.EstimateOutputVsize());
+ var estimatedBlameScriptCost = round.Parameters.MiningFeeRate.GetFee(blameScript.EstimateOutputVsize() + MultipartyTransactionParameters.SharedOverhead);
+ var diffMoney = coinjoin.Balance - coinjoin.EstimatedCost - estimatedBlameScriptCost;
if (diffMoney > round.Parameters.AllowedOutputAmounts.Min)
{
// If diff is smaller than max fee rate of a tx, then add it as fee.
@@ -563,7 +564,7 @@ public partial class Arena : PeriodicRunner
// ToDo: This condition could be more sophisticated by always trying to max out the miner fees to target 2 and only deal with the remaining diffMoney.
if (coinjoin.EffectiveFeeRate > highestFeeRate)
{
- coinjoin = coinjoin.AddOutput(new TxOut(diffMoney, blameScript));
+ coinjoin = coinjoin.AddOutput(new TxOut(diffMoney, blameScript)).AsPayingForSharedOverhead();
if (allReady)
{

MODIFY
WalletWasabi/WabiSabi/Models/MultipartyTransaction/ConstructionState.cs
WalletWasabi/WabiSabi/Models/MultipartyTransaction/ConstructionState.cs
@@ -112,4 +112,10 @@ public record ConstructionState : MultipartyTransactionState
return new SigningState(Parameters, Events);
}
+
+ public ConstructionState AsPayingForSharedOverhead() =>
+ this with
+ {
+ UnpaidSharedOverhead = 0
+ };
}

MODIFY
WalletWasabi/WabiSabi/Models/MultipartyTransaction/MultipartyTransactionState.cs
WalletWasabi/WabiSabi/Models/MultipartyTransaction/MultipartyTransactionState.cs
@@ -43,12 +43,17 @@ public abstract record MultipartyTransactionState
[JsonIgnore]
public int EstimatedVsize => MultipartyTransactionParameters.SharedOverhead + EstimatedInputsVsize + OutputsVsize;
+ [JsonIgnore]
+ public Money EstimatedCost => Parameters.MiningFeeRate.GetFee(EstimatedVsize - UnpaidSharedOverhead);
+
+ [JsonIgnore] protected int UnpaidSharedOverhead { get; init; } = MultipartyTransactionParameters.SharedOverhead;
+
// With no coordinator fees we can't ensure that the shared overhead
// of the transaction also pays at the nominal feerate so this will have
// to do for now, but in the future EstimatedVsize should be used
// including the shared overhead
[JsonIgnore]
- public FeeRate EffectiveFeeRate => new(Balance, EstimatedInputsVsize + OutputsVsize);
+ public FeeRate EffectiveFeeRate => new(Balance, EstimatedVsize - UnpaidSharedOverhead);
public ImmutableList<IEvent> Events { get; init; } = ImmutableList<IEvent>.Empty;

Fix blame output fee.

- First, someone has to pay for the common overhead, otherwise all the math is wrong.
- Second, the balance and effective feerate were not taking the shared overhead into account.