Decouple taproot activation from support in generate wallet (#2837)

This commit is contained in:
Nicolas Dorier
2021-09-04 22:07:09 +09:00
committed by GitHub
parent 1422bd8540
commit e584ebe7de
7 changed files with 79 additions and 54 deletions

View File

@@ -55,7 +55,9 @@ namespace BTCPayServer.Controllers
vm.RootKeyPath = network.GetRootKeyPath(); vm.RootKeyPath = network.GetRootKeyPath();
vm.CanUseHotWallet = hotWallet; vm.CanUseHotWallet = hotWallet;
vm.CanUseRPCImport = rpcImport; vm.CanUseRPCImport = rpcImport;
vm.CanUseTaproot = TaprootSupported(vm.CryptoCode); vm.SupportTaproot = network.NBitcoinNetwork.Consensus.SupportTaproot;
vm.SupportSegwit = network.NBitcoinNetwork.Consensus.SupportSegwit;
vm.IsTaprootActivated = TaprootActivated(vm.CryptoCode);
if (vm.Method == null) if (vm.Method == null)
{ {
@@ -110,11 +112,6 @@ namespace BTCPayServer.Controllers
try try
{ {
strategy = ParseDerivationStrategy(vm.DerivationScheme, network); strategy = ParseDerivationStrategy(vm.DerivationScheme, network);
if(strategy.AccountDerivation is TaprootDerivationStrategy && !TaprootSupported(vm.CryptoCode))
{
ModelState.AddModelError(nameof(vm.DerivationScheme), "Taproot is not supported");
return View(vm.ViewName, vm);
}
strategy.Source = "ManualDerivationScheme"; strategy.Source = "ManualDerivationScheme";
if (!string.IsNullOrEmpty(vm.AccountKey)) if (!string.IsNullOrEmpty(vm.AccountKey))
{ {
@@ -214,7 +211,9 @@ namespace BTCPayServer.Controllers
vm.CanUseHotWallet = hotWallet; vm.CanUseHotWallet = hotWallet;
vm.CanUseRPCImport = rpcImport; vm.CanUseRPCImport = rpcImport;
vm.CanUseTaproot = TaprootSupported(vm.CryptoCode); vm.SupportTaproot = network.NBitcoinNetwork.Consensus.SupportTaproot;
vm.SupportSegwit = network.NBitcoinNetwork.Consensus.SupportSegwit;
vm.IsTaprootActivated = TaprootActivated(vm.CryptoCode);
vm.RootKeyPath = network.GetRootKeyPath(); vm.RootKeyPath = network.GetRootKeyPath();
vm.Network = network; vm.Network = network;
@@ -266,14 +265,11 @@ namespace BTCPayServer.Controllers
IsHotWallet = isImport ? request.SavePrivateKeys : method == WalletSetupMethod.HotWallet, IsHotWallet = isImport ? request.SavePrivateKeys : method == WalletSetupMethod.HotWallet,
DerivationSchemeFormat = "BTCPay", DerivationSchemeFormat = "BTCPay",
CanUseHotWallet = hotWallet, CanUseHotWallet = hotWallet,
CanUseRPCImport = rpcImport CanUseRPCImport = rpcImport,
IsTaprootActivated = TaprootActivated(cryptoCode),
SupportTaproot = network.NBitcoinNetwork.Consensus.SupportTaproot,
SupportSegwit = network.NBitcoinNetwork.Consensus.SupportSegwit
}; };
if (request.ScriptPubKeyType == ScriptPubKeyType.TaprootBIP86 && !TaprootSupported(cryptoCode) )
{
ModelState.AddModelError(nameof(request.ScriptPubKeyType), $"Taproot not supported");
return View(vm.ViewName, vm);
}
if (isImport && string.IsNullOrEmpty(request.ExistingMnemonic)) if (isImport && string.IsNullOrEmpty(request.ExistingMnemonic))
{ {

View File

@@ -146,11 +146,16 @@ namespace BTCPayServer.Controllers
} }
} }
public bool TaprootSupported(string crytoCode) public bool TaprootActivated(string crytoCode)
{ {
var networkSupport = ((BTCPayNetwork)_NetworkProvider.GetNetwork(crytoCode))?.NBitcoinNetwork?.Consensus?.SupportTaproot is true; var network = (BTCPayNetwork)_NetworkProvider.GetNetwork(crytoCode);
#pragma warning disable CS0618
if (!(network.IsBTC && network.NBitcoinNetwork.ChainName == ChainName.Mainnet))
// Consider it activated for everything that is not mainnet bitcoin
return true;
#pragma warning restore CS0618
var status = _Dashboard.Get(crytoCode).Status; var status = _Dashboard.Get(crytoCode).Status;
return networkSupport && !(status.NetworkType == ChainName.Mainnet && status.ChainHeight < 709632); return status.ChainHeight >= 709632;
} }

View File

@@ -39,8 +39,10 @@ namespace BTCPayServer.Models.StoreViewModels
public bool CanUseHotWallet { get; set; } public bool CanUseHotWallet { get; set; }
[Display(Name = "Can use RPC import")] [Display(Name = "Can use RPC import")]
public bool CanUseRPCImport { get; set; } public bool CanUseRPCImport { get; set; }
[Display(Name = "Can use Taproot")] public bool SupportSegwit { get; set; }
public bool CanUseTaproot { get; set; } public bool SupportTaproot { get; set; }
[Display(Name = "Is taproot activated")]
public bool IsTaprootActivated { get; set; }
public RootedKeyPath GetAccountKeypath() public RootedKeyPath GetAccountKeypath()
{ {
if (KeyPath != null && RootFingerprint != null && if (KeyPath != null && RootFingerprint != null &&

View File

@@ -7,7 +7,9 @@
ViewData.SetActivePageAndTitle(StoreNavPages.Wallet, $"Create {Model.CryptoCode} {type} Wallet", Context.GetStoreData().StoreName); ViewData.SetActivePageAndTitle(StoreNavPages.Wallet, $"Create {Model.CryptoCode} {type} Wallet", Context.GetStoreData().StoreName);
ViewData.Add(nameof(Model.CanUseHotWallet), Model.CanUseHotWallet); ViewData.Add(nameof(Model.CanUseHotWallet), Model.CanUseHotWallet);
ViewData.Add(nameof(Model.CanUseRPCImport), Model.CanUseRPCImport); ViewData.Add(nameof(Model.CanUseRPCImport), Model.CanUseRPCImport);
ViewData.Add(nameof(Model.CanUseTaproot), Model.CanUseTaproot); ViewData.Add(nameof(Model.IsTaprootActivated), Model.IsTaprootActivated);
ViewData.Add(nameof(Model.SupportSegwit), Model.SupportSegwit);
ViewData.Add(nameof(Model.SupportTaproot), Model.SupportTaproot);
ViewData.Add(nameof(Model.Method), Model.Method); ViewData.Add(nameof(Model.Method), Model.Method);
} }

View File

@@ -21,7 +21,9 @@
{ {
ViewData.Add(nameof(Model.CanUseHotWallet), Model.CanUseHotWallet); ViewData.Add(nameof(Model.CanUseHotWallet), Model.CanUseHotWallet);
ViewData.Add(nameof(Model.CanUseRPCImport), Model.CanUseRPCImport); ViewData.Add(nameof(Model.CanUseRPCImport), Model.CanUseRPCImport);
ViewData.Add(nameof(Model.CanUseTaproot), Model.CanUseTaproot); ViewData.Add(nameof(Model.IsTaprootActivated), Model.IsTaprootActivated);
ViewData.Add(nameof(Model.SupportSegwit), Model.SupportSegwit);
ViewData.Add(nameof(Model.SupportTaproot), Model.SupportTaproot);
ViewData.Add(nameof(Model.Method), Model.Method); ViewData.Add(nameof(Model.Method), Model.Method);
<partial name="_GenerateWalletForm" model="Model.SetupRequest" /> <partial name="_GenerateWalletForm" model="Model.SetupRequest" />

View File

@@ -47,32 +47,35 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> @if (Model.SupportSegwit)
<td rowspan="4">P2WPKH</td> {
<td class="font-monospace">xpub…</td> <tr>
</tr> <td rowspan="4">P2WPKH</td>
<tr> <td class="font-monospace">xpub…</td>
<td class="font-monospace">zpub…</td> </tr>
</tr> <tr>
<tr> <td class="font-monospace">zpub…</td>
<td class="font-monospace">wpkh(xpub…/0/*)</td> </tr>
</tr> <tr>
<tr> <td class="font-monospace">wpkh(xpub…/0/*)</td>
<td class="font-monospace">wpkh([…/84'/0'/0']xpub…/0/*)</td> </tr>
</tr> <tr>
<tr> <td class="font-monospace">wpkh([…/84'/0'/0']xpub…/0/*)</td>
<td rowspan="4">P2SH-P2WPKH</td> </tr>
<td class="font-monospace">xpub…-[p2sh]</td> <tr>
</tr> <td rowspan="4">P2SH-P2WPKH</td>
<tr> <td class="font-monospace">xpub…-[p2sh]</td>
<td class="font-monospace">ypub…</td> </tr>
</tr> <tr>
<tr> <td class="font-monospace">ypub…</td>
<td class="font-monospace">sh(wpkh(xpub…/0/*)</td> </tr>
</tr> <tr>
<tr> <td class="font-monospace">sh(wpkh(xpub…/0/*)</td>
<td class="font-monospace">sh(wpkh([…/49'/0'/0']xpub…/0/*)</td> </tr>
</tr> <tr>
<td class="font-monospace">sh(wpkh([…/49'/0'/0']xpub…/0/*)</td>
</tr>
}
<tr> <tr>
<td rowspan="3">P2PKH</td> <td rowspan="3">P2PKH</td>
<td class="font-monospace">xpub…-[legacy]</td> <td class="font-monospace">xpub…-[legacy]</td>
@@ -83,7 +86,7 @@
<tr> <tr>
<td class="font-monospace">pkh(xpub…/0/*)</td> <td class="font-monospace">pkh(xpub…/0/*)</td>
</tr> </tr>
@if (Model.CanUseTaproot) @if (Model.SupportTaproot && Model.IsTaprootActivated)
{ {
<tr> <tr>
<td rowspan="1">P2TR</td> <td rowspan="1">P2TR</td>

View File

@@ -7,7 +7,7 @@
var isHotWallet = method is WalletSetupMethod.HotWallet; var isHotWallet = method is WalletSetupMethod.HotWallet;
var canUseHotWallet = ViewData["CanUseHotWallet"] is true; var canUseHotWallet = ViewData["CanUseHotWallet"] is true;
var canUseRpcImport = ViewData["CanUseRPCImport"] is true; var canUseRpcImport = ViewData["CanUseRPCImport"] is true;
var canUseTaproot = ViewData["CanUseTaproot"] is true; var isTaprootActivated = ViewData["IsTaprootActivated"] is true;
} }
@if (!User.IsInRole(Roles.ServerAdmin)) @if (!User.IsInRole(Roles.ServerAdmin))
@@ -34,12 +34,27 @@
<div class="form-group"> <div class="form-group">
<label asp-for="ScriptPubKeyType" class="form-label">Address type</label> <label asp-for="ScriptPubKeyType" class="form-label">Address type</label>
<select class="form-select w-auto" asp-for="ScriptPubKeyType"> <select class="form-select w-auto" asp-for="ScriptPubKeyType">
<option value="@ScriptPubKeyType.Segwit">Segwit (Recommended, cheapest transaction fee)</option> @if (ViewData["SupportSegwit"] is true)
<option value="@ScriptPubKeyType.SegwitP2SH">Segwit wrapped (Compatible with old wallets)</option>
<option value="@ScriptPubKeyType.Legacy">Legacy (Not recommended)</option>
@if (canUseTaproot)
{ {
<option value="@ScriptPubKeyType.TaprootBIP86">Taproot (ONLY FOR DEVELOPMENT)</option> <option value="@ScriptPubKeyType.Segwit">Segwit (Recommended)</option>
<option value="@ScriptPubKeyType.SegwitP2SH">Segwit wrapped (Compatible with old wallets)</option>
<option value="@ScriptPubKeyType.Legacy">Legacy (Not recommended)</option>
}
else
{
<option value="@ScriptPubKeyType.Legacy">Legacy</option>
}
@if (ViewData["SupportTaproot"] is true)
{
@if (isTaprootActivated)
{
<option value="@ScriptPubKeyType.TaprootBIP86">Taproot (For advanced users)</option>
}
else
{
<option value="@ScriptPubKeyType.TaprootBIP86" disabled>Taproot (Available from block 709632)</option>
}
} }
</select> </select>
<span asp-validation-for="ScriptPubKeyType" class="text-danger"></span> <span asp-validation-for="ScriptPubKeyType" class="text-danger"></span>