Merge pull request #1829 from btcpayserver/bitcoin-only-fixes

Do not crash UI and background services after switching to BItcoin Only when you had altcoin payments
This commit is contained in:
Nicolas Dorier 2020-08-16 21:39:30 +09:00 committed by GitHub
commit 12b5c88acf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 79 additions and 36 deletions

View File

@ -135,7 +135,7 @@ namespace BTCPayServer.Controllers
else
{
var paymentMethods = invoice.GetBlob(_NetworkProvider).GetPaymentMethods();
var options = invoice.GetBlob(_NetworkProvider).GetPaymentMethods()
var options = paymentMethods
.Select(o => o.GetId())
.Select(o => o.CryptoCode)
.Where(o => _NetworkProvider.GetNetwork<BTCPayNetwork>(o) is BTCPayNetwork n && !n.ReadonlyWallet)
@ -143,15 +143,15 @@ namespace BTCPayServer.Controllers
.OrderBy(o => o)
.Select(o => new PaymentMethodId(o, PaymentTypes.BTCLike))
.ToList();
var defaultRefund = invoice.Payments.Select(p => p.GetBlob(_NetworkProvider))
.Where(p => p != null)
.Select(p => p.GetPaymentMethodId().CryptoCode)
.FirstOrDefault();
var defaultRefund = invoice.Payments
.Select(p => p.GetBlob(_NetworkProvider))
.Select(p => p?.GetPaymentMethodId())
.FirstOrDefault(p => p != null && p.PaymentType == BitcoinPaymentType.Instance);
// TODO: What if no option?
var refund = new RefundModel();
refund.Title = "Select a payment method";
refund.AvailablePaymentMethods = new SelectList(options, nameof(PaymentMethodId.CryptoCode), nameof(PaymentMethodId.CryptoCode));
refund.SelectedPaymentMethod = defaultRefund ?? options.Select(o => o.CryptoCode).First();
refund.SelectedPaymentMethod = defaultRefund?.ToString() ?? options.Select(o => o.CryptoCode).First();
// Nothing to select, skip to next
if (refund.AvailablePaymentMethods.Count() == 1)

View File

@ -15,8 +15,7 @@ namespace BTCPayServer.Data
public static PaymentMethodId GetDefaultPaymentId(this StoreData storeData, BTCPayNetworkProvider networks)
{
PaymentMethodId[] paymentMethodIds = storeData.GetEnabledPaymentIds(networks);
var defaultPaymentId = string.IsNullOrEmpty(storeData.DefaultCrypto) ? null : PaymentMethodId.Parse(storeData.DefaultCrypto);
PaymentMethodId.TryParse(storeData.DefaultCrypto, out var defaultPaymentId);
var chosen = paymentMethodIds.FirstOrDefault(f => f == defaultPaymentId) ??
paymentMethodIds.FirstOrDefault(f => f.CryptoCode == defaultPaymentId?.CryptoCode) ??
paymentMethodIds.FirstOrDefault();
@ -80,7 +79,10 @@ namespace BTCPayServer.Data
JObject strategies = JObject.Parse(storeData.DerivationStrategies);
foreach (var strat in strategies.Properties())
{
var paymentMethodId = PaymentMethodId.Parse(strat.Name);
if (!PaymentMethodId.TryParse(strat.Name, out var paymentMethodId))
{
continue;
}
var network = networks.GetNetwork<BTCPayNetworkBase>(paymentMethodId.CryptoCode);
if (network != null)
{

View File

@ -117,8 +117,9 @@ namespace BTCPayServer
public static IEnumerable<BitcoinLikePaymentData> GetAllBitcoinPaymentData(this InvoiceEntity invoice)
{
return invoice.GetPayments()
.Where(p => p.GetPaymentMethodId().PaymentType == PaymentTypes.BTCLike)
.Select(p => (BitcoinLikePaymentData)p.GetCryptoPaymentData());
.Where(p => p.GetPaymentMethodId()?.PaymentType == PaymentTypes.BTCLike)
.Select(p => (BitcoinLikePaymentData)p.GetCryptoPaymentData())
.Where(data => data != null);
}
public static async Task<Dictionary<uint256, TransactionResult>> GetTransactions(this BTCPayWallet client, uint256[] hashes, bool includeOffchain = false, CancellationToken cts = default(CancellationToken))

View File

@ -33,7 +33,7 @@ namespace BTCPayServer.HostedServices
protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken)
{
if (evt is InvoiceEvent invoiceEvent && invoiceEvent.Name == InvoiceEvent.ReceivedPayment &&
invoiceEvent.Payment.GetPaymentMethodId().PaymentType == BitcoinPaymentType.Instance &&
invoiceEvent.Payment.GetPaymentMethodId()?.PaymentType == BitcoinPaymentType.Instance &&
invoiceEvent.Payment.GetCryptoPaymentData() is BitcoinLikePaymentData bitcoinLikePaymentData)
{
var walletId = new WalletId(invoiceEvent.Invoice.StoreId, invoiceEvent.Payment.GetCryptoCode());

View File

@ -55,7 +55,7 @@ namespace BTCPayServer.Models.AppViewModels
}
public class Contribution
{
public PaymentMethodId PaymentMehtodId { get; set; }
public PaymentMethodId PaymentMethodId { get; set; }
public decimal Value { get; set; }
public decimal CurrencyValue { get; set; }
}

View File

@ -159,7 +159,7 @@ namespace BTCPayServer.PaymentRequest
{
data.GetValue(),
invoiceEvent.Payment.GetCryptoCode(),
invoiceEvent.Payment.GetPaymentMethodId().PaymentType.ToString()
invoiceEvent.Payment.GetPaymentMethodId()?.PaymentType?.ToString()
});
}

View File

@ -104,10 +104,16 @@ namespace BTCPayServer.PaymentRequest
Currency = entity.ProductInformation.Currency,
ExpiryDate = entity.ExpirationTime.DateTime,
Status = entity.GetInvoiceState().ToString(),
Payments = entity.GetPayments().Select(paymentEntity =>
Payments = entity
.GetPayments()
.Select(paymentEntity =>
{
var paymentData = paymentEntity.GetCryptoPaymentData();
var paymentMethodId = paymentEntity.GetPaymentMethodId();
if (paymentData is null || paymentMethodId is null)
{
return null;
}
string txId = paymentData.GetPaymentId();
string link = GetTransactionLink(paymentMethodId, txId);
@ -118,7 +124,9 @@ namespace BTCPayServer.PaymentRequest
Link = link,
Id = txId
};
}).ToList()
})
.Where(payment => payment != null)
.ToList()
}).ToList()
};
}

View File

@ -222,7 +222,7 @@ namespace BTCPayServer.Payments.Bitcoin
var paymentEntitiesByPrevOut = new Dictionary<OutPoint, PaymentEntity>();
foreach (var payment in invoice.GetPayments(wallet.Network))
{
if (payment.GetPaymentMethodId().PaymentType != PaymentTypes.BTCLike)
if (payment.GetPaymentMethodId()?.PaymentType != PaymentTypes.BTCLike)
continue;
var paymentData = (BitcoinLikePaymentData)payment.GetCryptoPaymentData();
if (!transactions.TryGetValue(paymentData.Outpoint.Hash, out TransactionResult tx))

View File

@ -72,6 +72,7 @@ namespace BTCPayServer.Payments
public static bool TryParse(string str, out PaymentMethodId paymentMethodId)
{
str ??= "";
paymentMethodId = null;
var parts = str.Split('_', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 0 || parts.Length > 2)

View File

@ -22,7 +22,7 @@ namespace BTCPayServer.Payments
public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str)
{
return ((BTCPayNetwork)network).ToObject<BitcoinLikePaymentData>(str);
return ((BTCPayNetwork)network)?.ToObject<BitcoinLikePaymentData>(str);
}
public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData)

View File

@ -20,7 +20,7 @@ namespace BTCPayServer.Payments
public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str)
{
return ((BTCPayNetwork)network).ToObject<LightningLikePaymentData>(str);
return ((BTCPayNetwork)network)?.ToObject<LightningLikePaymentData>(str);
}
public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData)

View File

@ -39,7 +39,7 @@ namespace BTCPayServer.Services.Apps
{
data.GetValue(),
invoiceEvent.Payment.GetCryptoCode(),
invoiceEvent.Payment.GetPaymentMethodId().PaymentType.ToString()
invoiceEvent.Payment.GetPaymentMethodId()?.PaymentType?.ToString()
}, cancellationToken);
}
await InfoUpdated(appId);

View File

@ -333,7 +333,7 @@ namespace BTCPayServer.Services.Apps
.SelectMany(p =>
{
var contribution = new Contribution();
contribution.PaymentMehtodId = new PaymentMethodId(p.ProductInformation.Currency, PaymentTypes.BTCLike);
contribution.PaymentMethodId = new PaymentMethodId(p.ProductInformation.Currency, PaymentTypes.BTCLike);
contribution.CurrencyValue = p.ProductInformation.Price;
contribution.Value = contribution.CurrencyValue;
@ -363,18 +363,18 @@ namespace BTCPayServer.Services.Apps
.Select(pay =>
{
var paymentMethodContribution = new Contribution();
paymentMethodContribution.PaymentMehtodId = pay.GetPaymentMethodId();
paymentMethodContribution.PaymentMethodId = pay.GetPaymentMethodId();
paymentMethodContribution.Value = pay.GetCryptoPaymentData().GetValue() - pay.NetworkFee;
var rate = p.GetPaymentMethod(paymentMethodContribution.PaymentMehtodId).Rate;
var rate = p.GetPaymentMethod(paymentMethodContribution.PaymentMethodId).Rate;
paymentMethodContribution.CurrencyValue = rate * paymentMethodContribution.Value;
return paymentMethodContribution;
})
.ToArray();
})
.GroupBy(p => p.PaymentMehtodId)
.GroupBy(p => p.PaymentMethodId)
.ToDictionary(p => p.Key, p => new Contribution()
{
PaymentMehtodId = p.Key,
PaymentMethodId = p.Key,
Value = p.Select(v => v.Value).Sum(),
CurrencyValue = p.Select(v => v.CurrencyValue).Sum()
});

View File

@ -267,11 +267,11 @@ namespace BTCPayServer.Services.Invoices
#pragma warning disable CS0618
public List<PaymentEntity> GetPayments()
{
return Payments?.ToList() ?? new List<PaymentEntity>();
return Payments?.Where(entity => entity.GetPaymentMethodId() != null).ToList() ?? new List<PaymentEntity>();
}
public List<PaymentEntity> GetPayments(string cryptoCode)
{
return Payments.Where(p => p.CryptoCode == cryptoCode).ToList();
return GetPayments().Where(p => p.CryptoCode == cryptoCode).ToList();
}
public List<PaymentEntity> GetPayments(BTCPayNetworkBase network)
{
@ -551,7 +551,10 @@ namespace BTCPayServer.Services.Invoices
foreach (var prop in PaymentMethod.Properties())
{
var r = serializer.ToObject<PaymentMethod>(prop.Value.ToString());
var paymentMethodId = PaymentMethodId.Parse(prop.Name);
if (!PaymentMethodId.TryParse(prop.Name, out var paymentMethodId))
{
continue;
}
r.CryptoCode = paymentMethodId.CryptoCode;
r.PaymentType = paymentMethodId.PaymentType.ToString();
r.ParentEntity = this;
@ -1006,7 +1009,18 @@ namespace BTCPayServer.Services.Invoices
}
else
{
paymentData = GetPaymentMethodId().PaymentType.DeserializePaymentData(Network, CryptoPaymentData);
var paymentMethodId = GetPaymentMethodId();
if (paymentMethodId is null)
{
return null;
}
paymentData = paymentMethodId.PaymentType.DeserializePaymentData(Network, CryptoPaymentData);
if (paymentData is null)
{
return null;
}
paymentData.Network = Network;
if (paymentData is BitcoinLikePaymentData bitcoin)
{
@ -1051,7 +1065,16 @@ namespace BTCPayServer.Services.Invoices
public PaymentMethodId GetPaymentMethodId()
{
#pragma warning disable CS0618 // Type or member is obsolete
return new PaymentMethodId(CryptoCode ?? "BTC", string.IsNullOrEmpty(CryptoPaymentDataType) ? PaymentTypes.BTCLike : PaymentTypes.Parse(CryptoPaymentDataType));
PaymentType paymentType;
if (string.IsNullOrEmpty(CryptoPaymentDataType))
{
paymentType = BitcoinPaymentType.Instance;;
}
else if(!PaymentTypes.TryParse(CryptoPaymentDataType, out paymentType))
{
return null;
}
return new PaymentMethodId(CryptoCode ?? "BTC", paymentType);
#pragma warning restore CS0618 // Type or member is obsolete
}

View File

@ -704,7 +704,7 @@ retry:
Accounted = accounted
};
context.Payments.Add(data);
await context.Payments.AddAsync(data);
try
{

View File

@ -47,7 +47,7 @@
</div>
</div>
@{
var grouped = invoice.Payments.GroupBy(payment => payment.GetPaymentMethodId().PaymentType);
var grouped = invoice.Payments.GroupBy(payment => payment.GetPaymentMethodId()?.PaymentType).Where(entities => entities.Key!= null);
}
@foreach (var paymentGroup in grouped)
{

View File

@ -5,10 +5,14 @@
@{
PayjoinInformation payjoinIformation = null;
var onchainPayments = Model.Where(entity => entity.GetPaymentMethodId().PaymentType == BitcoinPaymentType.Instance).Select(payment =>
var onchainPayments = Model.Where(entity => entity.GetPaymentMethodId()?.PaymentType == BitcoinPaymentType.Instance).Select(payment =>
{
var m = new OnchainPaymentViewModel();
var onChainPaymentData = payment.GetCryptoPaymentData() as BitcoinLikePaymentData;
if (onChainPaymentData is null)
{
return null;
}
m.Crypto = payment.GetPaymentMethodId().CryptoCode;
m.DepositAddress = onChainPaymentData.GetDestination();
@ -38,7 +42,7 @@
m.Replaced = !payment.Accounted;
m.CryptoPaymentData = onChainPaymentData;
return m;
});
}).Where(model => model != null);
}
@if (onchainPayments.Any())

View File

@ -3,15 +3,19 @@
@model IEnumerable<BTCPayServer.Services.Invoices.PaymentEntity>
@{
var offchainPayments = Model.Where(entity => entity.GetPaymentMethodId().PaymentType == LightningPaymentType.Instance).Select(payment =>
var offchainPayments = Model.Where(entity => entity.GetPaymentMethodId()?.PaymentType == LightningPaymentType.Instance).Select(payment =>
{
var offChainPaymentData = payment.GetCryptoPaymentData() as LightningLikePaymentData;
if (offChainPaymentData is null)
{
return null;
}
return new OffChainPaymentViewModel()
{
Crypto = payment.Network.CryptoCode,
BOLT11 = offChainPaymentData.BOLT11
};
});
}).Where(model => model != null);
}