mirror of
https://github.com/aljazceru/BTCPayServerPlugins.git
synced 2025-12-17 07:34:24 +01:00
ws update
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
using WalletWasabi.Blockchain.Analysis;
|
||||
@@ -17,6 +18,7 @@ using WalletWasabi.Models;
|
||||
using WalletWasabi.WabiSabi;
|
||||
using WalletWasabi.WabiSabi.Backend.Rounds;
|
||||
using WalletWasabi.WabiSabi.Client;
|
||||
using WalletWasabi.WabiSabi.Client.CoinJoin.Client;
|
||||
using WalletWasabi.WabiSabi.Client.StatusChangedEvents;
|
||||
using WalletWasabi.WabiSabi.Models;
|
||||
using WalletWasabi.WabiSabi.Models.MultipartyTransaction;
|
||||
@@ -35,28 +37,24 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
}
|
||||
|
||||
public async
|
||||
Task<(
|
||||
ImmutableList<SmartCoin> selected,
|
||||
Func<IEnumerable<AliceClient>, Task<bool>> acceptableRegistered,
|
||||
Func<
|
||||
ImmutableArray<AliceClient>,
|
||||
(IEnumerable<TxOut> outputTxOuts, Dictionary<TxOut, PendingPayment> batchedPayments),
|
||||
TransactionWithPrecomputedData,
|
||||
RoundState,
|
||||
Task<bool>> acceptableOutputs
|
||||
)>
|
||||
Task<(ImmutableList<SmartCoin> selected, Func<IEnumerable<AliceClient>, Task<bool>> acceptableRegistered, Func<
|
||||
ImmutableArray<AliceClient>, (IEnumerable<TxOut> outputTxOuts, Dictionary<TxOut, PendingPayment>
|
||||
batchedPayments), TransactionWithPrecomputedData, RoundState, Task<bool>> acceptableOutputs)>
|
||||
SelectCoinsAsync((IEnumerable<SmartCoin> Candidates, IEnumerable<SmartCoin> Ineligible) coinCandidates,
|
||||
UtxoSelectionParameters utxoSelectionParameters, Money liquidityClue, SecureRandom secureRandom)
|
||||
RoundParameters roundParameters, Money liquidityClue, SecureRandom secureRandom, string coordinatorName)
|
||||
{
|
||||
SmartCoin[] FilterCoinsMore(IEnumerable<SmartCoin> coins)
|
||||
var log = new StringBuilder();
|
||||
try
|
||||
{
|
||||
SmartCoin[] FilterCoinsMore(IEnumerable<SmartCoin> coins)
|
||||
{
|
||||
return coins
|
||||
.Where(coin => utxoSelectionParameters.AllowedInputScriptTypes.Contains(coin.ScriptType))
|
||||
.Where(coin => utxoSelectionParameters.AllowedInputAmounts.Contains(coin.Amount))
|
||||
.Where(coin => roundParameters.AllowedInputTypes.Contains(coin.ScriptType))
|
||||
.Where(coin => roundParameters.AllowedInputAmounts.Contains(coin.Amount))
|
||||
.Where(coin =>
|
||||
{
|
||||
var effV = coin.EffectiveValue(utxoSelectionParameters.MiningFeeRate,
|
||||
utxoSelectionParameters.CoordinationFeeRate);
|
||||
var effV = coin.EffectiveValue(roundParameters.MiningFeeRate,
|
||||
roundParameters.CoordinationFeeRate);
|
||||
var percentageLeft = (effV.ToDecimal(MoneyUnit.BTC) / coin.Amount.ToDecimal(MoneyUnit.BTC));
|
||||
// filter out low value coins where 50% of the value would be eaten up by fees
|
||||
return effV > Money.Zero && percentageLeft >= 0.5m;
|
||||
@@ -69,7 +67,7 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!coin.HdPubKey.Labels.Contains("coinjoin") || coin.HdPubKey.Labels.Contains(utxoSelectionParameters.CoordinatorName))
|
||||
if (!coin.HdPubKey.Labels.Contains("coinjoin") || coin.HdPubKey.Labels.Contains(coordinatorName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -78,7 +76,7 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
_wallet.WabisabiStoreSettings.CrossMixBetweenCoordinatorsMode ==
|
||||
WabisabiStoreSettings.CrossMixMode.WhenFree)
|
||||
{
|
||||
return coin.Amount <= utxoSelectionParameters.CoordinationFeeRate.PlebsDontPayThreshold;
|
||||
return coin.Amount <= roundParameters.CoordinationFeeRate.PlebsDontPayThreshold;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -93,7 +91,7 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
|
||||
var payments =
|
||||
(_wallet.BatchPayments
|
||||
? await _wallet.DestinationProvider.GetPendingPaymentsAsync(utxoSelectionParameters)
|
||||
? await _wallet.DestinationProvider.GetPendingPaymentsAsync(roundParameters)
|
||||
: Array.Empty<PendingPayment>()).ToArray();
|
||||
|
||||
var maxPerType = new Dictionary<AnonsetType, int>();
|
||||
@@ -113,7 +111,7 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
maxPerType.TryAdd(AnonsetType.Red, 1);
|
||||
}
|
||||
|
||||
var isLowFee = utxoSelectionParameters.MiningFeeRate.SatoshiPerByte <= _wallet.LowFeeTarget;
|
||||
var isLowFee = roundParameters.MiningFeeRate.SatoshiPerByte <= _wallet.LowFeeTarget;
|
||||
var consolidationMode = _wallet.ConsolidationMode switch
|
||||
{
|
||||
ConsolidationModeType.Always => true,
|
||||
@@ -122,19 +120,19 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
ConsolidationModeType.WhenLowFeeAndManyUTXO => isLowFee && candidates.Count() > BTCPayWallet.HighAmountOfCoins,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
var mixReasons = await _wallet.ShouldMix(utxoSelectionParameters.CoordinatorName, isLowFee, payments.Any());
|
||||
var mixReasons = await _wallet.ShouldMix(coordinatorName, isLowFee, payments.Any());
|
||||
if (!mixReasons.Any())
|
||||
{
|
||||
throw new CoinJoinClientException(CoinjoinError.NoCoinsEligibleToMix, "ShouldMix returned false, so we will not mix");
|
||||
}
|
||||
else
|
||||
{
|
||||
_wallet.LogDebug($"ShouldMix returned true for {mixReasons.Length} reasons: {string.Join(", ", mixReasons)}");
|
||||
log.AppendLine($"ShouldMix returned true for {mixReasons.Length} reasons: {string.Join(", ", mixReasons)}");
|
||||
}
|
||||
Dictionary<AnonsetType, int> idealMinimumPerType = new Dictionary<AnonsetType, int>()
|
||||
{{AnonsetType.Red, 1}, {AnonsetType.Orange, 1}, {AnonsetType.Green, 1}};
|
||||
|
||||
var solution = await SelectCoinsInternal(utxoSelectionParameters, candidates,payments,
|
||||
var solution = await SelectCoinsInternal(log,coordinatorName,roundParameters, candidates,payments,
|
||||
Random.Shared.Next(20, 31),
|
||||
maxPerType,
|
||||
idealMinimumPerType,
|
||||
@@ -158,7 +156,7 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
throw new CoinJoinClientException(CoinjoinError.NoCoinsEligibleToMix, "ShouldMix returned true only for consolidation, but less than 10 coins were found, so we will not mix");
|
||||
}
|
||||
|
||||
_wallet.LogTrace(solution.ToString());
|
||||
log.AppendLine(solution.ToString());
|
||||
|
||||
async Task<bool> AcceptableRegistered(IEnumerable<AliceClient> coins)
|
||||
{
|
||||
@@ -183,7 +181,7 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
var effectiveSumOfRegisteredCoins = coins.Sum(coin => coin.EffectiveValue);
|
||||
var canHandleAPayment = solution.HandledPayments.Any(payment =>
|
||||
{
|
||||
var cost = payment.ToTxOut().EffectiveCost(utxoSelectionParameters.MiningFeeRate) + payment.Value;
|
||||
var cost = payment.ToTxOut().EffectiveCost(roundParameters.MiningFeeRate) + payment.Value;
|
||||
return effectiveSumOfRegisteredCoins >= cost;
|
||||
});
|
||||
if (!canHandleAPayment)
|
||||
@@ -204,7 +202,7 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
|
||||
if (remainingMixReasons.Count != mixReasons.Length)
|
||||
{
|
||||
_wallet.LogDebug($"Some mix reasons were removed due to the difference in registered coins: {string.Join(", ", mixReasons.Except(remainingMixReasons))}. Remaining: {string.Join(", ", remainingMixReasons)}");
|
||||
log.AppendLine($"Some mix reasons were removed due to the difference in registered coins: {string.Join(", ", mixReasons.Except(remainingMixReasons))}. Remaining: {string.Join(", ", remainingMixReasons)}");
|
||||
}
|
||||
|
||||
return remainingMixReasons.Any();
|
||||
@@ -267,9 +265,20 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
}
|
||||
|
||||
return (solution.Coins.ToImmutableList(), AcceptableRegistered , AcceptableOutputs);
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(log.Length > 0)
|
||||
_wallet.LogInfo(coordinatorName, $"coinselection: {log}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<SubsetSolution> SelectCoinsInternal(UtxoSelectionParameters utxoSelectionParameters,
|
||||
private async Task<SubsetSolution> SelectCoinsInternal(
|
||||
StringBuilder log,
|
||||
string coordinatorName,
|
||||
RoundParameters utxoSelectionParameters,
|
||||
IEnumerable<SmartCoin> coins,
|
||||
IEnumerable<PendingPayment> pendingPayments,
|
||||
int maxCoins,
|
||||
@@ -392,14 +401,14 @@ public class BTCPayCoinjoinCoinSelector : IRoundCoinSelector
|
||||
|
||||
if (chance <= rand)
|
||||
{
|
||||
if (_wallet.MinimumDenominationAmount is not null &&
|
||||
Money.Coins(solution.LeftoverValue).Satoshi < _wallet.MinimumDenominationAmount)
|
||||
var minDenomAmount = Math.Min(_wallet.MinimumDenominationAmount ?? 0, _wallet.AllowedDenominations?.Any() is true? _wallet.AllowedDenominations.Min(): 0);
|
||||
if (minDenomAmount > 0 &&
|
||||
Money.Coins(solution.LeftoverValue).Satoshi < minDenomAmount)
|
||||
{
|
||||
_wallet.LogDebug(
|
||||
$"coin selection: leftover value {solution.LeftoverValue} is less than minimum denomination amount {_wallet.MinimumDenominationAmount} so we will try to add more coins");
|
||||
log.AppendLine($"leftover value {solution.LeftoverValue} is less than minimum denomination amount {minDenomAmount} so we will try to add more coins");
|
||||
continue;
|
||||
}
|
||||
_wallet.LogDebug($"coin selection: no payments left but at {solution.Coins.Count()} coins. random chance to add another coin if: {chance} > {rand} (random 0-100) continue: {chance > rand}");
|
||||
log.AppendLine($"no payments left but at {solution.Coins.Count()} coins. random chance to add another coin if: {chance} > {rand} (random 0-100) continue: {chance > rand}");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -473,9 +482,9 @@ public enum AnonsetType
|
||||
|
||||
public class SubsetSolution
|
||||
{
|
||||
private readonly UtxoSelectionParameters _utxoSelectionParameters;
|
||||
private readonly RoundParameters _utxoSelectionParameters;
|
||||
|
||||
public SubsetSolution(int totalPaymentsGross, IWallet wallet, UtxoSelectionParameters utxoSelectionParameters)
|
||||
public SubsetSolution(int totalPaymentsGross, IWallet wallet, RoundParameters utxoSelectionParameters)
|
||||
{
|
||||
_utxoSelectionParameters = utxoSelectionParameters;
|
||||
TotalPaymentsGross = totalPaymentsGross;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
@@ -21,6 +23,7 @@ using NBXplorer.DerivationStrategy;
|
||||
using NBXplorer.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using WabiSabi.Crypto.Randomness;
|
||||
using WalletWasabi.Blockchain.Analysis;
|
||||
using WalletWasabi.Blockchain.Analysis.Clustering;
|
||||
using WalletWasabi.Blockchain.Keys;
|
||||
@@ -69,6 +72,8 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
StoreRepository storeRepository,
|
||||
IMemoryCache memoryCache)
|
||||
{
|
||||
WalletId = new WalletWasabi.Wallets.WalletId(new Guid(SHA256.HashData(Encoding.UTF8.GetBytes(storeId)).Take(16)
|
||||
.ToArray()));
|
||||
KeyChain = keyChain;
|
||||
_walletRepository = walletRepository;
|
||||
_btcPayNetworkProvider = btcPayNetworkProvider;
|
||||
@@ -88,8 +93,8 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
}
|
||||
|
||||
public string StoreId { get; set; }
|
||||
public List<(DateTimeOffset time, Microsoft.Extensions.Logging.LogLevel level , string message)> LastLogs { get; private set; } = new();
|
||||
public void Log(LogLevel logLevel, string logMessage, string callerFilePath = "", string callerMemberName = "",
|
||||
public List<(DateTimeOffset time, Microsoft.Extensions.Logging.LogLevel level, string coordinator, string message)> LastLogs { get; private set; } = new();
|
||||
public void Log(LogLevel logLevel, string logMessage, string coordinator, string callerFilePath = "", string callerMemberName = "",
|
||||
int callerLineNumber = -1)
|
||||
{
|
||||
var ll = logLevel switch
|
||||
@@ -103,14 +108,20 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(logLevel))
|
||||
};
|
||||
if(LastLogs.FirstOrDefault().message != logMessage)
|
||||
LastLogs.Insert(0, (DateTimeOffset.Now, ll, logMessage) );
|
||||
LastLogs.Insert(0, (DateTimeOffset.Now, ll, coordinator, logMessage) );
|
||||
if (LastLogs.Count >= 500)
|
||||
LastLogs.RemoveLast();
|
||||
|
||||
if (coordinator != null)
|
||||
{
|
||||
logMessage = $"[{coordinator}] {logMessage}";
|
||||
}
|
||||
_logger.Log(ll, logMessage, callerFilePath, callerMemberName, callerLineNumber);
|
||||
}
|
||||
|
||||
public string WalletName => StoreId;
|
||||
|
||||
public WalletWasabi.Wallets.WalletId WalletId { get; }
|
||||
|
||||
public bool IsUnderPlebStop => !WabisabiStoreSettings.Active;
|
||||
|
||||
bool IWallet.IsMixable(string coordinator)
|
||||
@@ -122,6 +133,10 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
|
||||
public IKeyChain KeyChain { get; }
|
||||
public IDestinationProvider DestinationProvider => this;
|
||||
public OutputProvider GetOutputProvider(string coordinatorName)
|
||||
{
|
||||
return new OutputProvider(this, SecureRandom.Instance);
|
||||
}
|
||||
|
||||
public int AnonScoreTarget => WabisabiStoreSettings.PlebMode? 5: WabisabiStoreSettings.AnonymitySetTarget;
|
||||
public ConsolidationModeType ConsolidationMode =>
|
||||
@@ -141,6 +156,9 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
public bool BatchPayments => WabisabiStoreSettings.PlebMode || WabisabiStoreSettings.BatchPayments;
|
||||
public long? MinimumDenominationAmount => WabisabiStoreSettings.PlebMode? 10000 : WabisabiStoreSettings.MinimumDenominationAmount;
|
||||
|
||||
public long[]? AllowedDenominations =>
|
||||
WabisabiStoreSettings.PlebMode ? null : WabisabiStoreSettings.AllowedDenominations;
|
||||
|
||||
|
||||
|
||||
public async Task<IWallet.MixingReason[]> ShouldMix(string coordinatorName, bool? isLowFee = null,
|
||||
@@ -217,8 +235,8 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
|
||||
public double GetPrivacyPercentage(CoinsView coins, int privateThreshold)
|
||||
{
|
||||
var privateAmount = coins.FilterBy(x => x.IsPrivate(this)).TotalAmount();
|
||||
var normalAmount = coins.FilterBy(x => !x.IsPrivate(this)).TotalAmount();
|
||||
var privateAmount = new CoinsView(coins.Where(x => x.IsPrivate(this))).TotalAmount();
|
||||
var normalAmount = new CoinsView(coins.Where(x => !x.IsPrivate(this))).TotalAmount();
|
||||
|
||||
var privateDecimalAmount = privateAmount.ToDecimal(MoneyUnit.BTC);
|
||||
var normalDecimalAmount = normalAmount.ToDecimal(MoneyUnit.BTC);
|
||||
@@ -339,7 +357,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.LogError($"Could not compute coin candidate: {e.Message}");
|
||||
this.LogError(coordinatorName,$"Could not compute coin candidate: {e.Message}");
|
||||
return Array.Empty<SmartCoin>();
|
||||
}
|
||||
}
|
||||
@@ -543,7 +561,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.LogError($"Failed to analyze anonsets of tx {smartTx.GetHash()}");
|
||||
this.LogError(coordinatorName,$"Failed to analyze anonsets of tx {smartTx.GetHash()}");
|
||||
}
|
||||
|
||||
|
||||
@@ -649,7 +667,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
|
||||
stopwatch.Stop();
|
||||
|
||||
this.LogInfo($"Registered coinjoin result for {StoreId} in {stopwatch.Elapsed}");
|
||||
this.LogInfo(coordinatorName,$"Registered coinjoin result for {StoreId} in {stopwatch.Elapsed}");
|
||||
_memoryCache.Remove(WabisabiService.GetCacheKey(StoreId) + "cjhistory");
|
||||
|
||||
break;
|
||||
@@ -657,7 +675,7 @@ public class BTCPayWallet : IWallet, IDestinationProvider
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
this.LogError( "Could not save coinjoin progress! " + e.Message);
|
||||
this.LogError(coordinatorName,"Could not save coinjoin progress! " + e.Message);
|
||||
// ignored
|
||||
|
||||
}
|
||||
@@ -691,7 +709,7 @@ public async Task<IEnumerable<IDestination>> GetNextDestinationsAsync(int count,
|
||||
_btcPayWallet.ReserveAddressAsync(StoreId ,DerivationScheme, "coinjoin"))).ContinueWith(task => task.Result.Select(information => information.Address));
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<PendingPayment>> GetPendingPaymentsAsync( UtxoSelectionParameters roundParameters)
|
||||
public async Task<IEnumerable<PendingPayment>> GetPendingPaymentsAsync(RoundParameters roundParameters)
|
||||
{
|
||||
|
||||
|
||||
@@ -715,11 +733,6 @@ public async Task<IEnumerable<IDestination>> GetNextDestinationsAsync(int count,
|
||||
|
||||
var payoutBlob = data.GetBlob(_btcPayNetworkJsonSerializerSettings);
|
||||
var value = new Money(payoutBlob.CryptoAmount.Value, MoneyUnit.BTC);
|
||||
if (!roundParameters.AllowedOutputAmounts.Contains(value) ||
|
||||
!roundParameters.AllowedOutputScriptTypes.Contains(bitcoinLikeClaimDestination.Address.ScriptPubKey.GetScriptType()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new PendingPayment()
|
||||
{
|
||||
Identifier = data.Id,
|
||||
@@ -738,9 +751,9 @@ public async Task<IEnumerable<IDestination>> GetNextDestinationsAsync(int count,
|
||||
}
|
||||
}
|
||||
|
||||
public Task<ScriptType> GetScriptTypeAsync()
|
||||
public Task<ScriptType[]> GetScriptTypeAsync()
|
||||
{
|
||||
return Task.FromResult(DerivationScheme.GetDerivation(0).ScriptPubKey.GetScriptType());
|
||||
return Task.FromResult(new []{DerivationScheme.GetDerivation(0).ScriptPubKey.GetScriptType()});
|
||||
}
|
||||
|
||||
private Action<(uint256 roundId, uint256 transactionId, int outputIndex)> PaymentSucceeded(string payoutId)
|
||||
|
||||
@@ -33,6 +33,7 @@ using WalletWasabi.WabiSabi;
|
||||
using WalletWasabi.WabiSabi.Backend;
|
||||
using WalletWasabi.WabiSabi.Backend.Rounds.CoinJoinStorage;
|
||||
using WalletWasabi.WabiSabi.Backend.Statistics;
|
||||
using WalletWasabi.WabiSabi.Client;
|
||||
using WalletWasabi.WabiSabi.Models;
|
||||
using WalletWasabi.WebClients.Wasabi;
|
||||
|
||||
@@ -266,7 +267,14 @@ public class WabisabiCoordinatorService : PeriodicRunner
|
||||
{
|
||||
instance.WasabiCoordinatorStatusFetcher.OverrideConnected = null;
|
||||
}
|
||||
_instanceManager.AddCoordinator("Local Coordinator", "local", _ => null, cachedSettings.TermsConditions, cachedSettings.CoordinatorDescription);
|
||||
|
||||
var coinjoinConfig = new CoinJoinConfiguration(WabiSabiCoordinator.Config.CoordinatorIdentifier, 10m, 100m);
|
||||
_instanceManager.AddCoordinator("Local Coordinator",
|
||||
"local", _ => null,
|
||||
cachedSettings.TermsConditions,
|
||||
cachedSettings.CoordinatorDescription,
|
||||
coinjoinConfig
|
||||
);
|
||||
}
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
|
||||
@@ -49,4 +49,5 @@ public class DiscoveredCoordinator
|
||||
public string Name { get; set; }
|
||||
public string Relay { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string? CoinjoinIdentifier { get; set; }
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ updateInProgressAnimation(myChart);
|
||||
|
||||
RoundState currentRound = null;
|
||||
CoinJoinTracker tracker = null;
|
||||
if (coordinator.CoinJoinManager.TrackedCoinJoins?.TryGetValue(wallet.WalletName, out tracker) is true &&
|
||||
if (coordinator.CoinJoinManager.TrackedCoinJoins?.TryGetValue(wallet.WalletId, out tracker) is true &&
|
||||
tracker?.CoinJoinClient?.CurrentRoundId is { } &&
|
||||
tracker?.CoinJoinClient?.RoundStatusUpdater?.RoundStates?.TryGetValue(tracker?.CoinJoinClient?.CurrentRoundId, out currentRound) is true)
|
||||
{
|
||||
@@ -397,7 +397,7 @@ updateInProgressAnimation(myChart);
|
||||
else if (coordinator.WasabiCoordinatorStatusFetcher.Connected)
|
||||
{
|
||||
var roundParameters = coordinator.RoundStateUpdater.RoundStates.LastOrDefault(pair => pair.Value.BlameOf == uint256.Zero).Value?.CoinjoinState.Parameters;
|
||||
coordinator.CoinJoinManager.TrackedWallets.TryGetValue(wallet.WalletName, out var trackedWallet);
|
||||
coordinator.CoinJoinManager.TrackedWallets.TryGetValue(wallet.WalletId, out var trackedWallet);
|
||||
if(trackedWallet is {} && setting.RoundWhenEnabled is not null && roundParameters is not null && !BTCPayWallet.IsRoundOk(roundParameters, setting))
|
||||
{
|
||||
<a asp-controller="WabisabiStore" asp-action="UpdateWabisabiStoreSettings" asp-route-storeId="@storeId" class="h6 text-danger">
|
||||
@@ -416,7 +416,7 @@ updateInProgressAnimation(myChart);
|
||||
@{
|
||||
if (coordinator.CoinPrison is not null)
|
||||
{
|
||||
var bannedCoins = coins.Where(coin => coordinator.CoinPrison.TryGetOrRemoveBannedCoin(coin.Outpoint, out _));
|
||||
var bannedCoins = coins.Where(coin => coordinator.CoinPrison.TryGetOrRemoveBannedCoin(coin, out _));
|
||||
@if (bannedCoins.Any())
|
||||
{
|
||||
<div class="text-muted">@bannedCoins.Count() banned coins(for disrupting rounds)</div>
|
||||
@@ -520,6 +520,7 @@ updateInProgressAnimation(myChart);
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Coordinator</th>
|
||||
<th>Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -531,6 +532,9 @@ updateInProgressAnimation(myChart);
|
||||
<td>
|
||||
<small class="text-muted" data-timeago-unixms="@evt.time.ToUnixTimeMilliseconds()">@evt.time.ToTimeAgo()</small>
|
||||
</td>
|
||||
<td>
|
||||
<pre>@evt.coordinator</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>@evt.message</pre>
|
||||
</td>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
@using BTCPayServer.Services.Stores
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using WalletWasabi.Backend.Controllers
|
||||
@using WalletWasabi.Blockchain.Analysis
|
||||
@using WalletWasabi.Wallets
|
||||
@model BTCPayServer.Plugins.Wabisabi.WabisabiStoreSettings
|
||||
@inject WabisabiCoordinatorClientInstanceManager WabisabiCoordinatorClientInstanceManager
|
||||
@@ -96,14 +97,14 @@
|
||||
</style>
|
||||
|
||||
<div class="@(anyEnabled ? "" : "d-none") card card-body coordinator-settings">
|
||||
@if (Model.Active && anyEnabled)
|
||||
{
|
||||
@if (Model.Active && anyEnabled)
|
||||
{
|
||||
<div class="position-absolute w-100 h-100 text-center rounded" id="blocker" style=" left: 0; top: 0; z-index: 1">
|
||||
<h4 class="d-none pt-4">Settings cannot be changed while active</h4>
|
||||
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-6">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input plebModeRadio"
|
||||
@@ -123,8 +124,8 @@
|
||||
<p class="text-muted">The world is broken and I need to be vigilant about my bitcoin practices.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="advanced" class="@(Model.PlebMode ? "d-none" : "")">
|
||||
</div>
|
||||
<div id="advanced" class="@(Model.PlebMode ? "d-none" : "")">
|
||||
<button type="submit" name="command" value="reset" class="btn btn-link">Reset to defaults </button>
|
||||
|
||||
<div class="row">
|
||||
@@ -201,12 +202,32 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-6">
|
||||
<div class="form-group">
|
||||
|
||||
<label asp-for="MinimumDenominationAmount" class="form-label">Minimum denomination (in sats)</label>
|
||||
<input type="number" class="form-control" asp-for="MinimumDenominationAmount" placeholder="sats" min="0">
|
||||
<p class="text-muted">Do no use any of the standard denominations below this amount (creates change (which will get remixed) but prevent tiny utxos)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-6">
|
||||
<div class="form-group">
|
||||
|
||||
<label asp-for="AllowedDenominations" class="form-label">Allowed denominations (in sats)</label>
|
||||
<select asp-for="AllowedDenominations" class="form-select" multiple="multiple">
|
||||
@foreach (var denomination in BlockchainAnalyzer.StdDenoms)
|
||||
{
|
||||
<option value="@denomination">@denomination sats</option>
|
||||
}
|
||||
</select>
|
||||
<p>DO NOT USE UNLESS YOU KNOW WHAT YOU ARE DOING</p>
|
||||
<p class="text-muted">Only generate outputs of these denoms. Leave blank to ignore. Generates change. You must match other user's settings to gain any anonymity.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-check">
|
||||
<label asp-for="RedCoinIsolation" class="form-check-label">Cautious coinjoin entry mode </label>
|
||||
<input asp-for="RedCoinIsolation" type="checkbox" class="form-check-input"/>
|
||||
@@ -307,7 +328,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@for (var index = 0; index < Model.Settings.Count; index++)
|
||||
|
||||
@@ -104,7 +104,7 @@ public class WabisabiCoordinatorClientInstanceManager:IHostedService
|
||||
|
||||
|
||||
public void AddCoordinator(string displayName, string name,
|
||||
Func<IServiceProvider, Uri> fetcher, string termsConditions = null, string description = null)
|
||||
Func<IServiceProvider, Uri> fetcher, string termsConditions = null, string description = null, CoinJoinConfiguration configuration = null)
|
||||
{
|
||||
if (termsConditions is null && name == "zksnacks")
|
||||
{
|
||||
@@ -171,7 +171,7 @@ public class WabisabiCoordinatorClientInstanceManager:IHostedService
|
||||
var instance = new WabisabiCoordinatorClientInstance(
|
||||
displayName,
|
||||
name, url is null? null: new Uri(url), wasabiHttpClientFactory,_provider.GetService<ILoggerFactory>(), _provider, UTXOLocker,
|
||||
_provider.GetService<WalletProvider>(), termsConditions, description);
|
||||
_provider.GetService<WalletProvider>(), termsConditions, description, configuration);
|
||||
if (HostedServices.TryAdd(instance.CoordinatorName, instance))
|
||||
{
|
||||
if(started)
|
||||
@@ -299,8 +299,7 @@ public class WabisabiCoordinatorClientInstance:IHostedService
|
||||
ILoggerFactory loggerFactory,
|
||||
IServiceProvider serviceProvider,
|
||||
IUTXOLocker utxoLocker,
|
||||
WalletProvider walletProvider, string termsConditions, string description, string coordinatorIdentifier = "CoinJoinCoordinatorIdentifier"
|
||||
)
|
||||
WalletProvider walletProvider, string termsConditions, string description, CoinJoinConfiguration config)
|
||||
{
|
||||
|
||||
_utxoLocker = utxoLocker;
|
||||
@@ -348,7 +347,7 @@ public class WabisabiCoordinatorClientInstance:IHostedService
|
||||
|
||||
CoinJoinManager = new CoinJoinManager(coordinatorName, WalletProvider, RoundStateUpdater,
|
||||
WasabiHttpClientFactory,
|
||||
WasabiCoordinatorStatusFetcher, coordinatorIdentifier, CoinPrison);
|
||||
WasabiCoordinatorStatusFetcher, config, CoinPrison);
|
||||
CoinJoinManager.StatusChanged += OnStatusChanged;
|
||||
|
||||
_hostedServices.Register<RoundStateUpdater>(() => RoundStateUpdater, "RoundStateUpdater");
|
||||
|
||||
@@ -27,6 +27,7 @@ using WalletWasabi.Backend.Controllers;
|
||||
using WalletWasabi.Blockchain.TransactionBuilding;
|
||||
using WalletWasabi.Blockchain.TransactionOutputs;
|
||||
using WalletWasabi.Extensions;
|
||||
using WalletWasabi.WabiSabi.Client;
|
||||
|
||||
namespace BTCPayServer.Plugins.Wabisabi
|
||||
{
|
||||
@@ -244,7 +245,8 @@ namespace BTCPayServer.Plugins.Wabisabi
|
||||
{
|
||||
coordSettings.DiscoveredCoordinators.Add(viewModel);
|
||||
await _wabisabiCoordinatorService.UpdateSettings(coordSettings);
|
||||
_instanceManager.AddCoordinator(viewModel.Name, viewModel.Name, provider => viewModel.Uri, viewModel.Description);
|
||||
var config = new CoinJoinConfiguration();
|
||||
_instanceManager.AddCoordinator(viewModel.Name, viewModel.Name, provider => viewModel.Uri, null,viewModel.Description, config);
|
||||
|
||||
TempData["SuccessMessage"] = $"Coordinator {viewModel.Name } added and started";
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public class WabisabiStoreSettings
|
||||
public CrossMixMode CrossMixBetweenCoordinatorsMode { get; set; } = CrossMixMode.WhenFree;
|
||||
public int FeeRateMedianTimeFrameHours { get; set; }
|
||||
public long MinimumDenominationAmount { get; set; } = 10000;
|
||||
public long[] AllowedDenominations { get; set; }
|
||||
public int ExplicitHighestFeeTarget { get; set; } = BTCPayWallet.DefaultExplicitHighestFeeTarget;
|
||||
public int LowFeeTarget { get; set; } = BTCPayWallet.DefaultLowFeeTarget;
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace BTCPayServer.Plugins.Wabisabi;
|
||||
|
||||
public class WalletProvider : PeriodicRunner,IWalletProvider
|
||||
{
|
||||
private Dictionary<string, WabisabiStoreSettings>? _cachedSettings;
|
||||
private ConcurrentDictionary<string, WabisabiStoreSettings>? _cachedSettings;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly IExplorerClientProvider _explorerClientProvider;
|
||||
@@ -255,8 +255,8 @@ public class WalletProvider : PeriodicRunner,IWalletProvider
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
_cachedSettings =
|
||||
await _storeRepository.GetSettingsAsync<WabisabiStoreSettings>(nameof(WabisabiStoreSettings));
|
||||
_cachedSettings = new ConcurrentDictionary<string, WabisabiStoreSettings>(
|
||||
(await _storeRepository.GetSettingsAsync<WabisabiStoreSettings>(nameof(WabisabiStoreSettings))));
|
||||
_initialLoad.SetResult();
|
||||
}, cancellationToken);
|
||||
_disposables.Add(_eventAggregator.SubscribeAsync<StoreRemovedEvent>(async @event =>
|
||||
|
||||
Submodule submodules/walletwasabi updated: 10b0aab0fe...3f52c3f7b7
Reference in New Issue
Block a user