Skip to content

Commit

Permalink
Remove plebsDontPay (WalletWasabi#13219)
Browse files Browse the repository at this point in the history
  • Loading branch information
lontivero authored Jul 2, 2024
1 parent 432c55a commit bf98ee0
Show file tree
Hide file tree
Showing 18 changed files with 33 additions and 63 deletions.
7 changes: 3 additions & 4 deletions WalletWasabi.Tests/UnitTests/Bases/ConfigManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task CheckFileChangeTestAsync()
// Change coordination fee rate.
{
// Double coordination fee rate.
config.CoordinationFeeRate = new CoordinationFeeRate(rate: 0.006m, plebsDontPayThreshold: Money.Coins(0.01m));
config.CoordinationFeeRate = new CoordinationFeeRate(rate: 0.006m);

// Change should be detected.
Assert.True(ConfigManager.CheckFileChange(configPath, config));
Expand All @@ -56,7 +56,7 @@ public async Task CheckFileChangeTestAsync()
Assert.Equal(expectedFileContents, actualFileContents);
}

static string GetVanillaConfigString(decimal coordinationFeeRate = 0.003m)
static string GetVanillaConfigString(decimal coordinationFeeRate = 0.0m)
=> $$"""
{
"ConfirmationTarget": 108,
Expand Down Expand Up @@ -84,8 +84,7 @@ static string GetVanillaConfigString(decimal coordinationFeeRate = 0.003m)
"MinInputCountByBlameRoundMultiplier": 0.4,
"RoundDestroyerThreshold": 375,
"CoordinationFeeRate": {
"Rate": {{coordinationFeeRate}},
"PlebsDontPayThreshold": 1000000
"Rate": {{coordinationFeeRate}}
},
"CoordinatorExtPubKey": "xpub6C13JhXzjAhVRgeTcRSWqKEPe1vHi3Tmh2K9PN1cZaZFVjjSaj76y5NNyqYjc2bugj64LVDFYu8NZWtJsXNYKFb9J94nehLAPAKqKiXcebC",
"CoordinatorExtPubKeyCurrentDepth": 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ await bobClient.RegisterOutputAsync(
Assert.Equal(Phase.TransactionSigning, round.Phase);
var tx = round.Assert<SigningState>().CreateTransaction();
Assert.Equal(2, tx.Inputs.Count);
Assert.Equal(2 + 1, tx.Outputs.Count); // +1 for the coordinator fee
Assert.Equal(2, tx.Outputs.Count);

await arena.StopAsync(token);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public async Task SuccessAsync()
var arenaClient = WabiSabiFactory.CreateArenaClient(arena);
var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id);

var (resp, _) = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
var resp = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
AssertSingleAliceSuccessfullyRegistered(round, minAliceDeadline, resp);

await arena.StopAsync(CancellationToken.None);
Expand Down Expand Up @@ -69,7 +69,7 @@ public async Task SuccessCustomCoordinatorIdentifierAsync()
arena);
var ownershipProof = OwnershipProof.GenerateCoinJoinInputProof(key, new OwnershipIdentifier(key, key.PubKey.GetScriptPubKey(ScriptPubKeyType.Segwit)), new CoinJoinInputCommitmentData("test", round.Id), ScriptPubKeyType.Segwit);

var (resp, _) = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
var resp = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
AssertSingleAliceSuccessfullyRegistered(round, minAliceDeadline, resp);

await arena.StopAsync(CancellationToken.None);
Expand All @@ -92,12 +92,9 @@ public async Task SuccessFromPreviousCoinJoinAsync()
var arenaClient = WabiSabiFactory.CreateArenaClient(arena);
var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id);

var (resp, _) = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
var resp = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
AssertSingleAliceSuccessfullyRegistered(round, minAliceDeadline, resp);

var myAlice = Assert.Single(round.Alices);
Assert.True(myAlice.IsCoordinationFeeExempted);

await arena.StopAsync(CancellationToken.None);
}

Expand Down Expand Up @@ -140,7 +137,7 @@ public async Task TaprootSuccessAsync()
var arenaClient = WabiSabiFactory.CreateArenaClient(arena);
var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id, ScriptPubKeyType.TaprootBIP86);

var (resp, _) = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
var resp = await arenaClient.RegisterInputAsync(round.Id, coin.Outpoint, ownershipProof, CancellationToken.None);
AssertSingleAliceSuccessfullyRegistered(round, minAliceDeadline, resp);

await arena.StopAsync(CancellationToken.None);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ private async Task TestFullCoinjoinAsync(ScriptPubKeyType scriptPubKeyType, int
wabiSabiApi);
var ownershipProof = WabiSabiFactory.CreateOwnershipProof(key, round.Id, scriptPubKeyType);

var (inputRegistrationResponse, _) = await aliceArenaClient.RegisterInputAsync(round.Id, outpoint, ownershipProof, CancellationToken.None);
var inputRegistrationResponse = await aliceArenaClient.RegisterInputAsync(round.Id, outpoint, ownershipProof, CancellationToken.None);
var aliceId = inputRegistrationResponse.Value;

var amountsToRequest = new[]
Expand Down Expand Up @@ -285,6 +285,6 @@ await bobArenaClient.RegisterOutputAsync(

var tx = round.Assert<SigningState>().CreateTransaction();
Assert.Single(tx.Inputs);
Assert.Equal(2 + 1, tx.Outputs.Count); // +1 because it pays coordination fees
Assert.Equal(2, tx.Outputs.Count);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ public async Task RegisterCoinIdempotencyAsync()
RoundState round = rounds.First(x => x.CoinjoinState is ConstructionState);

var ownershipProof = WabiSabiFactory.CreateOwnershipProof(signingKey, round.Id);
var (response, _) = await apiClient.RegisterInputAsync(round.Id, coinToRegister.Outpoint, ownershipProof, CancellationToken.None);
var response = await apiClient.RegisterInputAsync(round.Id, coinToRegister.Outpoint, ownershipProof, CancellationToken.None);

Assert.NotEqual(Guid.Empty, response.Value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ public void FeeTests(int inputCount, int outputCount, string feeRateString)
Random random = new(12345);

FeeRate feeRate = new(satoshiPerByte: decimal.Parse(feeRateString));
CoordinationFeeRate coordinatorFeeRate = new(0m, Money.Zero);
CoordinationFeeRate coordinatorFeeRate = CoordinationFeeRate.Zero;

var parameters = WabiSabiFactory.CreateRoundParameters(new()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ public void InputRegistrationResponseMessageSerialization()
var message = new InputRegistrationResponse(
Guid.NewGuid(),
CreateCredentialsResponse(),
CreateCredentialsResponse(),
true);
CreateCredentialsResponse());

AssertSerialization(message);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ public static StrobeHasher Append(this StrobeHasher hasher, string fieldName, de
public static StrobeHasher Append(this StrobeHasher hasher, string fieldName, CoordinationFeeRate coordinationFeeRate)
=> hasher
.Append($"{fieldName}.Rate", coordinationFeeRate.Rate)
.Append($"{fieldName}.PlebsDontPayThreshold", coordinationFeeRate.PlebsDontPayThreshold);
.Append($"{fieldName}.PlebsDontPayThreshold", Money.Zero);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
using NBitcoin;
using System.ComponentModel;
using WalletWasabi.WabiSabi.Models;

namespace WalletWasabi.JsonConverters;

public class DefaultValueCoordinationFeeRateAttribute : DefaultValueAttribute
{
public DefaultValueCoordinationFeeRateAttribute(double feeRate, double plebsDontPayThreshold)
: base(new CoordinationFeeRate((decimal)feeRate, Money.Coins((decimal)plebsDontPayThreshold)))
public DefaultValueCoordinationFeeRateAttribute(double feeRate)
: base(new CoordinationFeeRate((decimal)feeRate))
{
}
}
4 changes: 1 addition & 3 deletions WalletWasabi/WabiSabi/Backend/Models/Alice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ public Alice(Coin coin, OwnershipProof ownershipProof, Round round, Guid id, boo
Coin = coin;
OwnershipProof = ownershipProof;
Id = id;
IsCoordinationFeeExempted = isCoordinationFeeExempted;
}

public Round Round { get; }
Expand All @@ -28,12 +27,11 @@ public Alice(Coin coin, OwnershipProof ownershipProof, Round round, Guid id, boo

public bool ConfirmedConnection { get; set; } = false;
public bool ReadyToSign { get; set; }
public bool IsCoordinationFeeExempted { get; } = false;

public long CalculateRemainingVsizeCredentials(int maxRegistrableSize) => maxRegistrableSize - TotalInputVsize;

public Money CalculateRemainingAmountCredentials(FeeRate feeRate, CoordinationFeeRate coordinationFeeRate) =>
Coin.EffectiveValue(feeRate, IsCoordinationFeeExempted ? CoordinationFeeRate.Zero : coordinationFeeRate);
Coin.EffectiveValue(feeRate, coordinationFeeRate);

public void SetDeadlineRelativeTo(TimeSpan connectionConfirmationTimeout)
{
Expand Down
3 changes: 1 addition & 2 deletions WalletWasabi/WabiSabi/Backend/Rounds/Arena.Partial.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,7 @@ private async Task<InputRegistrationResponse> RegisterInputCoreAsync(InputRegist

return new(alice.Id,
commitAmountCredentialResponse,
commitVsizeCredentialResponse,
alice.IsCoordinationFeeExempted);
commitVsizeCredentialResponse);
}
}

Expand Down
8 changes: 1 addition & 7 deletions WalletWasabi/WabiSabi/Backend/Rounds/Arena.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using WalletWasabi.Extensions;
using WalletWasabi.Logging;
using WalletWasabi.WabiSabi.Backend.DoSPrevention;
using WalletWasabi.Helpers;

namespace WalletWasabi.WabiSabi.Backend.Rounds;

Expand Down Expand Up @@ -627,7 +626,7 @@ public static ConstructionState AddCoordinationFee(Round round, ConstructionStat
var sizeToPayFor = coinjoin.EstimatedVsize + coordinatorScriptPubKey.EstimateOutputVsize();
var miningFee = round.Parameters.MiningFeeRate.GetFee(sizeToPayFor) + Money.Satoshis(1);

var expectedCoordinationFee = round.Alices.Where(a => !a.IsCoordinationFeeExempted).Sum(x => round.Parameters.CoordinationFeeRate.GetFee(x.Coin.Amount));
var expectedCoordinationFee = round.Alices.Sum(x => round.Parameters.CoordinationFeeRate.GetFee(x.Coin.Amount));
var availableCoordinationFee = coinjoin.Balance - miningFee;

round.LogInfo($"Expected coordination fee: {expectedCoordinationFee} - Available coordination: {availableCoordinationFee}.");
Expand Down Expand Up @@ -699,11 +698,6 @@ private SigningState FinalizeTransaction(uint256 roundId, ConstructionState cons
return signingState;
}

public override void Dispose()
{
base.Dispose();
}

/// <summary>
/// If too many inputs seem to misbehave, problem is probably on coordinator's side.
/// Don't ban in that case to avoid huge amount of false-positives.
Expand Down
4 changes: 2 additions & 2 deletions WalletWasabi/WabiSabi/Backend/WabiSabiConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ public WabiSabiConfig(string filePath) : base(filePath)
[JsonProperty(PropertyName = "RoundDestroyerThreshold", DefaultValueHandling = DefaultValueHandling.Populate)]
public int RoundDestroyerThreshold { get; set; } = 375;

[DefaultValueCoordinationFeeRate(0.003, 0.01)]
[DefaultValueCoordinationFeeRate(0.0)]
[JsonProperty(PropertyName = "CoordinationFeeRate", DefaultValueHandling = DefaultValueHandling.Populate)]
public CoordinationFeeRate CoordinationFeeRate { get; set; } = new CoordinationFeeRate(0.003m, Money.Coins(0.01m));
public CoordinationFeeRate CoordinationFeeRate { get; set; } = new(0.0m);

[JsonProperty(PropertyName = "CoordinatorExtPubKey")]
public ExtPubKey CoordinatorExtPubKey { get; private set; } = NBitcoinHelpers.BetterParseExtPubKey(Constants.WabiSabiFallBackCoordinatorExtPubKey);
Expand Down
11 changes: 4 additions & 7 deletions WalletWasabi/WabiSabi/Client/CoinJoin/Client/AliceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ private AliceClient(
ArenaClient arenaClient,
SmartCoin coin,
IEnumerable<Credential> issuedAmountCredentials,
IEnumerable<Credential> issuedVsizeCredentials,
bool isCoordinationFeeExempted)
IEnumerable<Credential> issuedVsizeCredentials)
{
var roundParameters = roundState.CoinjoinState.Parameters;
AliceId = aliceId;
Expand All @@ -38,7 +37,6 @@ private AliceClient(
IssuedVsizeCredentials = issuedVsizeCredentials;
MaxVsizeAllocationPerAlice = roundParameters.MaxVsizeAllocationPerAlice;
ConfirmationTimeout = roundParameters.ConnectionConfirmationTimeout / 2;
IsCoordinationFeeExempted = isCoordinationFeeExempted;
}

public Guid AliceId { get; }
Expand All @@ -51,7 +49,6 @@ private AliceClient(
public IEnumerable<Credential> IssuedVsizeCredentials { get; private set; }
private long MaxVsizeAllocationPerAlice { get; }
private TimeSpan ConfirmationTimeout { get; }
public bool IsCoordinationFeeExempted { get; }

public DateTimeOffset LastSuccessfulInputConnectionConfirmation { get; private set; } = DateTimeOffset.UtcNow;

Expand Down Expand Up @@ -110,8 +107,8 @@ private static async Task<AliceClient> RegisterInputAsync(RoundState roundState,
coin,
new CoinJoinInputCommitmentData(arenaClient.CoordinatorIdentifier, roundState.Id));

var (response, isCoordinationFeeExempted) = await arenaClient.RegisterInputAsync(roundState.Id, coin.Coin.Outpoint, ownershipProof, cancellationToken).ConfigureAwait(false);
aliceClient = new(response.Value, roundState, arenaClient, coin, response.IssuedAmountCredentials, response.IssuedVsizeCredentials, isCoordinationFeeExempted);
var response = await arenaClient.RegisterInputAsync(roundState.Id, coin.Coin.Outpoint, ownershipProof, cancellationToken).ConfigureAwait(false);
aliceClient = new(response.Value, roundState, arenaClient, coin, response.IssuedAmountCredentials, response.IssuedVsizeCredentials);
coin.CoinJoinInProgress = true;

Logger.LogInfo($"Round ({roundState.Id}), Alice ({aliceClient.AliceId}): Registered {coin.Outpoint}.");
Expand Down Expand Up @@ -219,5 +216,5 @@ public async Task ReadyToSignAsync(CancellationToken cancellationToken)
Logger.LogInfo($"Round ({RoundId}), Alice ({AliceId}): Ready to sign.");
}

public Money EffectiveValue => SmartCoin.EffectiveValue(FeeRate, IsCoordinationFeeExempted ? CoordinationFeeRate.Zero : CoordinationFeeRate);
public Money EffectiveValue => SmartCoin.EffectiveValue(FeeRate, CoordinationFeeRate);
}
4 changes: 2 additions & 2 deletions WalletWasabi/WabiSabi/Client/CoinJoin/Client/ArenaClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public ArenaClient(
public string CoordinatorIdentifier { get; }
public IWabiSabiApiRequestHandler RequestHandler { get; }

public async Task<(ArenaResponse<Guid> ArenaResponse, bool IsCoordinationFeeExempted)> RegisterInputAsync(
public async Task<ArenaResponse<Guid>> RegisterInputAsync(
uint256 roundId,
OutPoint outPoint,
OwnershipProof ownershipProof,
Expand All @@ -53,7 +53,7 @@ public ArenaClient(
var realAmountCredentials = AmountCredentialClient.HandleResponse(inputRegistrationResponse.AmountCredentials, zeroAmountCredentialRequestData.CredentialsResponseValidation);
var realVsizeCredentials = VsizeCredentialClient.HandleResponse(inputRegistrationResponse.VsizeCredentials, zeroVsizeCredentialRequestData.CredentialsResponseValidation);

return (new(inputRegistrationResponse.AliceId, realAmountCredentials, realVsizeCredentials), inputRegistrationResponse.IsCoordinationFeeExempted);
return new(inputRegistrationResponse.AliceId, realAmountCredentials, realVsizeCredentials);
}

public async Task RemoveInputAsync(uint256 roundId, Guid aliceId, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ private void LogCoinJoinSummary(ImmutableArray<AliceClient> registeredAliceClien
var inputNetworkFee = Money.Satoshis(registeredAliceClients.Sum(alice => feeRate.GetFee(alice.SmartCoin.Coin.ScriptPubKey.EstimateInputVsize())));
var outputNetworkFee = Money.Satoshis(myOutputs.Sum(output => feeRate.GetFee(output.ScriptPubKey.EstimateOutputVsize())));
var totalNetworkFee = inputNetworkFee + outputNetworkFee;
var totalCoordinationFee = Money.Satoshis(registeredAliceClients.Where(a => !a.IsCoordinationFeeExempted).Sum(a => roundParameters.CoordinationFeeRate.GetFee(a.SmartCoin.Amount)));
var totalCoordinationFee = Money.Satoshis(registeredAliceClients.Sum(a => roundParameters.CoordinationFeeRate.GetFee(a.SmartCoin.Amount)));

string[] summary = new string[]
{
Expand Down
19 changes: 4 additions & 15 deletions WalletWasabi/WabiSabi/Models/CoordinationFeeRate.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
using NBitcoin;
using WalletWasabi.Helpers;

namespace WalletWasabi.WabiSabi.Models;

public readonly struct CoordinationFeeRate
{
public static readonly CoordinationFeeRate Zero = new(0, Money.Zero);
public static readonly CoordinationFeeRate Zero = new(0);

public CoordinationFeeRate(decimal rate, Money plebsDontPayThreshold)
public CoordinationFeeRate(decimal rate)
{
Rate = Guard.InRangeAndNotNull(nameof(rate), rate, 0m, 0.01m);
PlebsDontPayThreshold = plebsDontPayThreshold ?? Money.Zero;
Rate = rate >= 0 ? rate : throw new ArgumentOutOfRangeException(nameof(rate));
}

public decimal Rate { get; }
public Money PlebsDontPayThreshold { get; }

public Money GetFee(Money amount)
{
// Plebs don't have to pay.
if (amount <= PlebsDontPayThreshold)
{
return Money.Zero;
}
else
{
return Money.Satoshis(Math.Floor(amount.Satoshi * Rate));
}
return Money.Satoshis(Math.Floor(amount.Satoshi * Rate));
}
}
3 changes: 1 addition & 2 deletions WalletWasabi/WabiSabi/Models/InputRegistrationResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ namespace WalletWasabi.WabiSabi.Models;
public record InputRegistrationResponse(
Guid AliceId,
CredentialsResponse AmountCredentials,
CredentialsResponse VsizeCredentials,
[property: JsonProperty("isPayingZeroCoordinationFee")] bool IsCoordinationFeeExempted
CredentialsResponse VsizeCredentials
);

0 comments on commit bf98ee0

Please sign in to comment.