From 016523dc8496452581c39b4bfd83a8b03c31e20a Mon Sep 17 00:00:00 2001 From: sstone Date: Thu, 8 Aug 2024 20:07:35 +0200 Subject: [PATCH] Add support for testnet4 --- .../kotlin/fr/acinq/bitcoin/Bech32.kt | 3 +- .../kotlin/fr/acinq/bitcoin/Bitcoin.kt | 17 ++++---- .../kotlin/fr/acinq/bitcoin/Block.kt | 37 ++++++++++++++++- .../kotlin/fr/acinq/bitcoin/Descriptor.kt | 2 +- .../kotlin/fr/acinq/bitcoin/PublicKey.kt | 4 +- .../fr/acinq/bitcoin/BIP49TestsCommon.kt | 2 +- .../fr/acinq/bitcoin/BIP86TestsCommon.kt | 4 +- .../fr/acinq/bitcoin/BitcoinTestsCommon.kt | 41 ++++++++++++------- .../bitcoin/DeriveWalletKeysTestsCommon.kt | 8 ++-- .../fr/acinq/bitcoin/TaprootTestsCommon.kt | 6 +-- 10 files changed, 87 insertions(+), 37 deletions(-) diff --git a/src/commonMain/kotlin/fr/acinq/bitcoin/Bech32.kt b/src/commonMain/kotlin/fr/acinq/bitcoin/Bech32.kt index 19ca785a..2c0b75b4 100644 --- a/src/commonMain/kotlin/fr/acinq/bitcoin/Bech32.kt +++ b/src/commonMain/kotlin/fr/acinq/bitcoin/Bech32.kt @@ -48,7 +48,8 @@ public object Bech32 { @JvmStatic public fun hrp(chainHash: BlockHash): String = when (chainHash) { - Block.TestnetGenesisBlock.hash -> "tb" + Block.Testnet4GenesisBlock.hash -> "tb" + Block.Testnet3GenesisBlock.hash -> "tb" Block.SignetGenesisBlock.hash -> "tb" Block.RegtestGenesisBlock.hash -> "bcrt" Block.LivenetGenesisBlock.hash -> "bc" diff --git a/src/commonMain/kotlin/fr/acinq/bitcoin/Bitcoin.kt b/src/commonMain/kotlin/fr/acinq/bitcoin/Bitcoin.kt index 2637b59c..990744a3 100644 --- a/src/commonMain/kotlin/fr/acinq/bitcoin/Bitcoin.kt +++ b/src/commonMain/kotlin/fr/acinq/bitcoin/Bitcoin.kt @@ -116,7 +116,7 @@ public object Bitcoin { Script.isPay2pkh(pubkeyScript) -> { val prefix = when (chainHash) { Block.LivenetGenesisBlock.hash -> Base58.Prefix.PubkeyAddress - Block.TestnetGenesisBlock.hash, Block.RegtestGenesisBlock.hash, Block.SignetGenesisBlock.hash -> Base58.Prefix.PubkeyAddressTestnet + Block.Testnet4GenesisBlock.hash, Block.Testnet3GenesisBlock.hash, Block.RegtestGenesisBlock.hash, Block.SignetGenesisBlock.hash -> Base58.Prefix.PubkeyAddressTestnet else -> return Either.Left(BitcoinError.InvalidChainHash) } Either.Right(Base58Check.encode(prefix, (pubkeyScript[2] as OP_PUSHDATA).data)) @@ -125,7 +125,7 @@ public object Bitcoin { Script.isPay2sh(pubkeyScript) -> { val prefix = when (chainHash) { Block.LivenetGenesisBlock.hash -> Base58.Prefix.ScriptAddress - Block.TestnetGenesisBlock.hash, Block.RegtestGenesisBlock.hash, Block.SignetGenesisBlock.hash -> Base58.Prefix.ScriptAddressTestnet + Block.Testnet4GenesisBlock.hash, Block.Testnet3GenesisBlock.hash, Block.RegtestGenesisBlock.hash, Block.SignetGenesisBlock.hash -> Base58.Prefix.ScriptAddressTestnet else -> return Either.Left(BitcoinError.InvalidChainHash) } Either.Right(Base58Check.encode(prefix, (pubkeyScript[1] as OP_PUSHDATA).data)) @@ -204,13 +204,13 @@ public object Bitcoin { return runCatching { Base58Check.decode(address) }.fold( onSuccess = { when { - it.first == Base58.Prefix.PubkeyAddressTestnet && (chainHash == Block.TestnetGenesisBlock.hash || chainHash == Block.RegtestGenesisBlock.hash || chainHash == Block.SignetGenesisBlock.hash) -> + it.first == Base58.Prefix.PubkeyAddressTestnet && (chainHash == Block.Testnet4GenesisBlock.hash || chainHash == Block.Testnet3GenesisBlock.hash || chainHash == Block.RegtestGenesisBlock.hash || chainHash == Block.SignetGenesisBlock.hash) -> Either.Right(Script.pay2pkh(it.second)) it.first == Base58.Prefix.PubkeyAddress && chainHash == Block.LivenetGenesisBlock.hash -> Either.Right(Script.pay2pkh(it.second)) - it.first == Base58.Prefix.ScriptAddressTestnet && (chainHash == Block.TestnetGenesisBlock.hash || chainHash == Block.RegtestGenesisBlock.hash || chainHash == Block.SignetGenesisBlock.hash) -> + it.first == Base58.Prefix.ScriptAddressTestnet && (chainHash == Block.Testnet4GenesisBlock.hash || chainHash == Block.Testnet3GenesisBlock.hash || chainHash == Block.RegtestGenesisBlock.hash || chainHash == Block.SignetGenesisBlock.hash) -> Either.Right(listOf(OP_HASH160, OP_PUSHDATA(it.second), OP_EQUAL)) it.first == Base58.Prefix.ScriptAddress && chainHash == Block.LivenetGenesisBlock.hash -> @@ -227,7 +227,8 @@ public object Bitcoin { witnessVersion == null -> Either.Left(BitcoinError.InvalidWitnessVersion(it.second.toInt())) it.third.size != 20 && it.third.size != 32 -> Either.Left(BitcoinError.InvalidBech32Address) it.first == "bc" && chainHash == Block.LivenetGenesisBlock.hash -> Either.Right(listOf(witnessVersion, OP_PUSHDATA(it.third))) - it.first == "tb" && chainHash == Block.TestnetGenesisBlock.hash -> Either.Right(listOf(witnessVersion, OP_PUSHDATA(it.third))) + it.first == "tb" && chainHash == Block.Testnet4GenesisBlock.hash -> Either.Right(listOf(witnessVersion, OP_PUSHDATA(it.third))) + it.first == "tb" && chainHash == Block.Testnet3GenesisBlock.hash -> Either.Right(listOf(witnessVersion, OP_PUSHDATA(it.third))) it.first == "tb" && chainHash == Block.SignetGenesisBlock.hash -> Either.Right(listOf(witnessVersion, OP_PUSHDATA(it.third))) it.first == "bcrt" && chainHash == Block.RegtestGenesisBlock.hash -> Either.Right(listOf(witnessVersion, OP_PUSHDATA(it.third))) else -> Either.Left(BitcoinError.ChainHashMismatch) @@ -244,12 +245,14 @@ public object Bitcoin { public sealed class Chain(public val name: String, private val genesis: Block) { public object Regtest : Chain("Regtest", Block.RegtestGenesisBlock) - public object Testnet : Chain("Testnet", Block.TestnetGenesisBlock) + public object Testnet : Chain("Testnet", Block.Testnet3GenesisBlock) + public object Testnet4 : Chain("Testnet4", Block.Testnet4GenesisBlock) public object Signet : Chain("Signet", Block.SignetGenesisBlock) public object Mainnet : Chain("Mainnet", Block.LivenetGenesisBlock) public fun isMainnet(): Boolean = this is Mainnet - public fun isTestnet(): Boolean = this is Testnet + public fun isTestnet(): Boolean = this is Testnet || this is Testnet4 + public fun isTestnet4(): Boolean = this is Testnet4 public val chainHash: BlockHash get() = genesis.hash diff --git a/src/commonMain/kotlin/fr/acinq/bitcoin/Block.kt b/src/commonMain/kotlin/fr/acinq/bitcoin/Block.kt index 78629086..0ebd9c93 100644 --- a/src/commonMain/kotlin/fr/acinq/bitcoin/Block.kt +++ b/src/commonMain/kotlin/fr/acinq/bitcoin/Block.kt @@ -367,10 +367,45 @@ public data class Block(@JvmField val header: BlockHeader, @JvmField val tx: Lis } @JvmField - public val TestnetGenesisBlock: Block = LivenetGenesisBlock.copy( + public val Testnet3GenesisBlock: Block = LivenetGenesisBlock.copy( header = LivenetGenesisBlock.header.copy(time = 1296688602, nonce = 414098458) ) + @JvmField + @Deprecated("testnet is the deprecated testnet3 network, use testnet3 explicitly", replaceWith = ReplaceWith("Testnet3GenesisBlock", "fr.acinq.bitcoin.Block")) + public val TestnetGenesisBlock: Block = Testnet3GenesisBlock + + @JvmField + public val Testnet4GenesisBlock: Block = run { + val script = listOf( + OP_PUSHDATA(writeUInt32(486604799u)), + OP_PUSHDATA(ByteVector("04")), + OP_PUSHDATA("03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e".encodeToByteArray()) + ) + val scriptPubKey = listOf( + OP_PUSHDATA(ByteVector("000000000000000000000000000000000000000000000000000000000000000000")), + OP_CHECKSIG + ) + Block( + BlockHeader( + version = 1, + hashPreviousBlock = BlockHash(ByteVector32.Zeroes), + hashMerkleRoot = ByteVector32("7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e").reversed(), + time = 1714777860, + bits = 0x1d00ffff, + nonce = 393743547 + ), + listOf( + Transaction( + version = 1, + txIn = listOf(TxIn.coinbase(script)), + txOut = listOf(TxOut(amount = 5000000000.toSatoshi(), publicKeyScript = scriptPubKey)), + lockTime = 0 + ) + ) + ) + } + @JvmField public val RegtestGenesisBlock: Block = LivenetGenesisBlock.copy( header = LivenetGenesisBlock.header.copy( diff --git a/src/commonMain/kotlin/fr/acinq/bitcoin/Descriptor.kt b/src/commonMain/kotlin/fr/acinq/bitcoin/Descriptor.kt index 5cf1c352..1d379ddf 100644 --- a/src/commonMain/kotlin/fr/acinq/bitcoin/Descriptor.kt +++ b/src/commonMain/kotlin/fr/acinq/bitcoin/Descriptor.kt @@ -67,7 +67,7 @@ public object Descriptor { } private fun getBIP84KeyPath(chainHash: BlockHash): Pair = when (chainHash) { - Block.RegtestGenesisBlock.hash, Block.TestnetGenesisBlock.hash -> "84'/1'/0'/0" to DeterministicWallet.tpub + Block.Testnet4GenesisBlock.hash, Block.Testnet3GenesisBlock.hash, Block.RegtestGenesisBlock.hash -> "84'/1'/0'/0" to DeterministicWallet.tpub Block.LivenetGenesisBlock.hash -> "84'/0'/0'/0" to DeterministicWallet.xpub else -> error("invalid chain hash $chainHash") } diff --git a/src/commonMain/kotlin/fr/acinq/bitcoin/PublicKey.kt b/src/commonMain/kotlin/fr/acinq/bitcoin/PublicKey.kt index 3428b66a..0b58516b 100644 --- a/src/commonMain/kotlin/fr/acinq/bitcoin/PublicKey.kt +++ b/src/commonMain/kotlin/fr/acinq/bitcoin/PublicKey.kt @@ -77,7 +77,7 @@ public data class PublicKey(@JvmField val value: ByteVector) { * @return the "legacy" p2pkh address for this key */ public fun p2pkhAddress(chainHash: BlockHash): String = when (chainHash) { - Block.TestnetGenesisBlock.hash, Block.RegtestGenesisBlock.hash, Block.SignetGenesisBlock.hash -> Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, hash160()) + Block.Testnet4GenesisBlock.hash, Block.Testnet3GenesisBlock.hash, Block.RegtestGenesisBlock.hash, Block.SignetGenesisBlock.hash -> Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, hash160()) Block.LivenetGenesisBlock.hash -> Base58Check.encode(Base58.Prefix.PubkeyAddress, hash160()) else -> error("invalid chain hash $chainHash") } @@ -91,7 +91,7 @@ public data class PublicKey(@JvmField val value: ByteVector) { val script = Script.pay2wpkh(this) val hash = Crypto.hash160(Script.write(script)) return when (chainHash) { - Block.TestnetGenesisBlock.hash, Block.RegtestGenesisBlock.hash, Block.SignetGenesisBlock.hash -> Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, hash) + Block.Testnet4GenesisBlock.hash, Block.Testnet3GenesisBlock.hash, Block.RegtestGenesisBlock.hash, Block.SignetGenesisBlock.hash -> Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, hash) Block.LivenetGenesisBlock.hash -> Base58Check.encode(Base58.Prefix.ScriptAddress, hash) else -> error("invalid chain hash $chainHash") } diff --git a/src/commonTest/kotlin/fr/acinq/bitcoin/BIP49TestsCommon.kt b/src/commonTest/kotlin/fr/acinq/bitcoin/BIP49TestsCommon.kt index fc488d4e..95bed5d1 100644 --- a/src/commonTest/kotlin/fr/acinq/bitcoin/BIP49TestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/bitcoin/BIP49TestsCommon.kt @@ -41,6 +41,6 @@ class BIP49TestsCommon { key.publicKey, PublicKey.fromHex("03a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f") ) - assertEquals(computeBIP49Address(key.publicKey, Block.TestnetGenesisBlock.hash), "2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2") + assertEquals(computeBIP49Address(key.publicKey, Block.Testnet3GenesisBlock.hash), "2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2") } } \ No newline at end of file diff --git a/src/commonTest/kotlin/fr/acinq/bitcoin/BIP86TestsCommon.kt b/src/commonTest/kotlin/fr/acinq/bitcoin/BIP86TestsCommon.kt index 84e13248..963c3ca5 100644 --- a/src/commonTest/kotlin/fr/acinq/bitcoin/BIP86TestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/bitcoin/BIP86TestsCommon.kt @@ -56,7 +56,7 @@ class BIP86TestsCommon { val internalKey = XonlyPublicKey(key.publicKey) val outputKey = internalKey.outputKey(Crypto.TaprootTweak.NoScriptTweak).first assertEquals("tb1phlhs7afhqzkgv0n537xs939s687826vn8l24ldkrckvwsnlj3d7qj6u57c", Bech32.encodeWitnessAddress("tb", 1, outputKey.value.toByteArray())) - assertEquals("tb1phlhs7afhqzkgv0n537xs939s687826vn8l24ldkrckvwsnlj3d7qj6u57c", internalKey.p2trAddress(Block.TestnetGenesisBlock.hash)) + assertEquals("tb1phlhs7afhqzkgv0n537xs939s687826vn8l24ldkrckvwsnlj3d7qj6u57c", internalKey.p2trAddress(Block.Testnet3GenesisBlock.hash)) } @Test @@ -78,7 +78,7 @@ class BIP86TestsCommon { val (_, master) = DeterministicWallet.ExtendedPrivateKey.decode("tprv8ZgxMBicQKsPdyyuveRPhVYogdPXBDqRiUXDo5TcLKe3f9YfonipqbgJD7pCXdovZTfTyj6SjZ928SkPunnDTiXV7Y2HSsG9XAGki6n8dRF") for (i in 0 until 10) { val key = DeterministicWallet.derivePrivateKey(master, "86'/1'/0'/0/$i") - assertEquals(expected[i], key.publicKey.p2trAddress(Block.TestnetGenesisBlock.hash)) + assertEquals(expected[i], key.publicKey.p2trAddress(Block.Testnet3GenesisBlock.hash)) } } } \ No newline at end of file diff --git a/src/commonTest/kotlin/fr/acinq/bitcoin/BitcoinTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/bitcoin/BitcoinTestsCommon.kt index 33bbcce7..e7e03e8c 100644 --- a/src/commonTest/kotlin/fr/acinq/bitcoin/BitcoinTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/bitcoin/BitcoinTestsCommon.kt @@ -35,7 +35,7 @@ class BitcoinTestsCommon { fun address(script: List, chainHash: BlockHash) = addressFromPublicKeyScript(chainHash, script) - listOf(Block.LivenetGenesisBlock.hash, Block.TestnetGenesisBlock.hash, Block.RegtestGenesisBlock.hash, Block.SignetGenesisBlock.hash).forEach { + listOf(Block.LivenetGenesisBlock.hash, Block.Testnet4GenesisBlock.hash, Block.Testnet3GenesisBlock.hash, Block.RegtestGenesisBlock.hash, Block.SignetGenesisBlock.hash).forEach { assertEquals(address(Script.pay2pkh(pub), it).right, computeP2PkhAddress(pub, it)) assertEquals(address(Script.pay2wpkh(pub), it).right, computeP2WpkhAddress(pub, it)) assertEquals(address(Script.pay2sh(Script.pay2wpkh(pub)), it).right, computeP2ShOfP2WpkhAddress(pub, it)) @@ -46,10 +46,13 @@ class BitcoinTestsCommon { } listOf( - Triple("0014d0b19277b0f76c9512f26d77573fd31a8fd15fc7", Block.TestnetGenesisBlock.hash, "tb1q6zceyaas7akf2yhjd4m4w07nr28azh78gw79kk"), - Triple("00203287047df2aa7aade3f394790a9c9d6f9235943f48a012e8a9f2c3300ca4f2d1", Block.TestnetGenesisBlock.hash, "tb1qx2rsgl0j4fa2mclnj3us48yad7frt9plfzsp969f7tpnqr9y7tgsyprxej"), - Triple("76a914b17deefe2feab87fef7221cf806bb8ca61f00fa188ac", Block.TestnetGenesisBlock.hash, "mwhSm2SHhRhd19KZyaQLgJyAtCLnkbzWbf"), - Triple("a914d3cf9d04f4ecc36df8207b300e46bc6775fc84c087", Block.TestnetGenesisBlock.hash, "2NCZBGzKadAnLv1ijAqhrKavMuqvxqu18yY"), + Triple("a91470cfd1da47df7e0bfef97e4aea54589bb8c0a53c87", Block.Testnet4GenesisBlock.hash, "2N3XidLXMNVBRq1ZReFepeV3DRRqBKgkrmK"), + Triple("76a914b37842f6d94aa536d3c20d85bd475112c53b409088ac", Block.Testnet4GenesisBlock.hash, "mwsuKK65jpjpYQoQih287zZXd7y6X8Gick"), + Triple("00148558348fde975686571524cb292fa491066a25af", Block.Testnet4GenesisBlock.hash, "tb1qs4vrfr77jatgv4c4yn9jjtayjyrx5fd0jmtnl8"), + Triple("0014d0b19277b0f76c9512f26d77573fd31a8fd15fc7", Block.Testnet3GenesisBlock.hash, "tb1q6zceyaas7akf2yhjd4m4w07nr28azh78gw79kk"), + Triple("00203287047df2aa7aade3f394790a9c9d6f9235943f48a012e8a9f2c3300ca4f2d1", Block.Testnet3GenesisBlock.hash, "tb1qx2rsgl0j4fa2mclnj3us48yad7frt9plfzsp969f7tpnqr9y7tgsyprxej"), + Triple("76a914b17deefe2feab87fef7221cf806bb8ca61f00fa188ac", Block.Testnet3GenesisBlock.hash, "mwhSm2SHhRhd19KZyaQLgJyAtCLnkbzWbf"), + Triple("a914d3cf9d04f4ecc36df8207b300e46bc6775fc84c087", Block.Testnet3GenesisBlock.hash, "2NCZBGzKadAnLv1ijAqhrKavMuqvxqu18yY"), Triple("00145cb882efd643b7d63ae133e4d5e88e10bd5a20d7", Block.LivenetGenesisBlock.hash, "bc1qtjug9m7kgwmavwhpx0jdt6ywzz745gxhxwyn8u"), Triple("00208c2865c87ffd33fc5d698c7df9cf2d0fb39d93103c637a06dea32c848ebc3e1d", Block.LivenetGenesisBlock.hash, "bc1q3s5xtjrll5elchtf337lnnedp7eemycs833h5pk75vkgfr4u8cws3ytg02"), Triple("76a914536ffa992491508dca0354e52f32a3a7a679a53a88ac", Block.LivenetGenesisBlock.hash, "18cBEMRxXHqzWWCxZNtU91F5sbUNKhL5PX"), @@ -65,14 +68,15 @@ class BitcoinTestsCommon { // p2pkh // valid chain - assertEquals(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160())).right, Script.pay2pkh(pub)) + assertEquals(addressToPublicKeyScript(Block.Testnet4GenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160())).right, Script.pay2pkh(pub)) + assertEquals(addressToPublicKeyScript(Block.Testnet3GenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160())).right, Script.pay2pkh(pub)) assertEquals(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160())).right, (Script.pay2pkh(pub))) assertEquals(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddressTestnet, pub.hash160())).right, Script.pay2pkh(pub)) assertEquals(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160())).right, Script.pay2pkh(pub)) // wrong chain - assertEquals(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160())).left, BitcoinError.ChainHashMismatch) - assertEquals(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160())).left, BitcoinError.ChainHashMismatch) + assertEquals(addressToPublicKeyScript(Block.Testnet4GenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160())).left, BitcoinError.ChainHashMismatch) + assertEquals(addressToPublicKeyScript(Block.Testnet3GenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160())).left, BitcoinError.ChainHashMismatch) assertEquals(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160())).left, BitcoinError.ChainHashMismatch) assertEquals(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Base58Check.encode(Base58.Prefix.PubkeyAddress, pub.hash160())).left, BitcoinError.ChainHashMismatch) @@ -80,14 +84,16 @@ class BitcoinTestsCommon { val script = Script.write(Script.pay2wpkh(pub)) // valid chain - assertEquals(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script))).right, Script.pay2sh(script)) + assertEquals(addressToPublicKeyScript(Block.Testnet4GenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script))).right, Script.pay2sh(script)) + assertEquals(addressToPublicKeyScript(Block.Testnet3GenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script))).right, Script.pay2sh(script)) assertEquals(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script))).right, Script.pay2sh(script)) assertEquals(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script))).right, Script.pay2sh(script)) assertEquals(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script))).right, Script.pay2sh(script)) // wrong chain assertEquals(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddressTestnet, Crypto.hash160(script))).left, BitcoinError.ChainHashMismatch) - assertEquals(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script))).left, BitcoinError.ChainHashMismatch) + assertEquals(addressToPublicKeyScript(Block.Testnet4GenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script))).left, BitcoinError.ChainHashMismatch) + assertEquals(addressToPublicKeyScript(Block.Testnet3GenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script))).left, BitcoinError.ChainHashMismatch) assertEquals(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script))).left, BitcoinError.ChainHashMismatch) assertEquals(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Base58Check.encode(Base58.Prefix.ScriptAddress, Crypto.hash160(script))).left, BitcoinError.ChainHashMismatch) } @@ -98,19 +104,22 @@ class BitcoinTestsCommon { // p2wpkh assertEquals(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Bech32.encodeWitnessAddress("bc", 0, pub.hash160())).right, Script.pay2wpkh(pub)) - assertEquals(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, pub.hash160())).right, Script.pay2wpkh(pub)) + assertEquals(addressToPublicKeyScript(Block.Testnet4GenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, pub.hash160())).right, Script.pay2wpkh(pub)) + assertEquals(addressToPublicKeyScript(Block.Testnet3GenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, pub.hash160())).right, Script.pay2wpkh(pub)) assertEquals(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, pub.hash160())).right, Script.pay2wpkh(pub)) assertEquals(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Bech32.encodeWitnessAddress("bcrt", 0, pub.hash160())).right, Script.pay2wpkh(pub)) // wrong chain - assertEquals(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Bech32.encodeWitnessAddress("bc", 0, pub.hash160())).left, BitcoinError.ChainHashMismatch) + assertEquals(addressToPublicKeyScript(Block.Testnet4GenesisBlock.hash, Bech32.encodeWitnessAddress("bc", 0, pub.hash160())).left, BitcoinError.ChainHashMismatch) + assertEquals(addressToPublicKeyScript(Block.Testnet3GenesisBlock.hash, Bech32.encodeWitnessAddress("bc", 0, pub.hash160())).left, BitcoinError.ChainHashMismatch) assertEquals(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Bech32.encodeWitnessAddress("bc", 0, pub.hash160())).left, BitcoinError.ChainHashMismatch) assertEquals(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, pub.hash160())).left, BitcoinError.ChainHashMismatch) assertEquals(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Bech32.encodeWitnessAddress("bcrt", 0, pub.hash160())).left, BitcoinError.ChainHashMismatch) val script = Script.write(Script.pay2wpkh(pub)) assertEquals(addressToPublicKeyScript(Block.LivenetGenesisBlock.hash, Bech32.encodeWitnessAddress("bc", 0, Crypto.sha256(script))).right, Script.pay2wsh(script)) - assertEquals(addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, Crypto.sha256(script))).right, Script.pay2wsh(script)) + assertEquals(addressToPublicKeyScript(Block.Testnet4GenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, Crypto.sha256(script))).right, Script.pay2wsh(script)) + assertEquals(addressToPublicKeyScript(Block.Testnet3GenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, Crypto.sha256(script))).right, Script.pay2wsh(script)) assertEquals(addressToPublicKeyScript(Block.SignetGenesisBlock.hash, Bech32.encodeWitnessAddress("tb", 0, Crypto.sha256(script))).right, Script.pay2wsh(script)) assertEquals(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, Bech32.encodeWitnessAddress("bcrt", 0, Crypto.sha256(script))).right, Script.pay2wsh(script)) } @@ -119,7 +128,8 @@ class BitcoinTestsCommon { fun `check genesis block hashes`() { assertEquals(Block.RegtestGenesisBlock.blockId, BlockId("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")) assertEquals(Block.SignetGenesisBlock.blockId, BlockId("00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6")) - assertEquals(Block.TestnetGenesisBlock.blockId, BlockId("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")) + assertEquals(Block.Testnet3GenesisBlock.blockId, BlockId("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")) + assertEquals(Block.Testnet4GenesisBlock.blockId, BlockId("00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043")) assertEquals(Block.LivenetGenesisBlock.blockId, BlockId("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")) } @@ -127,7 +137,8 @@ class BitcoinTestsCommon { fun `check Chain objects`() { assertEquals(Block.RegtestGenesisBlock.hash, Chain.Regtest.chainHash) assertEquals(Block.SignetGenesisBlock.hash, Chain.Signet.chainHash) - assertEquals(Block.TestnetGenesisBlock.hash, Chain.Testnet.chainHash) + assertEquals(Block.Testnet3GenesisBlock.hash, Chain.Testnet.chainHash) + assertEquals(Block.Testnet4GenesisBlock.hash, Chain.Testnet4.chainHash) assertEquals(Block.LivenetGenesisBlock.hash, Chain.Mainnet.chainHash) } } \ No newline at end of file diff --git a/src/commonTest/kotlin/fr/acinq/bitcoin/DeriveWalletKeysTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/bitcoin/DeriveWalletKeysTestsCommon.kt index 2e525262..3c1b0a4b 100644 --- a/src/commonTest/kotlin/fr/acinq/bitcoin/DeriveWalletKeysTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/bitcoin/DeriveWalletKeysTestsCommon.kt @@ -71,10 +71,10 @@ class DeriveWalletKeysTestsCommon { return (0L..4L).map { val pub = DeterministicWallet.derivePublicKey(master, listOf(0L, it)) val address = when { - prefix == DeterministicWallet.tpub && derivationScheme == DerivationScheme.BIP44 -> computeBIP44Address(pub.publicKey, Block.TestnetGenesisBlock.hash) - prefix == DeterministicWallet.tpub && derivationScheme == DerivationScheme.BIP49 -> computeBIP49Address(pub.publicKey, Block.TestnetGenesisBlock.hash) - prefix == DeterministicWallet.upub && derivationScheme == DerivationScheme.BIP49 -> computeBIP49Address(pub.publicKey, Block.TestnetGenesisBlock.hash) - prefix == DeterministicWallet.vpub && derivationScheme == DerivationScheme.BIP84 -> computeBIP84Address(pub.publicKey, Block.TestnetGenesisBlock.hash) + prefix == DeterministicWallet.tpub && derivationScheme == DerivationScheme.BIP44 -> computeBIP44Address(pub.publicKey, Block.Testnet3GenesisBlock.hash) + prefix == DeterministicWallet.tpub && derivationScheme == DerivationScheme.BIP49 -> computeBIP49Address(pub.publicKey, Block.Testnet3GenesisBlock.hash) + prefix == DeterministicWallet.upub && derivationScheme == DerivationScheme.BIP49 -> computeBIP49Address(pub.publicKey, Block.Testnet3GenesisBlock.hash) + prefix == DeterministicWallet.vpub && derivationScheme == DerivationScheme.BIP84 -> computeBIP84Address(pub.publicKey, Block.Testnet3GenesisBlock.hash) prefix == DeterministicWallet.xpub && derivationScheme == DerivationScheme.BIP44 -> computeBIP44Address(pub.publicKey, Block.LivenetGenesisBlock.hash) prefix == DeterministicWallet.xpub && derivationScheme == DerivationScheme.BIP49 -> computeBIP49Address(pub.publicKey, Block.LivenetGenesisBlock.hash) prefix == DeterministicWallet.ypub && derivationScheme == DerivationScheme.BIP49 -> computeBIP49Address(pub.publicKey, Block.LivenetGenesisBlock.hash) diff --git a/src/commonTest/kotlin/fr/acinq/bitcoin/TaprootTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/bitcoin/TaprootTestsCommon.kt index cd695af8..b385dd08 100644 --- a/src/commonTest/kotlin/fr/acinq/bitcoin/TaprootTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/bitcoin/TaprootTestsCommon.kt @@ -36,7 +36,7 @@ class TaprootTestsCommon { val internalKey = key.publicKey.xOnly() val script = Script.pay2tr(internalKey, scripts = null) val outputKey = internalKey.outputKey(Crypto.TaprootTweak.NoScriptTweak).first - assertEquals("tb1phlhs7afhqzkgv0n537xs939s687826vn8l24ldkrckvwsnlj3d7qj6u57c", internalKey.p2trAddress(Block.TestnetGenesisBlock.hash)) + assertEquals("tb1phlhs7afhqzkgv0n537xs939s687826vn8l24ldkrckvwsnlj3d7qj6u57c", internalKey.p2trAddress(Block.Testnet3GenesisBlock.hash)) assertEquals(script, Script.pay2tr(outputKey)) // tx sends to tb1phlhs7afhqzkgv0n537xs939s687826vn8l24ldkrckvwsnlj3d7qj6u57c @@ -78,7 +78,7 @@ class TaprootTestsCommon { fun `send to and spend from taproot addresses`() { val privateKey = PrivateKey(ByteVector32("0101010101010101010101010101010101010101010101010101010101010101")) val internalKey = privateKey.publicKey().xOnly() - assertEquals("tb1p33wm0auhr9kkahzd6l0kqj85af4cswn276hsxg6zpz85xe2r0y8snwrkwy", privateKey.publicKey().p2trAddress(Block.TestnetGenesisBlock.hash)) + assertEquals("tb1p33wm0auhr9kkahzd6l0kqj85af4cswn276hsxg6zpz85xe2r0y8snwrkwy", privateKey.publicKey().p2trAddress(Block.Testnet3GenesisBlock.hash)) // this tx sends to tb1p33wm0auhr9kkahzd6l0kqj85af4cswn276hsxg6zpz85xe2r0y8snwrkwy val tx = Transaction.read( @@ -87,7 +87,7 @@ class TaprootTestsCommon { assertEquals(Script.pay2tr(internalKey, scripts = null), Script.parse(tx.txOut[1].publicKeyScript)) // we want to spend - val outputScript = addressToPublicKeyScript(Block.TestnetGenesisBlock.hash, "tb1pn3g330w4n5eut7d4vxq0pp303267qc6vg8d2e0ctjuqre06gs3yqnc5yx0").right!! + val outputScript = addressToPublicKeyScript(Block.Testnet3GenesisBlock.hash, "tb1pn3g330w4n5eut7d4vxq0pp303267qc6vg8d2e0ctjuqre06gs3yqnc5yx0").right!! val tx1 = Transaction( 2, listOf(TxIn(OutPoint(tx, 1), TxIn.SEQUENCE_FINAL)),