mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-23 22:56:52 +01:00
Implement bitcoind
RPC 27.0 (#5552)
* Add bitcoind 27.0 * Fix linux, windows hashes * Add BitcoindV27RpcClient * Switch BitcoindVersion.newest = V27 * Try downgrading lndRpcTest to use V26 in tests * Make pattern matching against 'bitcoind --version' more resilient for new versions of bitcoind * Add awaitDisconnect() to BitcoindRpcTestUtil.disconnectNodes(), fix flaky v2 connection in unit test
This commit is contained in:
parent
7ef6086673
commit
6543b261c4
11 changed files with 164 additions and 74 deletions
|
@ -148,7 +148,11 @@ class DisconnectedPeersRpcTest
|
|||
_ <- BitcoindRpcTestUtil.awaitConnection(from = freshClient,
|
||||
to = otherFreshClient,
|
||||
interval = 1.second)
|
||||
|
||||
// takes awhile to figure out what the transport type is...
|
||||
// wait until we are no longer 'detecting' the transport_protocol_type
|
||||
_ <- AsyncUtil.retryUntilSatisfiedF(() =>
|
||||
freshClient.getPeerInfo.map(
|
||||
_.exists(_.transport_protocol_type != "detecting")))
|
||||
info <- freshClient.getPeerInfo
|
||||
} yield {
|
||||
assert(info.exists(_.transport_protocol_type == "v2"))
|
||||
|
|
|
@ -23,7 +23,7 @@ TaskKeys.downloadBitcoind := {
|
|||
}
|
||||
|
||||
val versions =
|
||||
List("26.1", "25.2")
|
||||
List("27.0", "26.1", "25.2")
|
||||
|
||||
logger.debug(
|
||||
s"(Maybe) downloading Bitcoin Core binaries for versions: ${versions.mkString(",")}")
|
||||
|
@ -95,7 +95,8 @@ TaskKeys.downloadBitcoind := {
|
|||
if (Properties.isLinux)
|
||||
Map(
|
||||
"25.2" -> "8d8c387e597e0edfc256f0bbace1dac3ad1ebf4a3c06da3e2975fda333817dea",
|
||||
"26.1" -> "a5b7d206384a8100058d3f2e2f02123a8e49e83f523499e70e86e121a4897d5b"
|
||||
"26.1" -> "a5b7d206384a8100058d3f2e2f02123a8e49e83f523499e70e86e121a4897d5b",
|
||||
"27.0" -> "2a6974c5486f528793c79d42694b5987401e4a43c97f62b1383abf35bcee44a8"
|
||||
)
|
||||
else if (Properties.isMac)
|
||||
Map(
|
||||
|
@ -105,13 +106,18 @@ TaskKeys.downloadBitcoind := {
|
|||
"e06ba379f6039ca99bc32d3e7974d420a31363498936f88aac7bab6f239de0f5"),
|
||||
"26.1" -> (if (System.getProperty("os.arch") == "aarch64")
|
||||
"8a8e415763b7ffd5988153cf03967d812eca629016dd3b0ddf6da3ab6f4a3621"
|
||||
else
|
||||
""),
|
||||
"27.0" -> (if (System.getProperty("os.arch") == "aarch64")
|
||||
"1d9d9b837297a73fc7a3b1cfed376644e3fa25c4e1672fbc143d5946cb52431d"
|
||||
else
|
||||
"")
|
||||
)
|
||||
else if (Properties.isWin)
|
||||
Map(
|
||||
"25.2" -> "c2ac84f55ee879caefd4414868d318a741c52a7286da190bf7233d86a2ffca69",
|
||||
"26.1" -> "7bd0849e47472aeff99a0ea2c0cefd98f5be829e5a2d3b0168b5a54456cc638a"
|
||||
"26.1" -> "7bd0849e47472aeff99a0ea2c0cefd98f5be829e5a2d3b0168b5a54456cc638a",
|
||||
"27.0" -> "ca75babeaa3fb75f5a166f544adaa93fd7c1f06cf20d4e2c8c2a8b010f4c7603"
|
||||
)
|
||||
else sys.error(s"Unsupported OS: ${Properties.osName}")
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.bitcoins.rpc.client.v18.V18AssortedRpc
|
|||
import org.bitcoins.rpc.client.v20.V20MultisigRpc
|
||||
import org.bitcoins.rpc.client.v25.BitcoindV25RpcClient
|
||||
import org.bitcoins.rpc.client.v26.BitcoindV26RpcClient
|
||||
import org.bitcoins.rpc.client.v27.BitcoindV27RpcClient
|
||||
import org.bitcoins.rpc.config._
|
||||
|
||||
import java.io.File
|
||||
|
@ -345,6 +346,7 @@ object BitcoindRpcClient {
|
|||
val bitcoind = version match {
|
||||
case BitcoindVersion.V25 => BitcoindV25RpcClient.withActorSystem(instance)
|
||||
case BitcoindVersion.V26 => BitcoindV26RpcClient.withActorSystem(instance)
|
||||
case BitcoindVersion.V27 => BitcoindV27RpcClient.withActorSystem(instance)
|
||||
case BitcoindVersion.Unknown =>
|
||||
sys.error(
|
||||
s"Cannot create a Bitcoin Core RPC client: unsupported version"
|
||||
|
@ -368,10 +370,10 @@ object BitcoindVersion
|
|||
with BitcoinSLogger {
|
||||
|
||||
/** The newest version of `bitcoind` we support */
|
||||
val newest: BitcoindVersion = V26
|
||||
val newest: BitcoindVersion = V27
|
||||
|
||||
val standard: Vector[BitcoindVersion] =
|
||||
Vector(V25)
|
||||
Vector(V27, V26, V25)
|
||||
|
||||
val known: Vector[BitcoindVersion] = standard
|
||||
|
||||
|
@ -383,6 +385,10 @@ object BitcoindVersion
|
|||
override def toString: String = "v26"
|
||||
}
|
||||
|
||||
case object V27 extends BitcoindVersion {
|
||||
override def toString: String = "v27"
|
||||
}
|
||||
|
||||
case object Unknown extends BitcoindVersion {
|
||||
override def toString: String = "Unknown"
|
||||
}
|
||||
|
@ -402,6 +408,8 @@ object BitcoindVersion
|
|||
// need to translate the int 210100 (as an example) to a BitcoindVersion
|
||||
int.toString.substring(0, 2) match {
|
||||
case "25" => V25
|
||||
case "26" => V26
|
||||
case "27" => V27
|
||||
case _ =>
|
||||
logger.warn(
|
||||
s"Unsupported Bitcoin Core version: $int. The latest supported version is ${BitcoindVersion.newest}"
|
||||
|
|
|
@ -4,7 +4,6 @@ import org.bitcoins.commons.jsonmodels.bitcoind._
|
|||
import org.bitcoins.commons.serializers.JsonSerializers._
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion._
|
||||
import play.api.libs.json.{JsString, Json}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
@ -24,27 +23,20 @@ trait UtilRpc { self: Client =>
|
|||
}
|
||||
|
||||
def decodeScript(script: ScriptPubKey): Future[DecodeScriptResult] = {
|
||||
self.version.flatMap { case V25 | V26 | Unknown =>
|
||||
bitcoindCall[DecodeScriptResultV22](
|
||||
"decodescript",
|
||||
List(Json.toJson(script))
|
||||
)
|
||||
}
|
||||
|
||||
bitcoindCall[DecodeScriptResultV22](
|
||||
"decodescript",
|
||||
List(Json.toJson(script))
|
||||
)
|
||||
}
|
||||
|
||||
def getIndexInfo: Future[Map[String, IndexInfoResult]] = {
|
||||
version.flatMap { case V25 | V26 | Unknown =>
|
||||
bitcoindCall[Map[String, IndexInfoResult]]("getindexinfo")
|
||||
}
|
||||
bitcoindCall[Map[String, IndexInfoResult]]("getindexinfo")
|
||||
}
|
||||
|
||||
def getIndexInfo(indexName: String): Future[IndexInfoResult] = {
|
||||
version.flatMap { case V25 | V26 | Unknown =>
|
||||
bitcoindCall[Map[String, IndexInfoResult]](
|
||||
"getindexinfo",
|
||||
List(JsString(indexName))
|
||||
).map(_.head._2)
|
||||
}
|
||||
bitcoindCall[Map[String, IndexInfoResult]](
|
||||
"getindexinfo",
|
||||
List(JsString(indexName))
|
||||
).map(_.head._2)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.bitcoins.core.protocol.blockchain.MerkleBlock
|
|||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionInput}
|
||||
import org.bitcoins.core.psbt.PSBT
|
||||
import org.bitcoins.crypto._
|
||||
import org.bitcoins.rpc.client.common.BitcoindVersion._
|
||||
import play.api.libs.json._
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
@ -160,14 +159,10 @@ trait WalletRpc { self: Client =>
|
|||
def getWalletInfo(
|
||||
walletName: String
|
||||
): Future[GetWalletInfoResult] = {
|
||||
self.version.flatMap {
|
||||
case BitcoindVersion.V25 | BitcoindVersion.V26 |
|
||||
BitcoindVersion.Unknown =>
|
||||
bitcoindCall[GetWalletInfoResultPostV22](
|
||||
"getwalletinfo",
|
||||
uriExtensionOpt = Some(walletExtension(walletName))
|
||||
)
|
||||
}
|
||||
bitcoindCall[GetWalletInfoResultPostV22](
|
||||
"getwalletinfo",
|
||||
uriExtensionOpt = Some(walletExtension(walletName))
|
||||
)
|
||||
}
|
||||
|
||||
def getWalletInfo: Future[GetWalletInfoResult] = {
|
||||
|
@ -381,32 +376,19 @@ trait WalletRpc { self: Client =>
|
|||
passphrase: String = "",
|
||||
avoidReuse: Boolean = false,
|
||||
descriptors: Boolean = true
|
||||
): Future[CreateWalletResult] =
|
||||
self.version.flatMap {
|
||||
case V25 | V26 =>
|
||||
bitcoindCall[CreateWalletResult](
|
||||
"createwallet",
|
||||
List(
|
||||
JsString(walletName),
|
||||
JsBoolean(disablePrivateKeys),
|
||||
JsBoolean(blank),
|
||||
if (passphrase.isEmpty) JsNull else JsString(passphrase),
|
||||
JsBoolean(avoidReuse),
|
||||
JsBoolean(descriptors)
|
||||
)
|
||||
)
|
||||
case Unknown =>
|
||||
bitcoindCall[CreateWalletResult](
|
||||
"createwallet",
|
||||
List(
|
||||
JsString(walletName),
|
||||
JsBoolean(disablePrivateKeys),
|
||||
JsBoolean(blank),
|
||||
JsString(passphrase),
|
||||
JsBoolean(avoidReuse)
|
||||
)
|
||||
)
|
||||
}
|
||||
): Future[CreateWalletResult] = {
|
||||
bitcoindCall[CreateWalletResult](
|
||||
"createwallet",
|
||||
List(
|
||||
JsString(walletName),
|
||||
JsBoolean(disablePrivateKeys),
|
||||
JsBoolean(blank),
|
||||
if (passphrase.isEmpty) JsNull else JsString(passphrase),
|
||||
JsBoolean(avoidReuse),
|
||||
JsBoolean(descriptors)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
def getAddressInfo(
|
||||
address: BitcoinAddress,
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package org.bitcoins.rpc.client.v27
|
||||
|
||||
import org.apache.pekko.actor.ActorSystem
|
||||
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
|
||||
import org.bitcoins.rpc.config.BitcoindInstance
|
||||
|
||||
import scala.concurrent.Future
|
||||
import scala.util.Try
|
||||
|
||||
class BitcoindV27RpcClient(override val instance: BitcoindInstance)(implicit
|
||||
actorSystem: ActorSystem
|
||||
) extends BitcoindRpcClient(instance) {
|
||||
|
||||
override lazy val version: Future[BitcoindVersion] =
|
||||
Future.successful(BitcoindVersion.V27)
|
||||
}
|
||||
|
||||
object BitcoindV27RpcClient {
|
||||
|
||||
/** Creates an RPC client from the given instance.
|
||||
*
|
||||
* Behind the scenes, we create an actor system for you. You can use
|
||||
* `withActorSystem` if you want to manually specify an actor system for the
|
||||
* RPC client.
|
||||
*/
|
||||
def apply(instance: BitcoindInstance): BitcoindV27RpcClient = {
|
||||
implicit val system: ActorSystem =
|
||||
ActorSystem.create(BitcoindRpcClient.ActorSystemName)
|
||||
withActorSystem(instance)
|
||||
}
|
||||
|
||||
/** Creates an RPC client from the given instance, together with the given
|
||||
* actor system. This is for advanced users, where you need fine grained
|
||||
* control over the RPC client.
|
||||
*/
|
||||
def withActorSystem(instance: BitcoindInstance)(implicit
|
||||
system: ActorSystem
|
||||
): BitcoindV27RpcClient =
|
||||
new BitcoindV27RpcClient(instance)(system)
|
||||
|
||||
def fromUnknownVersion(
|
||||
rpcClient: BitcoindRpcClient
|
||||
): Try[BitcoindV27RpcClient] =
|
||||
Try {
|
||||
new BitcoindV27RpcClient(rpcClient.instance)(rpcClient.system)
|
||||
}
|
||||
|
||||
}
|
|
@ -57,17 +57,16 @@ sealed trait BitcoindInstanceLocal extends BitcoindInstance {
|
|||
Seq(binaryPath, "--version").!!.split(Properties.lineSeparator).head
|
||||
.split(" ")
|
||||
.last
|
||||
|
||||
foundVersion match {
|
||||
case _: String
|
||||
if foundVersion.startsWith(BitcoindVersion.V25.toString) =>
|
||||
BitcoindVersion.V25
|
||||
case _: String =>
|
||||
BitcoindVersion.known
|
||||
.find(v => foundVersion.startsWith(v.toString))
|
||||
.getOrElse {
|
||||
println(
|
||||
s"Unsupported Bitcoin Core version: $foundVersion. The latest supported version is ${BitcoindVersion.newest}")
|
||||
logger.warn(
|
||||
s"Unsupported Bitcoin Core version: $foundVersion. The latest supported version is ${BitcoindVersion.newest}"
|
||||
)
|
||||
BitcoindVersion.newest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
versionT match {
|
||||
|
|
|
@ -38,7 +38,7 @@ trait LndFixture extends BitcoinSFixture with CachedBitcoindNewest {
|
|||
}
|
||||
|
||||
/** A trait that is useful if you need Lnd fixtures for your test suite */
|
||||
trait DualLndFixture extends BitcoinSFixture with CachedBitcoindNewest {
|
||||
trait DualLndFixture extends BitcoinSFixture with CachedBitcoindV26 {
|
||||
|
||||
override type FixtureParam = (BitcoindRpcClient, LndRpcClient, LndRpcClient)
|
||||
|
||||
|
|
|
@ -124,6 +124,15 @@ trait BitcoindFixturesCachedPair[T <: BitcoindRpcClient]
|
|||
} else {
|
||||
Future.unit
|
||||
}
|
||||
isNodeAdded <- BitcoindRpcTestUtil.isNodeAdded(bitcoinds)
|
||||
_ <-
|
||||
if (isNodeAdded) {
|
||||
val node1 = bitcoinds.node1
|
||||
val node2Uri = bitcoinds.node2.getDaemon.uri
|
||||
node1.addNode(node2Uri, AddNodeArgument.Remove)
|
||||
} else {
|
||||
Future.unit
|
||||
}
|
||||
} yield {
|
||||
nodePair
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.bitcoins.rpc.client.common.BitcoindVersion._
|
|||
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
|
||||
import org.bitcoins.rpc.client.v25.BitcoindV25RpcClient
|
||||
import org.bitcoins.rpc.client.v26.BitcoindV26RpcClient
|
||||
import org.bitcoins.rpc.client.v27.BitcoindV27RpcClient
|
||||
import org.bitcoins.rpc.config._
|
||||
import org.bitcoins.rpc.util.{NodePair, RpcUtil}
|
||||
import org.bitcoins.testkit.util.{BitcoindRpcTestClient, FileUtil, TorUtil}
|
||||
|
@ -103,7 +104,6 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
|||
|regtest=1
|
||||
|server=1
|
||||
|daemon=$isDaemon
|
||||
|v2transport=1
|
||||
|[regtest]
|
||||
|rpcuser=$username
|
||||
|rpcpassword=$pass
|
||||
|
@ -178,7 +178,7 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
|||
version match {
|
||||
// default to newest version
|
||||
case Unknown => getBinary(BitcoindVersion.newest, binaryDirectory)
|
||||
case known @ (V25 | V26) =>
|
||||
case known @ (V25 | V26 | V27) =>
|
||||
val fileList = Files
|
||||
.list(binaryDirectory)
|
||||
.iterator()
|
||||
|
@ -274,6 +274,22 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
|||
binaryDirectory = binaryDirectory
|
||||
)
|
||||
|
||||
def v27Instance(
|
||||
port: Int = RpcUtil.randomPort,
|
||||
rpcPort: Int = RpcUtil.randomPort,
|
||||
zmqConfig: ZmqConfig = RpcUtil.zmqConfig,
|
||||
pruneMode: Boolean = false,
|
||||
binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory
|
||||
)(implicit system: ActorSystem): BitcoindInstanceLocal =
|
||||
instance(
|
||||
port = port,
|
||||
rpcPort = rpcPort,
|
||||
zmqConfig = zmqConfig,
|
||||
pruneMode = pruneMode,
|
||||
versionOpt = Some(BitcoindVersion.V27),
|
||||
binaryDirectory = binaryDirectory
|
||||
)
|
||||
|
||||
/** Gets an instance of bitcoind with the given version */
|
||||
def getInstance(
|
||||
bitcoindVersion: BitcoindVersion,
|
||||
|
@ -300,6 +316,14 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
|||
pruneMode,
|
||||
binaryDirectory = binaryDirectory
|
||||
)
|
||||
case BitcoindVersion.V27 =>
|
||||
BitcoindRpcTestUtil.v27Instance(
|
||||
port,
|
||||
rpcPort,
|
||||
zmqConfig,
|
||||
pruneMode,
|
||||
binaryDirectory = binaryDirectory
|
||||
)
|
||||
case BitcoindVersion.Unknown =>
|
||||
sys.error(
|
||||
s"Could not create a bitcoind version with version=${BitcoindVersion.Unknown}"
|
||||
|
@ -642,6 +666,9 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
|||
case BitcoindVersion.V26 =>
|
||||
BitcoindV26RpcClient.withActorSystem(
|
||||
BitcoindRpcTestUtil.v26Instance())
|
||||
case BitcoindVersion.V27 =>
|
||||
BitcoindV27RpcClient.withActorSystem(
|
||||
BitcoindRpcTestUtil.v27Instance())
|
||||
}
|
||||
|
||||
// this is safe as long as this method is never
|
||||
|
@ -728,14 +755,18 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
|
|||
connectNodes(pair.node1, pair.node2)
|
||||
}
|
||||
|
||||
def disconnectNodes(
|
||||
first: BitcoindRpcClient,
|
||||
second: BitcoindRpcClient): Future[Unit] = {
|
||||
first.disconnectNode(second.getDaemon.uri)
|
||||
def disconnectNodes(first: BitcoindRpcClient, second: BitcoindRpcClient)(
|
||||
implicit system: ActorSystem): Future[Unit] = {
|
||||
import system.dispatcher
|
||||
val disconnectF = first.disconnectNode(second.getDaemon.uri)
|
||||
for {
|
||||
_ <- disconnectF
|
||||
_ <- awaitDisconnected(first, second)
|
||||
} yield ()
|
||||
}
|
||||
|
||||
def disconnectNodes[T <: BitcoindRpcClient](
|
||||
nodePair: NodePair[T]): Future[Unit] = {
|
||||
def disconnectNodes[T <: BitcoindRpcClient](nodePair: NodePair[T])(implicit
|
||||
system: ActorSystem): Future[Unit] = {
|
||||
disconnectNodes(nodePair.node1, nodePair.node2)
|
||||
}
|
||||
|
||||
|
|
|
@ -94,6 +94,17 @@ trait CachedBitcoindFunded[T <: BitcoindRpcClient] extends CachedBitcoind[T] {
|
|||
}
|
||||
}
|
||||
|
||||
trait CachedBitcoindV26 extends CachedBitcoindFunded[BitcoindRpcClient] {
|
||||
_: BitcoinSPekkoAsyncTest =>
|
||||
|
||||
override protected lazy val cachedBitcoindWithFundsF
|
||||
: Future[BitcoindRpcClient] = {
|
||||
val _ = isBitcoindUsed.set(true)
|
||||
BitcoinSFixture
|
||||
.createBitcoindWithFunds(Some(BitcoindVersion.V26))
|
||||
}
|
||||
}
|
||||
|
||||
trait CachedBitcoindNewest extends CachedBitcoindFunded[BitcoindRpcClient] {
|
||||
_: BitcoinSPekkoAsyncTest =>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue