btcpayserver/BTCPayServer.Tests/PSBTTests.cs

153 lines
8.1 KiB
C#
Raw Normal View History

2019-05-12 14:51:24 +09:00
using System.Collections.Generic;
2020-06-28 17:55:27 +09:00
using System.Linq;
2019-05-12 14:51:24 +09:00
using System.Threading.Tasks;
using BTCPayServer.Controllers;
2020-06-28 17:55:27 +09:00
using BTCPayServer.Models;
2019-05-12 14:51:24 +09:00
using BTCPayServer.Models.WalletViewModels;
using BTCPayServer.Tests.Logging;
using Microsoft.AspNetCore.Mvc;
using NBitcoin;
using NBitpayClient;
using Xunit;
using Xunit.Abstractions;
namespace BTCPayServer.Tests
{
public class PSBTTests
{
public PSBTTests(ITestOutputHelper helper)
{
Logs.Tester = new XUnitLog(helper) { Name = "Tests" };
Logs.LogProvider = new XUnitLogProvider(helper);
}
[Fact]
[Trait("Integration", "Integration")]
public async Task CanPlayWithPSBT()
{
using (var tester = ServerTester.Create())
{
2019-10-07 16:04:25 +09:00
await tester.StartAsync();
2019-05-12 14:51:24 +09:00
var user = tester.NewAccount();
user.GrantAccess();
user.RegisterDerivationScheme("BTC");
var invoice = user.BitPay.CreateInvoice(new Invoice()
{
Price = 10,
Currency = "USD",
PosData = "posData",
OrderId = "orderId",
ItemDesc = "Some \", description",
FullNotifications = true
}, Facade.Merchant);
var cashCow = tester.ExplorerNode;
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network);
cashCow.SendToAddress(invoiceAddress, Money.Coins(1.5m));
TestUtils.Eventually(() =>
{
invoice = user.BitPay.GetInvoice(invoice.Id);
Assert.Equal("paid", invoice.Status);
});
2019-10-12 20:35:30 +09:00
var walletController = user.GetController<WalletsController>();
2019-05-12 14:51:24 +09:00
var walletId = new WalletId(user.StoreId, "BTC");
var sendDestination = new Key().PubKey.Hash.GetAddress(user.SupportedNetwork.NBitcoinNetwork).ToString();
2019-05-12 14:51:24 +09:00
var sendModel = new WalletSendModel()
{
Outputs = new List<WalletSendModel.TransactionOutput>()
{
new WalletSendModel.TransactionOutput()
{
DestinationAddress = sendDestination,
Amount = 0.1m,
}
},
2019-05-12 14:51:24 +09:00
FeeSatoshiPerByte = 1,
CurrentBalance = 1.5m
};
string redirectedPSBT = AssertRedirectedPSBT(await walletController.WalletSend(walletId, sendModel, command: "analyze-psbt"), nameof(walletController.WalletPSBT));
2019-05-19 23:33:32 +09:00
var vmPSBT = await walletController.WalletPSBT(walletId, new WalletPSBTViewModel() { PSBT = redirectedPSBT }).AssertViewModelAsync<WalletPSBTViewModel>();
2019-05-12 14:51:24 +09:00
var unsignedPSBT = PSBT.Parse(vmPSBT.PSBT, user.SupportedNetwork.NBitcoinNetwork);
Assert.NotNull(vmPSBT.Decoded);
2019-05-13 08:55:26 +09:00
var filePSBT = (FileContentResult)(await walletController.WalletPSBT(walletId, vmPSBT, "save-psbt"));
2019-05-12 14:51:24 +09:00
PSBT.Load(filePSBT.FileContents, user.SupportedNetwork.NBitcoinNetwork);
var vmPSBT2 = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel()
{
SigningContext = new SigningContextModel()
{
2020-06-28 17:55:27 +09:00
PSBT = AssertRedirectedPSBT(await walletController.WalletPSBT(walletId, vmPSBT, "broadcast"), nameof(walletController.WalletPSBTReady))
}
2020-06-28 17:55:27 +09:00
}).AssertViewModelAsync<WalletPSBTReadyViewModel>();
2019-05-31 12:17:47 +09:00
Assert.NotEmpty(vmPSBT2.Inputs.Where(i => i.Error != null));
Assert.Equal(vmPSBT.PSBT, vmPSBT2.SigningContext.PSBT);
2019-05-12 14:51:24 +09:00
var signedPSBT = unsignedPSBT.Clone();
signedPSBT.SignAll(user.DerivationScheme, user.GenerateWalletResponseV.AccountHDKey, user.GenerateWalletResponseV.AccountKeyPath);
2019-05-12 14:51:24 +09:00
vmPSBT.PSBT = signedPSBT.ToBase64();
var psbtReady = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel()
{
SigningContext = new SigningContextModel()
{
PSBT = AssertRedirectedPSBT(await walletController.WalletPSBT(walletId, vmPSBT, "broadcast"), nameof(walletController.WalletPSBTReady))
}
2020-06-28 17:55:27 +09:00
}).AssertViewModelAsync<WalletPSBTReadyViewModel>();
2019-05-20 00:06:03 +09:00
Assert.Equal(2 + 1, psbtReady.Destinations.Count); // The fee is a destination
Assert.Contains(psbtReady.Destinations, d => d.Destination == sendDestination && !d.Positive);
Assert.Contains(psbtReady.Destinations, d => d.Positive);
var redirect = Assert.IsType<RedirectToActionResult>(await walletController.WalletPSBTReady(walletId, psbtReady, command: "broadcast"));
2019-05-12 14:51:24 +09:00
Assert.Equal(nameof(walletController.WalletTransactions), redirect.ActionName);
vmPSBT.PSBT = unsignedPSBT.ToBase64();
var combineVM = await walletController.WalletPSBT(walletId, vmPSBT, "combine").AssertViewModelAsync<WalletPSBTCombineViewModel>();
Assert.Equal(vmPSBT.PSBT, combineVM.OtherPSBT);
combineVM.PSBT = signedPSBT.ToBase64();
var psbt = AssertRedirectedPSBT(await walletController.WalletPSBTCombine(walletId, combineVM), nameof(walletController.WalletPSBT));
2019-05-12 14:51:24 +09:00
2019-11-08 21:42:34 +09:00
var signedPSBT2 = PSBT.Parse(psbt, user.SupportedNetwork.NBitcoinNetwork);
2019-05-12 14:51:24 +09:00
Assert.True(signedPSBT.TryFinalize(out _));
Assert.True(signedPSBT2.TryFinalize(out _));
Assert.Equal(signedPSBT, signedPSBT2);
// Can use uploaded file?
combineVM.PSBT = null;
combineVM.UploadedPSBTFile = TestUtils.GetFormFile("signedPSBT", signedPSBT.ToBytes());
psbt = AssertRedirectedPSBT(await walletController.WalletPSBTCombine(walletId, combineVM), nameof(walletController.WalletPSBT));
2019-11-08 21:42:34 +09:00
signedPSBT2 = PSBT.Parse(psbt, user.SupportedNetwork.NBitcoinNetwork);
2019-05-12 14:51:24 +09:00
Assert.True(signedPSBT.TryFinalize(out _));
Assert.True(signedPSBT2.TryFinalize(out _));
Assert.Equal(signedPSBT, signedPSBT2);
var ready = (await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel()
{
SigningContext = new SigningContextModel(signedPSBT)
})).AssertViewModel<WalletPSBTReadyViewModel>();
Assert.Equal(signedPSBT.ToBase64(), ready.SigningContext.PSBT);
psbt = AssertRedirectedPSBT(await walletController.WalletPSBTReady(walletId, ready, command: "analyze-psbt"), nameof(walletController.WalletPSBT));
2019-11-08 21:42:34 +09:00
Assert.Equal(signedPSBT.ToBase64(), psbt);
2019-05-12 14:51:24 +09:00
redirect = Assert.IsType<RedirectToActionResult>(await walletController.WalletPSBTReady(walletId, ready, command: "broadcast"));
Assert.Equal(nameof(walletController.WalletTransactions), redirect.ActionName);
2020-07-14 09:52:17 +02:00
//test base64 psbt file
Assert.False(string.IsNullOrEmpty(Assert.IsType<WalletPSBTViewModel>(
Assert.IsType<ViewResult>(
await walletController.WalletPSBT(walletId,
new WalletPSBTViewModel()
{
UploadedPSBTFile = TestUtils.GetFormFile("base64", signedPSBT.ToBase64())
})).Model).PSBT));
2019-05-12 14:51:24 +09:00
}
}
2019-11-08 21:42:34 +09:00
private static string AssertRedirectedPSBT(IActionResult view, string actionName)
2019-11-08 21:42:34 +09:00
{
var postRedirectView = Assert.IsType<ViewResult>(view);
var postRedirectViewModel = Assert.IsType<PostRedirectViewModel>(postRedirectView.Model);
Assert.Equal(actionName, postRedirectViewModel.AspAction);
var redirectedPSBT = postRedirectViewModel.Parameters.Single(p => p.Key == "psbt" || p.Key == "SigningContext.PSBT").Value;
2019-11-08 21:42:34 +09:00
return redirectedPSBT;
}
2019-05-12 14:51:24 +09:00
}
}