From 1f7a982519575a11181b771735714bb111de80a0 Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Thu, 27 Feb 2025 16:47:13 -0600 Subject: [PATCH 1/3] core: Add support for testnet4 --- .../bitcoins/commons/config/AppConfig.scala | 1 + .../commons/jsonmodels/ExplorerEnv.scala | 7 +- .../bitcoins/commons/util/DatadirUtil.scala | 2 + .../server/BitcoindRpcBackendUtil.scala | 6 +- .../bitcoins/rpc/client/common/Client.scala | 1 + .../rpc/config/BitcoindAuthCredentials.scala | 1 + .../bitcoins/rpc/config/BitcoindConfig.scala | 10 +- .../scala/org/bitcoins/chain/pow/Pow.scala | 2 +- .../rpc/config/CLightningConfig.scala | 1 + .../rpc/config/CLightningInstanceLocal.scala | 9 -- .../core/crypto/WIFEncodingTest.scala | 4 +- .../core/config/NetworkParameters.scala | 18 +++ .../org/bitcoins/core/hd/HDCoinType.scala | 4 +- .../core/protocol/BtcHumanReadablePart.scala | 8 +- .../protocol/blockchain/ChainParams.scala | 103 +++++++++++++++++- .../bitcoins/core/protocol/ln/LnParams.scala | 8 +- .../oracle/config/DLCOracleAppConfig.scala | 1 + .../org/bitcoins/esplora/EsploraSite.scala | 7 +- .../feeprovider/MempoolSpaceProvider.scala | 2 + .../bitcoins/lnd/rpc/config/LndInstance.scala | 1 + .../scala/org/bitcoins/node/PeerFinder.scala | 4 +- .../wallet/internal/AccountHandling.scala | 4 +- 22 files changed, 161 insertions(+), 43 deletions(-) diff --git a/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfig.scala b/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfig.scala index 0aa6e97dbc..939b4c12ca 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfig.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfig.scala @@ -139,6 +139,7 @@ abstract class AppConfig extends StartStopAsync[Unit] with BitcoinSLogger { val lastDirname = network match { case MainNet => "mainnet" case TestNet3 => "testnet3" + case TestNet4 => "testnet4" case RegTest => "regtest" case SigNet => "signet" } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/ExplorerEnv.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/ExplorerEnv.scala index 7e61775b36..d7597bc04a 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/ExplorerEnv.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/ExplorerEnv.scala @@ -5,7 +5,8 @@ import org.bitcoins.core.config.{ MainNet, RegTest, SigNet, - TestNet3 + TestNet3, + TestNet4 } import org.bitcoins.crypto.StringFactory @@ -57,8 +58,8 @@ object ExplorerEnv extends StringFactory[ExplorerEnv] { def fromBitcoinNetwork(network: BitcoinNetwork): ExplorerEnv = { network match { - case MainNet => Production - case TestNet3 | RegTest | SigNet => Test + case MainNet => Production + case TestNet3 | TestNet4 | RegTest | SigNet => Test } } } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirUtil.scala b/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirUtil.scala index f47d26e7e0..33add9fe4a 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirUtil.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirUtil.scala @@ -15,6 +15,7 @@ object DatadirUtil { case "testnet3" => TestNet3 case "testnet" => TestNet3 case "test" => TestNet3 + case "testnet4" => TestNet4 case "regtest" => RegTest case "signet" => SigNet case "sig" => SigNet @@ -25,6 +26,7 @@ object DatadirUtil { network match { case MainNet => "mainnet" case TestNet3 => "testnet3" + case TestNet4 => "testnet4" case RegTest => "regtest" case SigNet => "signet" } diff --git a/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala b/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala index 59b3cb1983..a81e97c4cd 100644 --- a/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala +++ b/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala @@ -16,7 +16,7 @@ import org.bitcoins.commons.jsonmodels.bitcoind.GetBlockHeaderResult import org.bitcoins.commons.util.BitcoinSLogger import org.bitcoins.core.api.node.NodeApi import org.bitcoins.core.api.wallet.{NeutrinoHDWalletApi, WalletApi} -import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3} +import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3, TestNet4} import org.bitcoins.core.gcs.FilterType import org.bitcoins.core.protocol.blockchain.Block import org.bitcoins.core.protocol.transaction.Transaction @@ -430,8 +430,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { import system.dispatcher val interval = intervalOpt.getOrElse { bitcoind.bitcoindRpcAppConfig.network match { - case MainNet | TestNet3 | SigNet => 10.seconds - case RegTest => 1.second + case MainNet | TestNet3 | TestNet4 | SigNet => 10.seconds + case RegTest => 1.second } } val processingBitcoindBlocks = new AtomicBoolean(false) diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala index f574643d51..15ec17c914 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala @@ -70,6 +70,7 @@ trait Client val prefix = instance.network match { case MainNet => "" case TestNet3 => "testnet" + case TestNet4 => "testnet4" case RegTest => "regtest" case SigNet => "signet" } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindAuthCredentials.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindAuthCredentials.scala index 8b77e5186f..d54a9a83b7 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindAuthCredentials.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindAuthCredentials.scala @@ -61,6 +61,7 @@ object BitcoindAuthCredentials extends BitcoinSLogger { case TestNet3 => "testnet3" case RegTest => "regtest" case SigNet => "signet" + case TestNet4 => "testnet4" } Paths.get(datadir.toString, middleSegment, ".cookie") diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindConfig.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindConfig.scala index 8db4cace31..acfa51a48d 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindConfig.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindConfig.scala @@ -70,15 +70,17 @@ case class BitcoindConfig( case MainNet => "main" case RegTest => "regtest" case TestNet3 => "test" + case TestNet4 => "testnet4" case SigNet => "signet" } /** The networks we're _not_ on */ private lazy val otherNetworks = network match { - case MainNet => List("test", "regtest", "signet") - case RegTest => List("main", "test", "signet") - case TestNet3 => List("main", "regtest", "signet") - case SigNet => List("main", "test", "regtest") + case MainNet => List("test", "regtest", "signet", "testnet4") + case RegTest => List("main", "test", "signet", "testnet4") + case TestNet3 => List("main", "regtest", "signet", "testnet4") + case TestNet4 => List("main", "test", "regtest", "signet") + case SigNet => List("main", "test", "regtest", "testnet4") } private lazy val ourNetworkString: String = networkString(network) diff --git a/chain/src/main/scala/org/bitcoins/chain/pow/Pow.scala b/chain/src/main/scala/org/bitcoins/chain/pow/Pow.scala index ab158c9d3e..5e03826d19 100644 --- a/chain/src/main/scala/org/bitcoins/chain/pow/Pow.scala +++ b/chain/src/main/scala/org/bitcoins/chain/pow/Pow.scala @@ -49,7 +49,7 @@ sealed abstract class Pow { case RegTestNetChainParams => RegTestNetChainParams.compressedPowLimit case TestNetChainParams | MainNetChainParams | - SigNetChainParams(_) => + SigNetChainParams(_) | TestNet4ChainParams => // if we can't find a non min difficulty block, let's just fail throw new RuntimeException( s"Could not find non mindifficulty block in chain of size=${blockchain.length}! hash=${tip.hashBE.hex} height=${currentHeight}" diff --git a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningConfig.scala b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningConfig.scala index d53a685006..96de67766f 100644 --- a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningConfig.scala +++ b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningConfig.scala @@ -257,6 +257,7 @@ object CLightningConfig network match { case MainNet => "bitcoin" case TestNet3 => "testnet" + case TestNet4 => "testnet4" case RegTest => "regtest" case SigNet => "signet" } diff --git a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningInstanceLocal.scala b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningInstanceLocal.scala index 9877ec19dc..535259e58a 100644 --- a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningInstanceLocal.scala +++ b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningInstanceLocal.scala @@ -28,15 +28,6 @@ object CLightningInstanceLocal override val DEFAULT_CONF_FILE: Path = DEFAULT_DATADIR.resolve("config") - private[clightning] def getNetworkDirName(network: BitcoinNetwork): String = { - network match { - case MainNet => "" - case TestNet3 => "testnet" - case SigNet => "signet" - case RegTest => "regtest" - } - } - override def fromConfigFile( file: File = DEFAULT_CONF_FILE.toFile )(implicit system: ActorSystem): CLightningInstanceLocal = { diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/WIFEncodingTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/WIFEncodingTest.scala index a667ca998d..b0d181cc47 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/WIFEncodingTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/WIFEncodingTest.scala @@ -1,6 +1,6 @@ package org.bitcoins.core.crypto -import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3} +import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3, TestNet4} import org.bitcoins.crypto.{ECPrivateKey, ECPrivateKeyBytes} import org.bitcoins.testkitcore.gen.{ ChainParamsGenerator, @@ -72,7 +72,7 @@ class WIFEncodingTest extends BitcoinSUnitTest { network match { case MainNet => assert(ECPrivateKeyUtil.parseNetworkFromWIF(wif).get == MainNet) - case TestNet3 | RegTest | SigNet => + case TestNet3 | TestNet4 | RegTest | SigNet => assert(ECPrivateKeyUtil.parseNetworkFromWIF(wif).get == TestNet3) } assert( diff --git a/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala b/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala index 1de305d09e..65b0d51a1f 100644 --- a/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala +++ b/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala @@ -173,6 +173,24 @@ sealed abstract class SigNet extends BitcoinNetwork { } case object SigNet extends SigNet + +sealed abstract class TestNet4 extends BitcoinNetwork { + override def chainParams: BitcoinChainParams = TestNet4ChainParams + override def port: Int = 48333 + override def rpcPort: Int = 48334 + override def magicBytes: ByteVector = ByteVector( + 0x1c, + 0x16, + 0x3f, + 0x28 + ) + override def dnsSeeds: Seq[String] = Vector( + "seed.testnet4.bitcoin.sprovoost.nl", + "seed.testnet4.wiz.biz" + ) +} + +case object TestNet4 extends TestNet4 // $COVERAGE-ON$ object Networks extends StringFactory[NetworkParameters] { diff --git a/core/src/main/scala/org/bitcoins/core/hd/HDCoinType.scala b/core/src/main/scala/org/bitcoins/core/hd/HDCoinType.scala index 0fd1143efb..da6333de15 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/HDCoinType.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/HDCoinType.scala @@ -39,8 +39,8 @@ object HDCoinType { def fromNetwork(np: NetworkParameters): HDCoinType = { np match { - case MainNet => Bitcoin - case TestNet3 | RegTest | SigNet => Testnet + case MainNet => Bitcoin + case TestNet3 | TestNet4 | RegTest | SigNet => Testnet } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/BtcHumanReadablePart.scala b/core/src/main/scala/org/bitcoins/core/protocol/BtcHumanReadablePart.scala index 3ae9b0eea1..649f944c82 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/BtcHumanReadablePart.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/BtcHumanReadablePart.scala @@ -49,10 +49,10 @@ object BtcHumanReadablePart extends StringFactory[BtcHumanReadablePart] { def apply(network: NetworkParameters): BtcHumanReadablePart = network match { - case _: MainNet => bc - case _: TestNet3 => tb - case _: RegTest => bcrt - case _: SigNet => tb + case _: MainNet => bc + case _: TestNet3 | _: TestNet4 => tb + case _: RegTest => bcrt + case _: SigNet => tb } def apply(hrp: Bech32HumanReadablePart): BtcHumanReadablePart = diff --git a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala index 9c04d1f6b7..d947b1342b 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala @@ -2,22 +2,26 @@ package org.bitcoins.core.protocol.blockchain import java.math.BigInteger import java.nio.charset.StandardCharsets - -import org.bitcoins.core.config._ +import org.bitcoins.core.config.* import org.bitcoins.core.consensus.Merkle import org.bitcoins.core.currency.{Bitcoins, CurrencyUnit, Satoshis} import org.bitcoins.core.number.{Int32, UInt32} import org.bitcoins.core.protocol.script.{ EmptyScriptPubKey, + P2PKScriptPubKey, ScriptPubKey, ScriptSignature } -import org.bitcoins.core.protocol.transaction._ +import org.bitcoins.core.protocol.transaction.* import org.bitcoins.core.script.constant.{BytesToPushOntoStack, ScriptConstant} import org.bitcoins.core.script.crypto.OP_CHECKSIG import org.bitcoins.core.util.{BitcoinScriptUtil, NumberUtil} -import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE} -import scodec.bits.{ByteVector, _} +import org.bitcoins.crypto.{ + DoubleSha256Digest, + DoubleSha256DigestBE, + ECPublicKey +} +import scodec.bits.{ByteVector, *} import scala.concurrent.duration.{Duration, DurationInt} @@ -345,7 +349,7 @@ object TestNetChainParams extends BitcoinChainParams { Int32.one, Satoshis(5000000000L)) - override lazy val base58Prefixes: Map[Base58Type, ByteVector] = + override lazy val base58Prefixes: Map[Base58Type, ByteVector] = { Map( Base58Type.PubKeyAddress -> hex"6f", Base58Type.ScriptAddress -> hex"c4", @@ -353,6 +357,7 @@ object TestNetChainParams extends BitcoinChainParams { Base58Type.ExtPublicKey -> hex"043587cf", Base58Type.ExtSecretKey -> hex"04358394" ) + } /** Testnet pow limit * [[https://github.com/bitcoin/bitcoin/blob/a083f75ba79d465f15fddba7b00ca02e31bb3d40/src/chainparams.cpp#L189 testnet pow limit]] @@ -505,6 +510,92 @@ case class SigNetChainParams( override def signetBlocks: Boolean = true } +object TestNet4ChainParams extends BitcoinChainParams { + + /** The best chain should have this amount of work */ + override val minimumChainWork: BigInteger = { + val bytes = ByteVector.fromValidHex( + "00000000000000000000000000000000000000000000005faa15d02e6202f3ba") + new BigInteger(1, bytes.toArray) + } + + /** @inheritdoc + */ + override def network: BitcoinNetwork = TestNet4 + + /** Return the BIP70 network string ( + * [[org.bitcoins.core.protocol.blockchain.MainNetChainParams MainNetChainParams]], + * [[org.bitcoins.core.protocol.blockchain.MainNetChainParams TestNetChainParams]] + * or + * [[org.bitcoins.core.protocol.blockchain.MainNetChainParams RegTestNetChainParams]].) + * + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki BIP70]] + */ + override def networkId: String = "testnet4" + + /** The Genesis [[org.bitcoins.core.protocol.blockchain.Block Block]] in the + * blockchain. + */ + override val genesisBlock: Block = { + createGenesisBlock( + timestamp = + "03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e", + scriptPubKey = P2PKScriptPubKey(ECPublicKey.fromHex( + "000000000000000000000000000000000000000000000000000000000000000000")), + time = UInt32(1714777860), + nonce = UInt32(393743547), + nBits = UInt32.fromHex("1d00ffff"), + version = Int32.one, + amount = Bitcoins(50) + ) + } + + /** The mapping from a + * [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]]to a + * String. Base58 prefixes for various keys/hashes on the network. + * + * @see + * Bitcoin wiki + * [[https://en.bitcoin.it/wiki/List_of_address_prefixes article]] on + * address prefixes + */ + override def base58Prefixes: Map[Base58Type, ByteVector] = { + TestNetChainParams.base58Prefixes + } + + /** The minimum amount of proof of work required for a block + * [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/consensus/params.h#L70 bitcoin core pow limit]] + * + * @return + */ + override def powLimit: BigInteger = MainNetChainParams.powLimit + + /** Whether we should allow minimum difficulty blocks or not As an example you + * can trivially mine blocks on [[RegTestNetChainParams]] and + * [[TestNetChainParams]] but not the [[MainNetChainParams]] + * + * @return + */ + override def allowMinDifficultyBlocks: Boolean = true + + /** Whether this chain supports proof of work retargeting or not + * + * @see + * [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/consensus/params.h#L72 link]] + * @return + */ + override def noRetargeting: Boolean = false + + /** Uses signet blocks that require checking the signet challenge */ + override def signetBlocks: Boolean = false + + /** Blocks must satisfy the given script to be considered valid (only for + * signet networks) + */ + override def signetChallenge: ScriptPubKey = EmptyScriptPubKey +} + sealed abstract class Base58Type object Base58Type { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnParams.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnParams.scala index 621c7460ea..32910a7645 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnParams.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnParams.scala @@ -63,10 +63,10 @@ object LnParams { def fromNetworkParameters(np: NetworkParameters): LnParams = np match { - case MainNet => LnBitcoinMainNet - case TestNet3 => LnBitcoinTestNet - case RegTest => LnBitcoinRegTest - case SigNet => LnBitcoinSigNet + case MainNet => LnBitcoinMainNet + case TestNet3 | TestNet4 => LnBitcoinTestNet + case RegTest => LnBitcoinRegTest + case SigNet => LnBitcoinSigNet } val allNetworks: Vector[LnParams] = diff --git a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfig.scala b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfig.scala index 8a69c98080..9a705577e1 100644 --- a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfig.scala +++ b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfig.scala @@ -77,6 +77,7 @@ case class DLCOracleAppConfig( val lastDirname = network match { case MainNet => "mainnet" case TestNet3 => "testnet3" + case TestNet4 => "testnet4" case RegTest => "regtest" case SigNet => "signet" } diff --git a/esplora/src/main/scala/org/bitcoins/esplora/EsploraSite.scala b/esplora/src/main/scala/org/bitcoins/esplora/EsploraSite.scala index 5b48e65200..36facc9888 100644 --- a/esplora/src/main/scala/org/bitcoins/esplora/EsploraSite.scala +++ b/esplora/src/main/scala/org/bitcoins/esplora/EsploraSite.scala @@ -12,7 +12,7 @@ case class BlockstreamEsploraSite(network: BitcoinNetwork) extends EsploraSite { override val url: String = network match { case MainNet => "https://blockstream.info/api" case TestNet3 => "https://blockstream.info/testnet/api" - case net @ (RegTest | SigNet) => + case net @ (RegTest | SigNet | TestNet4) => sys.error(s"Blockstream.info does not support $net") } @@ -27,7 +27,7 @@ case class BlockstreamTorEsploraSite(network: BitcoinNetwork) "http://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion/api" case TestNet3 => "http://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion/testnet/api" - case net @ (RegTest | SigNet) => + case net @ (RegTest | TestNet4 | SigNet) => sys.error(s"Blockstream.info does not support $net") } @@ -40,6 +40,7 @@ case class MempoolSpaceEsploraSite(network: BitcoinNetwork) override val url: String = network match { case MainNet => "https://mempool.space/api" case TestNet3 => "https://mempool.space/testnet/api" + case TestNet4 => "https://mempool.space/testnet4/api/" case SigNet => "https://mempool.space/signet/api" case RegTest => sys.error(s"Mempool.space cannot be used for RegTest") @@ -56,6 +57,8 @@ case class MempoolSpaceTorEsploraSite(network: BitcoinNetwork) "http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/api" case TestNet3 => "http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/testnet/api" + case TestNet4 => + "http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/testnet4/api" case SigNet => "http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/signet/api" case RegTest => diff --git a/fee-provider/src/main/scala/org/bitcoins/feeprovider/MempoolSpaceProvider.scala b/fee-provider/src/main/scala/org/bitcoins/feeprovider/MempoolSpaceProvider.scala index f1b21d57de..d06a66b8b6 100644 --- a/fee-provider/src/main/scala/org/bitcoins/feeprovider/MempoolSpaceProvider.scala +++ b/fee-provider/src/main/scala/org/bitcoins/feeprovider/MempoolSpaceProvider.scala @@ -27,6 +27,8 @@ case class MempoolSpaceProvider( Uri("https://mempool.space/api/v1/fees/recommended") case TestNet3 => Uri("https://mempool.space/testnet/api/v1/fees/recommended") + case TestNet4 => + Uri("https://mempool.space/testnet4/api/v1/fees/recommended") case SigNet => Uri("https://mempool.space/signet/api/v1/fees/recommended") case RegTest => diff --git a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndInstance.scala b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndInstance.scala index eef4d4731a..4530a8f111 100644 --- a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndInstance.scala +++ b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndInstance.scala @@ -73,6 +73,7 @@ object LndInstanceLocal network match { case _: MainNet => "mainnet" case _: TestNet3 => "testnet" + case _: TestNet4 => "testnet4" case _: RegTest => "regtest" case _: SigNet => "signet" } diff --git a/node/src/main/scala/org/bitcoins/node/PeerFinder.scala b/node/src/main/scala/org/bitcoins/node/PeerFinder.scala index 346873c177..0b5a1b21e7 100644 --- a/node/src/main/scala/org/bitcoins/node/PeerFinder.scala +++ b/node/src/main/scala/org/bitcoins/node/PeerFinder.scala @@ -5,7 +5,7 @@ import org.apache.pekko.stream.scaladsl.SourceQueue import org.bitcoins.asyncutil.AsyncUtil import org.bitcoins.chain.config.ChainAppConfig import org.bitcoins.core.api.node.{Peer, PeerManagerApi} -import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3} +import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3, TestNet4} import org.bitcoins.core.p2p.{ServiceIdentifier, VersionMessage} import org.bitcoins.core.util.StartStopAsync import org.bitcoins.node.config.NodeAppConfig @@ -82,7 +82,7 @@ case class PeerFinder( .filter(nodeAppConfig.torConf.enabled || !_.contains(".onion")) val peers = BitcoinSNodeUtil.stringsToPeers(addresses) Random.shuffle(peers) - case TestNet3 | RegTest | SigNet => + case TestNet3 | TestNet4 | RegTest | SigNet => Vector.empty } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala index 98178bb9b1..4a1d89f13f 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala @@ -15,6 +15,7 @@ import org.bitcoins.core.protocol.blockchain.{ MainNetChainParams, RegTestNetChainParams, SigNetChainParams, + TestNet4ChainParams, TestNetChainParams } import org.bitcoins.core.protocol.script.ScriptPubKey @@ -522,7 +523,8 @@ case class AccountHandling( protected[wallet] lazy val DEFAULT_HD_COIN_TYPE: HDCoinType = { chainParams match { case MainNetChainParams => HDCoinType.Bitcoin - case RegTestNetChainParams | TestNetChainParams | SigNetChainParams(_) => + case RegTestNetChainParams | TestNetChainParams | TestNet4ChainParams | + SigNetChainParams(_) => HDCoinType.Testnet } From 3637580052f41d80b4dfe6e17d6fe13f00a95716 Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Fri, 28 Feb 2025 14:35:44 -0600 Subject: [PATCH 2/3] core: Fix first set of testnet4 bugs --- app/server/src/main/resources/logback.xml | 2 +- .../core/config/NetworkParameters.scala | 1 + .../protocol/blockchain/ChainParams.scala | 17 ++++++----- .../scala/org/bitcoins/core/util/HDUtil.scala | 30 +++++++++++-------- .../scala/org/bitcoins/node/PeerFinder.scala | 4 +-- 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/app/server/src/main/resources/logback.xml b/app/server/src/main/resources/logback.xml index 49d2eafb99..3a19170aee 100644 --- a/app/server/src/main/resources/logback.xml +++ b/app/server/src/main/resources/logback.xml @@ -35,7 +35,7 @@ - + diff --git a/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala b/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala index 65b0d51a1f..dc138ed8d1 100644 --- a/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala +++ b/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala @@ -232,6 +232,7 @@ object BitcoinNetworks extends StringFactory[BitcoinNetwork] { case "testnet3" => TestNet3 case "testnet" => TestNet3 case "test" => TestNet3 + case "testnet4" => TestNet4 case "regtest" => RegTest case "signet" => SigNet case "sig" => SigNet diff --git a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala index d947b1342b..c3cc2e15b6 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala @@ -8,7 +8,6 @@ import org.bitcoins.core.currency.{Bitcoins, CurrencyUnit, Satoshis} import org.bitcoins.core.number.{Int32, UInt32} import org.bitcoins.core.protocol.script.{ EmptyScriptPubKey, - P2PKScriptPubKey, ScriptPubKey, ScriptSignature } @@ -16,11 +15,7 @@ import org.bitcoins.core.protocol.transaction.* import org.bitcoins.core.script.constant.{BytesToPushOntoStack, ScriptConstant} import org.bitcoins.core.script.crypto.OP_CHECKSIG import org.bitcoins.core.util.{BitcoinScriptUtil, NumberUtil} -import org.bitcoins.crypto.{ - DoubleSha256Digest, - DoubleSha256DigestBE, - ECPublicKey -} +import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE} import scodec.bits.{ByteVector, *} import scala.concurrent.duration.{Duration, DurationInt} @@ -538,11 +533,17 @@ object TestNet4ChainParams extends BitcoinChainParams { * blockchain. */ override val genesisBlock: Block = { + val asm = Seq( + BytesToPushOntoStack(33), + ScriptConstant( + "000000000000000000000000000000000000000000000000000000000000000000"), + OP_CHECKSIG + ) + val spk = ScriptPubKey.fromAsm(asm) createGenesisBlock( timestamp = "03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e", - scriptPubKey = P2PKScriptPubKey(ECPublicKey.fromHex( - "000000000000000000000000000000000000000000000000000000000000000000")), + scriptPubKey = spk, time = UInt32(1714777860), nonce = UInt32(393743547), nBits = UInt32.fromHex("1d00ffff"), diff --git a/core/src/main/scala/org/bitcoins/core/util/HDUtil.scala b/core/src/main/scala/org/bitcoins/core/util/HDUtil.scala index 7647f5c186..dc7e5d6d0b 100644 --- a/core/src/main/scala/org/bitcoins/core/util/HDUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/util/HDUtil.scala @@ -15,18 +15,22 @@ object HDUtil { (hdPurpose, network) match { case (SegWit, MainNet) | (Taproot, MainNet) => SegWitMainNetPriv - case (SegWit, TestNet3 | RegTest | SigNet) => SegWitTestNet3Priv - case (Taproot, TestNet3 | RegTest | SigNet) => SegWitTestNet3Priv - case (NestedSegWit, MainNet) => NestedSegWitMainNetPriv - case (NestedSegWit, TestNet3 | RegTest | SigNet) => + case (SegWit, TestNet3 | RegTest | SigNet | TestNet4) => + SegWitTestNet3Priv + case (Taproot, TestNet3 | RegTest | SigNet | TestNet4) => + SegWitTestNet3Priv + case (NestedSegWit, MainNet) => NestedSegWitMainNetPriv + case (NestedSegWit, TestNet3 | RegTest | SigNet | TestNet4) => NestedSegWitTestNet3Priv case (Multisig, MainNet) => LegacyMainNetPriv - case (Multisig, TestNet3 | RegTest | SigNet) => + case (Multisig, TestNet3 | RegTest | SigNet | TestNet4) => LegacyTestNet3Priv - case (Legacy, MainNet) => LegacyMainNetPriv - case (Legacy, TestNet3 | RegTest | SigNet) => LegacyTestNet3Priv - case (HDPurpose(585), MainNet) => SegWitMainNetPriv - case (HDPurpose(585), TestNet3 | RegTest | SigNet) => SegWitTestNet3Priv + case (Legacy, MainNet) => LegacyMainNetPriv + case (Legacy, TestNet3 | RegTest | SigNet | TestNet4) => + LegacyTestNet3Priv + case (HDPurpose(585), MainNet) => SegWitMainNetPriv + case (HDPurpose(585), TestNet3 | RegTest | SigNet | TestNet4) => + SegWitTestNet3Priv case (unknown: HDPurpose, _) => throw new IllegalArgumentException(s"Got unknown HD purpose $unknown") } @@ -40,16 +44,16 @@ object HDUtil { (hdPurpose, network) match { case (SegWit, MainNet | SigNet) => ExtKeyPubVersion.SegWitMainNetPub - case (SegWit, TestNet3 | RegTest | SigNet) => + case (SegWit, TestNet3 | RegTest | SigNet | TestNet4) => ExtKeyPubVersion.SegWitTestNet3Pub case (NestedSegWit, MainNet) => ExtKeyPubVersion.NestedSegWitMainNetPub - case (NestedSegWit, TestNet3 | RegTest | SigNet) => + case (NestedSegWit, TestNet3 | RegTest | SigNet | TestNet4) => ExtKeyPubVersion.NestedSegWitTestNet3Pub case (Multisig, MainNet) => ExtKeyPubVersion.LegacyMainNetPub - case (Multisig, TestNet3 | RegTest | SigNet) => + case (Multisig, TestNet3 | RegTest | SigNet | TestNet4) => ExtKeyPubVersion.LegacyTestNet3Pub case (Legacy, MainNet) => ExtKeyPubVersion.LegacyMainNetPub - case (Legacy, TestNet3 | RegTest | SigNet) => + case (Legacy, TestNet3 | RegTest | SigNet | TestNet4) => ExtKeyPubVersion.LegacyTestNet3Pub case (unknown: HDPurpose, _) => throw new IllegalArgumentException(s"Got unknown HD purpose $unknown") diff --git a/node/src/main/scala/org/bitcoins/node/PeerFinder.scala b/node/src/main/scala/org/bitcoins/node/PeerFinder.scala index 0b5a1b21e7..346873c177 100644 --- a/node/src/main/scala/org/bitcoins/node/PeerFinder.scala +++ b/node/src/main/scala/org/bitcoins/node/PeerFinder.scala @@ -5,7 +5,7 @@ import org.apache.pekko.stream.scaladsl.SourceQueue import org.bitcoins.asyncutil.AsyncUtil import org.bitcoins.chain.config.ChainAppConfig import org.bitcoins.core.api.node.{Peer, PeerManagerApi} -import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3, TestNet4} +import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3} import org.bitcoins.core.p2p.{ServiceIdentifier, VersionMessage} import org.bitcoins.core.util.StartStopAsync import org.bitcoins.node.config.NodeAppConfig @@ -82,7 +82,7 @@ case class PeerFinder( .filter(nodeAppConfig.torConf.enabled || !_.contains(".onion")) val peers = BitcoinSNodeUtil.stringsToPeers(addresses) Random.shuffle(peers) - case TestNet3 | TestNet4 | RegTest | SigNet => + case TestNet3 | RegTest | SigNet => Vector.empty } From 28f32291343ca42f58de99bf222e50ea0e5d9cf7 Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Fri, 28 Feb 2025 14:44:47 -0600 Subject: [PATCH 3/3] fix pattern match --- node/src/main/scala/org/bitcoins/node/PeerFinder.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/src/main/scala/org/bitcoins/node/PeerFinder.scala b/node/src/main/scala/org/bitcoins/node/PeerFinder.scala index 346873c177..856daeb398 100644 --- a/node/src/main/scala/org/bitcoins/node/PeerFinder.scala +++ b/node/src/main/scala/org/bitcoins/node/PeerFinder.scala @@ -5,7 +5,7 @@ import org.apache.pekko.stream.scaladsl.SourceQueue import org.bitcoins.asyncutil.AsyncUtil import org.bitcoins.chain.config.ChainAppConfig import org.bitcoins.core.api.node.{Peer, PeerManagerApi} -import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3} +import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3, TestNet4} import org.bitcoins.core.p2p.{ServiceIdentifier, VersionMessage} import org.bitcoins.core.util.StartStopAsync import org.bitcoins.node.config.NodeAppConfig @@ -82,7 +82,7 @@ case class PeerFinder( .filter(nodeAppConfig.torConf.enabled || !_.contains(".onion")) val peers = BitcoinSNodeUtil.stringsToPeers(addresses) Random.shuffle(peers) - case TestNet3 | RegTest | SigNet => + case TestNet3 | RegTest | SigNet | TestNet4 => Vector.empty }