Fix: Could not send money from wallet of a coin without segwit

This commit is contained in:
nicolas.dorier 2018-06-30 21:26:10 +09:00
parent ac8feceaf2
commit 42d60ef84b
3 changed files with 42 additions and 22 deletions

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<Version>1.0.2.37</Version> <Version>1.0.2.38</Version>
<NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn> <NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -40,10 +40,10 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" />
<PackageReference Include="Microsoft.NetCore.Analyzers" Version="2.6.0" /> <PackageReference Include="Microsoft.NetCore.Analyzers" Version="2.6.0" />
<PackageReference Include="NBitcoin" Version="4.1.1.18" /> <PackageReference Include="NBitcoin" Version="4.1.1.20" />
<PackageReference Include="NBitpayClient" Version="1.0.0.29" /> <PackageReference Include="NBitpayClient" Version="1.0.0.29" />
<PackageReference Include="DBreeze" Version="1.87.0" /> <PackageReference Include="DBreeze" Version="1.87.0" />
<PackageReference Include="NBXplorer.Client" Version="1.0.2.11" /> <PackageReference Include="NBXplorer.Client" Version="1.0.2.12" />
<PackageReference Include="NicolasDorier.CommandLine" Version="1.0.0.2" /> <PackageReference Include="NicolasDorier.CommandLine" Version="1.0.0.2" />
<PackageReference Include="NicolasDorier.CommandLine.Configuration" Version="1.0.0.3" /> <PackageReference Include="NicolasDorier.CommandLine.Configuration" Version="1.0.0.3" />
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.14" /> <PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.14" />

View File

@ -288,7 +288,7 @@ namespace BTCPayServer.Controllers
var unspentCoins = await wallet.GetUnspentCoins(strategyBase); var unspentCoins = await wallet.GetUnspentCoins(strategyBase);
var changeAddress = await change; var changeAddress = await change;
var send = new[] { ( var send = new[] { (
destination: destinationAddress as IDestination, destination: destinationAddress as IDestination,
amount: amountBTC, amount: amountBTC,
substractFees: subsctractFeesValue) }; substractFees: subsctractFeesValue) };
@ -335,15 +335,15 @@ namespace BTCPayServer.Controllers
Dictionary<uint256, Transaction> parentTransactions = new Dictionary<uint256, Transaction>(); Dictionary<uint256, Transaction> parentTransactions = new Dictionary<uint256, Transaction>();
if(!strategy.Segwit) if (!strategy.Segwit)
{ {
var parentHashes = usedCoins.Select(c => c.Outpoint.Hash).ToHashSet(); var parentHashes = usedCoins.Select(c => c.Outpoint.Hash).ToHashSet();
var explorer = _ExplorerProvider.GetExplorerClient(network); var explorer = _ExplorerProvider.GetExplorerClient(network);
var getTransactionAsyncs = parentHashes.Select(h => (Op: explorer.GetTransactionAsync(h), Hash: h)).ToList(); var getTransactionAsyncs = parentHashes.Select(h => (Op: explorer.GetTransactionAsync(h), Hash: h)).ToList();
foreach(var getTransactionAsync in getTransactionAsyncs) foreach (var getTransactionAsync in getTransactionAsyncs)
{ {
var tx = (await getTransactionAsync.Op); var tx = (await getTransactionAsync.Op);
if(tx == null) if (tx == null)
throw new Exception($"Parent transaction {getTransactionAsync.Hash} not found"); throw new Exception($"Parent transaction {getTransactionAsync.Hash} not found");
parentTransactions.Add(tx.Transaction.GetHash(), tx.Transaction); parentTransactions.Add(tx.Transaction.GetHash(), tx.Transaction);
} }
@ -356,7 +356,7 @@ namespace BTCPayServer.Controllers
KeyPath = foundKeyPath.Derive(keypaths[c.TxOut.ScriptPubKey]), KeyPath = foundKeyPath.Derive(keypaths[c.TxOut.ScriptPubKey]),
PubKey = strategy.Root.Derive(keypaths[c.TxOut.ScriptPubKey]).PubKey PubKey = strategy.Root.Derive(keypaths[c.TxOut.ScriptPubKey]).PubKey
}).ToArray(), unsigned, hasChange ? foundKeyPath.Derive(changeAddress.Item2) : null); }).ToArray(), unsigned, hasChange ? foundKeyPath.Derive(changeAddress.Item2) : null);
try try
{ {
var broadcastResult = await wallet.BroadcastTransactionsAsync(new List<Transaction>() { transaction }); var broadcastResult = await wallet.BroadcastTransactionsAsync(new List<Transaction>() { transaction });
@ -377,7 +377,7 @@ namespace BTCPayServer.Controllers
{ result = new LedgerTestResult() { Success = false, Error = "Timeout" }; } { result = new LedgerTestResult() { Success = false, Error = "Timeout" }; }
catch (Exception ex) catch (Exception ex)
{ result = new LedgerTestResult() { Success = false, Error = ex.Message }; } { result = new LedgerTestResult() { Success = false, Error = ex.Message }; }
finally { hw.Dispose(); }
try try
{ {
if (result != null) if (result != null)

View File

@ -20,9 +20,9 @@ namespace BTCPayServer.Services
public HardwareWalletException(string message) : base(message) { } public HardwareWalletException(string message) : base(message) { }
public HardwareWalletException(string message, Exception inner) : base(message, inner) { } public HardwareWalletException(string message, Exception inner) : base(message, inner) { }
} }
public class HardwareWalletService public class HardwareWalletService : IDisposable
{ {
class WebSocketTransport : LedgerWallet.Transports.ILedgerTransport class WebSocketTransport : LedgerWallet.Transports.ILedgerTransport, IDisposable
{ {
private readonly WebSocket webSocket; private readonly WebSocket webSocket;
@ -33,26 +33,40 @@ namespace BTCPayServer.Services
this.webSocket = webSocket; this.webSocket = webSocket;
} }
SemaphoreSlim _Semaphore = new SemaphoreSlim(1, 1);
public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(10); public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(10);
public async Task<byte[][]> Exchange(byte[][] apdus) public async Task<byte[][]> Exchange(byte[][] apdus)
{ {
await _Semaphore.WaitAsync();
List<byte[]> responses = new List<byte[]>(); List<byte[]> responses = new List<byte[]>();
using (CancellationTokenSource cts = new CancellationTokenSource(Timeout)) try
{ {
foreach (var apdu in apdus) using (CancellationTokenSource cts = new CancellationTokenSource(Timeout))
{ {
await this.webSocket.SendAsync(new ArraySegment<byte>(apdu), WebSocketMessageType.Binary, true, cts.Token); foreach (var apdu in apdus)
} {
foreach (var apdu in apdus) await this.webSocket.SendAsync(new ArraySegment<byte>(apdu), WebSocketMessageType.Binary, true, cts.Token);
{ }
byte[] response = new byte[300]; foreach (var apdu in apdus)
var result = await this.webSocket.ReceiveAsync(new ArraySegment<byte>(response), cts.Token); {
Array.Resize(ref response, result.Count); byte[] response = new byte[300];
responses.Add(response); var result = await this.webSocket.ReceiveAsync(new ArraySegment<byte>(response), cts.Token);
Array.Resize(ref response, result.Count);
responses.Add(response);
}
} }
} }
finally
{
_Semaphore.Release();
}
return responses.ToArray(); return responses.ToArray();
} }
public void Dispose()
{
_Semaphore.Dispose();
}
} }
private readonly LedgerClient _Ledger; private readonly LedgerClient _Ledger;
@ -121,7 +135,7 @@ namespace BTCPayServer.Services
public async Task<KeyPath> GetKeyPath(BTCPayNetwork network, DirectDerivationStrategy directStrategy) public async Task<KeyPath> GetKeyPath(BTCPayNetwork network, DirectDerivationStrategy directStrategy)
{ {
List<KeyPath> derivations = new List<KeyPath>(); List<KeyPath> derivations = new List<KeyPath>();
if(network.NBitcoinNetwork.Consensus.SupportSegwit) if (network.NBitcoinNetwork.Consensus.SupportSegwit)
derivations.Add(new KeyPath("49'")); derivations.Add(new KeyPath("49'"));
derivations.Add(new KeyPath("44'")); derivations.Add(new KeyPath("44'"));
KeyPath foundKeyPath = null; KeyPath foundKeyPath = null;
@ -155,6 +169,12 @@ namespace BTCPayServer.Services
_Transport.Timeout = TimeSpan.FromMinutes(5); _Transport.Timeout = TimeSpan.FromMinutes(5);
return await Ledger.SignTransactionAsync(signatureRequests, unsigned, changeKeyPath); return await Ledger.SignTransactionAsync(signatureRequests, unsigned, changeKeyPath);
} }
public void Dispose()
{
if(_Transport != null)
_Transport.Dispose();
}
} }
public class LedgerTestResult public class LedgerTestResult