Skip to content

Commit fabe399

Browse files
committed
Fix: Incorrect Redeem for non p2sh or p2wsh in Miniscript.ToScripts
1 parent 4480461 commit fabe399

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

NBitcoin.Tests/MiniscriptTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,39 @@ public void CanGenerateSegwitAndTaprootFromMiniscript(string str, ScriptPubKeyTy
223223
Assert.Equal(str, policy.DescriptorTemplate.ToString());
224224
}
225225

226+
[Fact]
227+
public void CanGenerateScripts()
228+
{
229+
var settings = new MiniscriptParsingSettings(Network.RegTest)
230+
{
231+
Dialect = MiniscriptDialect.BIP388,
232+
AllowedParameters = ParameterTypeFlags.All
233+
};
234+
var script = Miniscript.Parse("pkh([aaaaaaaa/44h/1h/0h]tpubDDV486pBqkML6Ywhznz8DS3VS95h3q4A2pUMCc6yy739QpKMg3gA8EXGrjraDBDxrhLsezepjCEfBtak5wngDH4vMh6aXKV8hPN7JsMtdEf/<0;1>/*)", settings);
235+
var expectedScripts = script.Derive(AddressIntent.Deposit, 0).Miniscript.ToScripts();
236+
Assert.Equal("76a914bc1bf603880f28ffaf9c888b5660e9adf8dcadac88ac", expectedScripts.ScriptPubKey.ToHex());
237+
Assert.Equal("76a914bc1bf603880f28ffaf9c888b5660e9adf8dcadac88ac", expectedScripts.ScriptCode.ToHex());
238+
Assert.Null(expectedScripts.RedeemScript);
239+
240+
script = Miniscript.Parse("sh(pkh([aaaaaaaa/44h/1h/0h]tpubDDV486pBqkML6Ywhznz8DS3VS95h3q4A2pUMCc6yy739QpKMg3gA8EXGrjraDBDxrhLsezepjCEfBtak5wngDH4vMh6aXKV8hPN7JsMtdEf/<0;1>/*))", settings);
241+
expectedScripts = script.Derive(AddressIntent.Deposit, 0).Miniscript.ToScripts();
242+
Assert.Equal("a91498062e6879a7b6643735a626ac129db470087a2f87", expectedScripts.ScriptPubKey.ToHex());
243+
Assert.Equal("76a914bc1bf603880f28ffaf9c888b5660e9adf8dcadac88ac", expectedScripts.ScriptCode.ToHex());
244+
Assert.Equal("76a914bc1bf603880f28ffaf9c888b5660e9adf8dcadac88ac", expectedScripts.RedeemScript.ToHex());
245+
246+
script = Miniscript.Parse("wsh(pkh([aaaaaaaa/44h/1h/0h]tpubDDV486pBqkML6Ywhznz8DS3VS95h3q4A2pUMCc6yy739QpKMg3gA8EXGrjraDBDxrhLsezepjCEfBtak5wngDH4vMh6aXKV8hPN7JsMtdEf/<0;1>/*))", settings);
247+
expectedScripts = script.Derive(AddressIntent.Deposit, 0).Miniscript.ToScripts();
248+
Assert.Equal("0020df3d2f624d5744aa959d0e87cfdfb33dec486a329aee2aeee8da17c98f7e999f", expectedScripts.ScriptPubKey.ToHex());
249+
Assert.Equal("76a914bc1bf603880f28ffaf9c888b5660e9adf8dcadac88ac", expectedScripts.ScriptCode.ToHex());
250+
Assert.Equal("76a914bc1bf603880f28ffaf9c888b5660e9adf8dcadac88ac", expectedScripts.RedeemScript.ToHex());
251+
252+
script = Miniscript.Parse("sh(wsh(pkh([aaaaaaaa/44h/1h/0h]tpubDDV486pBqkML6Ywhznz8DS3VS95h3q4A2pUMCc6yy739QpKMg3gA8EXGrjraDBDxrhLsezepjCEfBtak5wngDH4vMh6aXKV8hPN7JsMtdEf/<0;1>/*)))", settings);
253+
expectedScripts = script.Derive(AddressIntent.Deposit, 0).Miniscript.ToScripts();
254+
Assert.Equal("a914151fd2c5490f9a6488a72fad3d8fa7bd1e3fab3387", expectedScripts.ScriptPubKey.ToHex());
255+
Assert.Equal("76a914bc1bf603880f28ffaf9c888b5660e9adf8dcadac88ac", expectedScripts.ScriptCode.ToHex());
256+
Assert.Equal("76a914bc1bf603880f28ffaf9c888b5660e9adf8dcadac88ac", expectedScripts.RedeemScript.ToHex());
257+
}
258+
226259
[Fact]
227260
public void CanGenerateSH()
228261
{

NBitcoin/WalletPolicies/Miniscript.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,13 @@ public MiniscriptParsingSettings(Network network, KeyType? defaultKeyType = null
9191
/// </summary>
9292
public class Miniscript
9393
{
94-
public record Scripts(Script ScriptPubKey, Script? RedeemScript);
94+
/// <summary>
95+
/// Scripts generated by the Miniscript
96+
/// </summary>
97+
/// <param name="ScriptPubKey">The script that appears in the <see cref="TxOut.ScriptPubKey"></see></param>
98+
/// <param name="RedeemScript">The script that must be pushed in the <see cref="TxIn.WitScript"></see> for WSH outputs, or <see cref="TxIn.ScriptSig"></see> for non-segwit P2SH outputs</param>
99+
/// <param name="ScriptCode">The script that must be included in the hash algorithm used for signing the input.</param>
100+
public record Scripts(Script ScriptPubKey, Script? RedeemScript, Script? ScriptCode);
95101
public record TaprootInfo(TaprootInternalPubKey InternalPubKey, uint256? MerkleRoot);
96102
public MiniscriptNode RootNode { get; }
97103
public IReadOnlyDictionary<string, IReadOnlyCollection<MiniscriptNode.Parameter>> Parameters { get; }
@@ -730,10 +736,14 @@ public Scripts ToScripts()
730736
if (Parameters.Count > 0)
731737
throw new InvalidOperationException("Impossible to generate a script while parameters haven't been set. Use ToScriptString() if you want a user-readable representation instead.");
732738
var scriptPubKey = RootNode.GetScript();
739+
Script? scriptCode = null;
733740
Script? redeem = null;
734741
if (GetScriptCodeNode(RootNode) is { } n)
735-
redeem = n.GetScript();
736-
return new(scriptPubKey, redeem);
742+
scriptCode = n.GetScript();
743+
if (RootNode is Fragment f &&
744+
(f.Descriptor == FragmentDescriptor.wsh || f.Descriptor == FragmentDescriptor.sh))
745+
redeem = scriptCode;
746+
return new(scriptPubKey, redeem, scriptCode);
737747
}
738748

739749
/// <summary>
@@ -804,7 +814,7 @@ public DerivationResult[] Derive(DeriveParameters parameters)
804814
}
805815

806816
/// <summary>
807-
/// Make the miniscript more readable by removing HDKeys (such as [fingerprint]xpub/<0;1>/*) by key placeholders (such as @0/<0;1>/*). It is the reverse operation of <see cref="ReplaceKeyPlaceholdersByHDKeys(HDKeyNode[])"/>
817+
/// Make the miniscript more readable by removing HDKeys (such as [fingerprint]xpub/&lt;0;1&gt;/*) by key placeholders (such as @0/&lt;0;1&gt;/*). It is the reverse operation of <see cref="ReplaceKeyPlaceholdersByHDKeys(HDKeyNode[])"/>
808818
/// </summary>
809819
/// <returns>The modified <see cref="Miniscript"/></returns>
810820
public Miniscript ReplaceHDKeysByKeyPlaceholders(out HDKeyNode[] keys)

NBitcoin/WalletPolicies/MiniscriptNode.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ public PubKey GetAggregatePubKey()
529529
/// <param name="DepositIndex"></param>
530530
/// <param name="ChangeIndex"></param>
531531
/// <param name="Target"></param>
532-
/// <param name="ShortForm">If <0;1>/* path should be be noted /** instead</param>
532+
/// <param name="ShortForm">If &lt;0;1&gt;/* path should be be noted /** instead</param>
533533
public record MultipathNode(int DepositIndex, int ChangeIndex, MiniscriptNode Target, bool ShortForm) : MiniscriptNode
534534
{
535535
internal static MultipathNode Parse(string str, Network network)

0 commit comments

Comments
 (0)