Skip to content

Commit 58aa810

Browse files
committed
Don't use nullable script tree/script root parameters in Script.pay2tr()
Users had to cast null to ByteVector32?/ScriptTree? which was ugly. Now they have to pass in either an explicit script/script root or use an explicit TaprootTweak.
1 parent c9e7181 commit 58aa810

File tree

5 files changed

+15
-14
lines changed

5 files changed

+15
-14
lines changed

src/commonMain/kotlin/fr/acinq/bitcoin/Script.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -480,19 +480,19 @@ public object Script {
480480

481481
/**
482482
* @param internalKey internal public key that will be tweaked with the [scripts] provided.
483-
* @param scripts optional spending scripts that can be used instead of key-path spending.
483+
* @param scripts spending script tree.
484484
*/
485485
@JvmStatic
486-
public fun pay2tr(internalKey: XonlyPublicKey, scripts: ScriptTree?): List<ScriptElt> = pay2tr(internalKey, scripts?.hash())
486+
public fun pay2tr(internalKey: XonlyPublicKey, scripts: ScriptTree): List<ScriptElt> =
487+
pay2tr(internalKey, scripts.hash())
487488

488489
/**
489490
* @param internalKey internal public key that will be tweaked with the [scriptsRoot] provided.
490-
* @param scriptsRoot optional merkle root of the spending scripts that can be used instead of key-path spending.
491+
* @param scriptsRoot merkle root of the spending script tree.
491492
*/
492493
@JvmStatic
493-
public fun pay2tr(internalKey: XonlyPublicKey, scriptsRoot: ByteVector32?): List<ScriptElt> {
494-
val tweak = scriptsRoot?.let { Crypto.TaprootTweak.ScriptPathTweak(it) } ?: Crypto.TaprootTweak.KeyPathTweak
495-
return pay2tr(internalKey, tweak)
494+
public fun pay2tr(internalKey: XonlyPublicKey, scriptsRoot: ByteVector32): List<ScriptElt> {
495+
return pay2tr(internalKey, Crypto.TaprootTweak.ScriptPathTweak(scriptsRoot))
496496
}
497497

498498
/**

src/commonTest/kotlin/fr/acinq/bitcoin/TaprootTestsCommon.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class TaprootTestsCommon {
3030
val (_, master) = DeterministicWallet.ExtendedPrivateKey.decode("tprv8ZgxMBicQKsPeQQADibg4WF7mEasy3piWZUHyThAzJCPNgMHDVYhTCVfev3jFbDhcYm4GimeFMbbi9z1d9rfY1aL5wfJ9mNebQ4thJ62EJb")
3131
val key = DeterministicWallet.derivePrivateKey(master, "86'/1'/0'/0/1")
3232
val internalKey = key.publicKey.xOnly()
33-
val script = Script.pay2tr(internalKey, scripts = null)
33+
val script = Script.pay2tr(internalKey, Crypto.TaprootTweak.KeyPathTweak)
3434
val outputKey = internalKey.outputKey(Crypto.TaprootTweak.KeyPathTweak).first
3535
assertEquals("tb1phlhs7afhqzkgv0n537xs939s687826vn8l24ldkrckvwsnlj3d7qj6u57c", internalKey.p2trAddress(Block.Testnet3GenesisBlock.hash))
3636

@@ -79,7 +79,7 @@ class TaprootTestsCommon {
7979
val tx = Transaction.read(
8080
"02000000000101bf77ef36f2c0f32e0822cef0514948254997495a34bfba7dd4a73aabfcbb87900000000000fdffffff02c2c2000000000000160014b5c3dbfeb8e7d0c809c3ba3f815fd430777ef4be50c30000000000002251208c5db7f797196d6edc4dd7df6048f4ea6b883a6af6af032342088f436543790f0140583f758bea307216e03c1f54c3c6088e8923c8e1c89d96679fb00de9e808a79d0fba1cc3f9521cb686e8f43fb37cc6429f2e1480c70cc25ecb4ac0dde8921a01f1f70000"
8181
)
82-
assertEquals(Script.pay2tr(internalKey, scripts = null), Script.parse(tx.txOut[1].publicKeyScript))
82+
assertEquals(Script.pay2tr(internalKey, Crypto.TaprootTweak.KeyPathTweak), Script.parse(tx.txOut[1].publicKeyScript))
8383

8484
// we want to spend
8585
val outputScript = addressToPublicKeyScript(Block.Testnet3GenesisBlock.hash, "tb1pn3g330w4n5eut7d4vxq0pp303267qc6vg8d2e0ctjuqre06gs3yqnc5yx0").right!!

src/commonTest/kotlin/fr/acinq/bitcoin/psbt/PsbtTestsCommon.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,9 +1485,9 @@ class PsbtTestsCommon {
14851485
// We make sure our utxos come from transactions with multiple outputs and are at different indices.
14861486
val utxos = listOf(
14871487
// @formatter:off
1488-
Transaction(version = 2, txIn = listOf(), txOut = listOf(TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef"))), TxOut(100_000.sat(), Script.pay2tr(getPublicKey(0), scripts = null))), lockTime = 0),
1489-
Transaction(version = 2, txIn = listOf(), txOut = listOf(TxOut(110_000.sat(), Script.pay2tr(getPublicKey(1), scripts = null)), TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef")))), lockTime = 0),
1490-
Transaction(version = 2, txIn = listOf(), txOut = listOf(TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef"))), TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef"))), TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef"))), TxOut(200_000.sat(), Script.pay2tr(getPublicKey(2), scripts = null))), lockTime = 0),
1488+
Transaction(version = 2, txIn = listOf(), txOut = listOf(TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef"))), TxOut(100_000.sat(), Script.pay2tr(getPublicKey(0), Crypto.TaprootTweak.KeyPathTweak))), lockTime = 0),
1489+
Transaction(version = 2, txIn = listOf(), txOut = listOf(TxOut(110_000.sat(), Script.pay2tr(getPublicKey(1), Crypto.TaprootTweak.KeyPathTweak)), TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef")))), lockTime = 0),
1490+
Transaction(version = 2, txIn = listOf(), txOut = listOf(TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef"))), TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef"))), TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef"))), TxOut(200_000.sat(), Script.pay2tr(getPublicKey(2), Crypto.TaprootTweak.KeyPathTweak))), lockTime = 0),
14911491
Transaction(version = 2, txIn = listOf(), txOut = listOf(TxOut(5_000.sat(), Script.pay2wsh(ByteVector("deadbeef"))), TxOut(50_000.sat(), Script.pay2pkh(p2pkhPriv.publicKey()))), lockTime = 0),
14921492
// @formatter:on
14931493
)

src/commonTest/kotlin/fr/acinq/bitcoin/reference/BIP341TestsCommon.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,13 @@ class BIP341TestsCommon {
8989
}
9090

9191
val intermediary = it.jsonObject["intermediary"]!!.jsonObject
92-
val (tweakedKey, _) = internalPubkey.outputKey(scriptTree?.hash()?.let { Crypto.TaprootTweak.ScriptPathTweak(it) } ?: Crypto.TaprootTweak.KeyPathTweak)
92+
val tweak = scriptTree?.hash()?.let { Crypto.TaprootTweak.ScriptPathTweak(it) } ?: Crypto.TaprootTweak.KeyPathTweak
93+
val (tweakedKey, _) = internalPubkey.outputKey(tweak)
9394
scriptTree?.let { assertEquals(ByteVector32(intermediary["merkleRoot"]!!.jsonPrimitive.content), it.hash()) }
9495
assertEquals(ByteVector32(intermediary["tweakedPubkey"]!!.jsonPrimitive.content), tweakedKey.value)
9596

9697
val expected = it.jsonObject["expected"]!!.jsonObject
97-
val script = Script.pay2tr(internalPubkey, scriptTree)
98+
val script = Script.pay2tr(internalPubkey, tweak)
9899
assertEquals(ByteVector(expected["scriptPubKey"]!!.jsonPrimitive.content), Script.write(script).byteVector())
99100
val bip350Address = Bech32.encodeWitnessAddress("bc", 1.toByte(), tweakedKey.value.toByteArray())
100101
assertEquals(expected["bip350Address"]!!.jsonPrimitive.content, bip350Address)

src/commonTest/kotlin/fr/acinq/bitcoin/reference/ScriptTestsCommon.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ class ScriptTestsCommon {
193193
}
194194
val witness = ScriptWitness(witnessStack)
195195
val scriptPubKey = if (scriptPubKeyText == "0x51 0x20 #TAPROOTOUTPUT#") {
196-
Script.write(Script.pay2tr(priv.xOnlyPublicKey(), leaf))
196+
Script.write(Script.pay2tr(priv.xOnlyPublicKey(), leaf?.let { Crypto.TaprootTweak.ScriptPathTweak(it.hash()) } ?: Crypto.TaprootTweak.KeyPathTweak))
197197
} else {
198198
parseFromText(scriptPubKeyText)
199199
}

0 commit comments

Comments
 (0)