diff --git a/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala b/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala index 4f748e89af..de705afb8a 100644 --- a/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala +++ b/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala @@ -3,13 +3,14 @@ package org.bitcoins.server.util import org.apache.pekko.actor.ActorSystem import org.apache.pekko.stream.scaladsl.{Sink, Source} import org.bitcoins.commons.util.BitcoinSLogger +import org.bitcoins.core.api.callback.OnBlockReceived import org.bitcoins.core.api.dlc.wallet.DLCNeutrinoHDWalletApi import org.bitcoins.core.api.wallet.{NeutrinoWalletApi, WalletApi} import org.bitcoins.core.gcs.GolombFilter import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader} import org.bitcoins.core.protocol.transaction.Transaction import org.bitcoins.crypto.DoubleSha256DigestBE -import org.bitcoins.node._ +import org.bitcoins.node.* import org.bitcoins.node.callback.NodeCallbackStreamManager import org.bitcoins.wallet.WalletNotInitialized diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/BitcoindInstanceTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/BitcoindInstanceTest.scala index 9476f405d4..06c913d34d 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/BitcoindInstanceTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/BitcoindInstanceTest.scala @@ -74,7 +74,7 @@ class BitcoindInstanceTest extends BitcoindRpcTest { .isInstanceOf[BitcoindAuthCredentials.CookieBased] ) - val cli = BitcoindRpcClient.withActorSystem(instance) + val cli = BitcoindRpcClient(instance) testClientStart(cli) } @@ -94,7 +94,7 @@ class BitcoindInstanceTest extends BitcoindRpcTest { instance.authCredentials .isInstanceOf[BitcoindAuthCredentials.PasswordBased] ) - testClientStart(BitcoindRpcClient.withActorSystem(instance)) + testClientStart(BitcoindRpcClient(instance)) } // the values in this conf was generated by executing @@ -132,13 +132,14 @@ class BitcoindInstanceTest extends BitcoindRpcTest { binary = newestBitcoindBinary ) - testClientStart(BitcoindRpcClient.withActorSystem(instance)) + testClientStart(BitcoindRpcClient(instance)) } it should "parse a bitcoin.conf file, start bitcoind, mine some blocks and quit" in { val instance = BitcoindInstanceLocal.fromDatadir(datadir.toFile, newestBitcoindBinary) - val client = BitcoindRpcClient.withActorSystem(instance) + val client = + BitcoindRpcClient(instance) for { _ <- startClient(client) @@ -185,7 +186,8 @@ class BitcoindInstanceTest extends BitcoindRpcTest { binary = newestBitcoindBinary ) - val client = BitcoindRpcClient.withActorSystem(instance) + val client = + BitcoindRpcClient(instance) for { _ <- startClient(client) remoteInstance = BitcoindInstanceRemote( @@ -196,7 +198,9 @@ class BitcoindInstanceTest extends BitcoindRpcTest { zmqConfig = instance.zmqConfig, proxyParams = None ) - remoteClient = BitcoindRpcClient.withActorSystem(remoteInstance) + remoteClient = new BitcoindRpcClient(remoteInstance)( + system, + instance.bitcoindRpcAppConfig) _ <- remoteClient.start() _ <- remoteClient.isStartedF.map { case false => diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala index 3c3707fec2..55c2bc0d6a 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala @@ -66,10 +66,10 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { // This client's wallet is encrypted lazy val walletClientF: Future[BitcoindRpcClient] = clientsF.flatMap { _ => + val instance = + BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.newest)) val walletClient = - BitcoindRpcClient.withActorSystem( - BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.newest)) - ) + BitcoindRpcClient(instance) for { _ <- startClient(walletClient) diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/BitcoindCallbacks.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/BitcoindCallbacks.scala new file mode 100644 index 0000000000..711f33bcf0 --- /dev/null +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/BitcoindCallbacks.scala @@ -0,0 +1,38 @@ +package org.bitcoins.rpc + +import org.bitcoins.commons.util.BitcoinSLogger +import org.bitcoins.core.api.CallbackHandler +import org.bitcoins.core.api.callback.{ + CallbackFactory, + ModuleCallbacks, + NodeApiCallbacks, + OnBlockReceived +} +import org.bitcoins.core.protocol.blockchain.Block + +trait BitcoindCallbacks + extends NodeApiCallbacks + with ModuleCallbacks[BitcoindCallbacks] + with BitcoinSLogger + +object BitcoindCallbacks extends CallbackFactory[BitcoindCallbacks] { + private case class BitcoindCallbacksImpl( + onBlockReceived: CallbackHandler[Block, OnBlockReceived]) + extends BitcoindCallbacks { + override def +(other: BitcoindCallbacks): BitcoindCallbacks = { + copy(onBlockReceived = onBlockReceived ++ other.onBlockReceived) + } + } + override def empty: BitcoindCallbacks = BitcoindCallbacksImpl( + CallbackHandler.empty) + + /** Constructs a set of callbacks that only acts on block received */ + def onBlockReceived(f: OnBlockReceived): BitcoindCallbacks = { + BitcoindCallbacksImpl(onBlockReceived = + CallbackHandler[Block, OnBlockReceived]( + "onBlockReceived", + Vector(f) + )) + } + +} diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala index 449e4932e4..7ed777621e 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala @@ -1,6 +1,8 @@ package org.bitcoins.rpc.client.common +import org.apache.pekko.Done import org.apache.pekko.actor.ActorSystem +import org.apache.pekko.stream.scaladsl.{Keep, RunnableGraph, Sink, Source} import org.bitcoins.commons.util.BitcoinSLogger import org.bitcoins.core.api.chain.db.BlockHeaderDb import org.bitcoins.core.api.chain.{ChainApi, FilterSyncMarker} @@ -19,7 +21,7 @@ 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 org.bitcoins.rpc.config.* import java.io.File import java.util.concurrent.atomic.AtomicBoolean @@ -35,7 +37,8 @@ import scala.concurrent.Future * handle them as you see fit. */ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit - override val system: ActorSystem + override val system: ActorSystem, + bitcoindRpcAppConfig: BitcoindRpcAppConfig ) extends Client with FeeRateApi with NodeApi @@ -166,7 +169,17 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit override def downloadBlocks( blockHashes: Vector[DoubleSha256DigestBE] - ): Future[Unit] = Future.unit + ): Future[Unit] = { + val callback = + bitcoindRpcAppConfig.callBacks.executeOnBlockReceivedCallbacks(_) + val graph: RunnableGraph[Future[Done]] = Source(blockHashes) + .mapAsync(FutureUtil.getParallelism)(getBlockRaw) + .toMat(Sink.foreachAsync(1)(callback))(Keep.right) + + graph + .run() + .map(_ => ()) + } override def processHeaders(headers: Vector[BlockHeader]): Future[ChainApi] = Future.successful(this) @@ -294,35 +307,16 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit } object BitcoindRpcClient { - - /** The name we give to actor systems we create. We use this information to - * know which actor systems to shut down - */ - private[rpc] val ActorSystemName = "bitcoind-rpc-client-created-by-bitcoin-s" - - implicit private lazy val system: ActorSystem = - ActorSystem.create(ActorSystemName) - val DEFAULT_WALLET_NAME: String = "wallet.dat" - /** 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): BitcoindRpcClient = { - withActorSystem(instance)(system) - } - /** 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 + def apply(instance: BitcoindInstanceLocal)(implicit system: ActorSystem ): BitcoindRpcClient = - new BitcoindRpcClient(instance) + new BitcoindRpcClient(instance)(system, instance.bitcoindRpcAppConfig) /** Constructs a RPC client from the given datadir, or the default datadir if * no directory is provided. This is always a [[BitcoindInstanceLocal]] since @@ -331,7 +325,7 @@ object BitcoindRpcClient { def fromDatadir( datadir: File = BitcoindConfig.DEFAULT_DATADIR, binary: File - ): BitcoindRpcClient = { + )(implicit system: ActorSystem): BitcoindRpcClient = { val instance = BitcoindInstanceLocal.fromDatadir(datadir, binary) val cli = BitcoindRpcClient(instance) cli @@ -340,13 +334,13 @@ object BitcoindRpcClient { /** Returns a bitcoind with the appropriated version you passed in, the * bitcoind is NOT started. */ - def fromVersion(version: BitcoindVersion, instance: BitcoindInstance)(implicit - system: ActorSystem + def fromVersion(version: BitcoindVersion, instance: BitcoindInstanceLocal)( + implicit system: ActorSystem ): 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.V25 => BitcoindV25RpcClient(instance) + case BitcoindVersion.V26 => BitcoindV26RpcClient(instance) + case BitcoindVersion.V27 => BitcoindV27RpcClient(instance) case BitcoindVersion.Unknown => sys.error( s"Cannot create a Bitcoin Core RPC client: unsupported version" @@ -355,11 +349,24 @@ object BitcoindRpcClient { bitcoind } - def fromVersionNoSystem( - version: BitcoindVersion, - instance: BitcoindInstance + /** Returns a bitcoind with the appropriated version you passed in, the + * bitcoind is NOT started. + */ + def fromVersion(version: BitcoindVersion, instance: BitcoindInstanceRemote)( + implicit + system: ActorSystem, + bitcoindRpcAppConfig: BitcoindRpcAppConfig ): BitcoindRpcClient = { - fromVersion(version, instance)(system) + val bitcoind = version match { + case BitcoindVersion.V25 => new BitcoindV25RpcClient(instance) + case BitcoindVersion.V26 => new BitcoindV26RpcClient(instance) + case BitcoindVersion.V27 => new BitcoindV27RpcClient(instance) + case BitcoindVersion.Unknown => + sys.error( + s"Cannot create a Bitcoin Core RPC client: unsupported version" + ) + } + bitcoind } } 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 51f9161f0c..5d75cb6bf1 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 @@ -323,11 +323,6 @@ trait Client // i think bitcoind stops asynchronously // so it returns fast from the 'stop' rpc command _ <- stopBinary() - _ <- { - if (system.name == BitcoindRpcClient.ActorSystemName) { - system.terminate() - } else Future.unit - } } yield this.asInstanceOf[BitcoindRpcClient] } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v25/BitcoindV25RpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v25/BitcoindV25RpcClient.scala index 60adac2f90..57e5be636d 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v25/BitcoindV25RpcClient.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v25/BitcoindV25RpcClient.scala @@ -2,13 +2,17 @@ package org.bitcoins.rpc.client.v25 import org.apache.pekko.actor.ActorSystem import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion} -import org.bitcoins.rpc.config.BitcoindInstance +import org.bitcoins.rpc.config.{ + BitcoindInstance, + BitcoindInstanceLocal, + BitcoindRpcAppConfig +} import scala.concurrent.Future -import scala.util.Try class BitcoindV25RpcClient(override val instance: BitcoindInstance)(implicit - actorSystem: ActorSystem + actorSystem: ActorSystem, + bitcoindRpcAppConfig: BitcoindRpcAppConfig ) extends BitcoindRpcClient(instance) { override lazy val version: Future[BitcoindVersion] = @@ -17,32 +21,13 @@ class BitcoindV25RpcClient(override val instance: BitcoindInstance)(implicit object BitcoindV25RpcClient { - /** 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): BitcoindV25RpcClient = { - 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 + def apply(instance: BitcoindInstanceLocal)(implicit system: ActorSystem ): BitcoindV25RpcClient = - new BitcoindV25RpcClient(instance)(system) - - def fromUnknownVersion( - rpcClient: BitcoindRpcClient - ): Try[BitcoindV25RpcClient] = - Try { - new BitcoindV25RpcClient(rpcClient.instance)(rpcClient.system) - } + new BitcoindV25RpcClient(instance)(system, instance.bitcoindRpcAppConfig) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v26/BitcoindV26RpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v26/BitcoindV26RpcClient.scala index ae14f73128..95e6d42770 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v26/BitcoindV26RpcClient.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v26/BitcoindV26RpcClient.scala @@ -2,13 +2,17 @@ package org.bitcoins.rpc.client.v26 import org.apache.pekko.actor.ActorSystem import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion} -import org.bitcoins.rpc.config.BitcoindInstance +import org.bitcoins.rpc.config.{ + BitcoindInstance, + BitcoindInstanceLocal, + BitcoindRpcAppConfig +} import scala.concurrent.Future -import scala.util.Try class BitcoindV26RpcClient(override val instance: BitcoindInstance)(implicit - actorSystem: ActorSystem + actorSystem: ActorSystem, + bitcoindRpcAppConfig: BitcoindRpcAppConfig ) extends BitcoindRpcClient(instance) { override lazy val version: Future[BitcoindVersion] = @@ -17,32 +21,13 @@ class BitcoindV26RpcClient(override val instance: BitcoindInstance)(implicit object BitcoindV26RpcClient { - /** 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): BitcoindV26RpcClient = { - 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 + def apply(instance: BitcoindInstanceLocal)(implicit system: ActorSystem ): BitcoindV26RpcClient = - new BitcoindV26RpcClient(instance)(system) - - def fromUnknownVersion( - rpcClient: BitcoindRpcClient - ): Try[BitcoindV26RpcClient] = - Try { - new BitcoindV26RpcClient(rpcClient.instance)(rpcClient.system) - } + new BitcoindV26RpcClient(instance)(system, instance.bitcoindRpcAppConfig) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v27/BitcoindV27RpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v27/BitcoindV27RpcClient.scala index 2a4003beb9..5157348276 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v27/BitcoindV27RpcClient.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v27/BitcoindV27RpcClient.scala @@ -2,13 +2,17 @@ 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 org.bitcoins.rpc.config.{ + BitcoindInstance, + BitcoindInstanceLocal, + BitcoindRpcAppConfig +} import scala.concurrent.Future -import scala.util.Try class BitcoindV27RpcClient(override val instance: BitcoindInstance)(implicit - actorSystem: ActorSystem + actorSystem: ActorSystem, + bitcoindRpcAppConfig: BitcoindRpcAppConfig ) extends BitcoindRpcClient(instance) { override lazy val version: Future[BitcoindVersion] = @@ -17,32 +21,13 @@ class BitcoindV27RpcClient(override val instance: BitcoindInstance)(implicit 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 + def apply(instance: BitcoindInstanceLocal)(implicit system: ActorSystem ): BitcoindV27RpcClient = - new BitcoindV27RpcClient(instance)(system) - - def fromUnknownVersion( - rpcClient: BitcoindRpcClient - ): Try[BitcoindV27RpcClient] = - Try { - new BitcoindV27RpcClient(rpcClient.instance)(rpcClient.system) - } + new BitcoindV27RpcClient(instance)(system, instance.bitcoindRpcAppConfig) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala index 03a7b0a018..2d3c2c0ee6 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala @@ -77,6 +77,10 @@ sealed trait BitcoindInstanceLocal extends BitcoindInstance { throw exception } } + + def bitcoindRpcAppConfig: BitcoindRpcAppConfig = { + BitcoindRpcAppConfig.fromDatadir(datadir.toPath) + } } /** Refers to a bitcoind instance that is running remotely on another machine */ diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala index 4803fe31df..0203aaa1dc 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala @@ -4,7 +4,10 @@ import com.typesafe.config.Config import org.apache.pekko.actor.ActorSystem import org.bitcoins.asyncutil.AsyncUtil import org.bitcoins.commons.config.{AppConfig, ConfigOps} +import org.bitcoins.core.api.CallbackConfig +import org.bitcoins.core.api.callback.CallbackFactory import org.bitcoins.core.api.tor.Socks5ProxyParams +import org.bitcoins.rpc.BitcoindCallbacks import org.bitcoins.rpc.BitcoindException.InWarmUp import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion} import org.bitcoins.rpc.util.AppConfigFactoryActorSystem @@ -12,7 +15,7 @@ import org.bitcoins.tor.config.TorAppConfig import java.io.File import java.net.{InetSocketAddress, URI} -import java.nio.file._ +import java.nio.file.* import scala.concurrent.duration.DurationInt import scala.concurrent.{Future, Promise} @@ -26,7 +29,8 @@ case class BitcoindRpcAppConfig( baseDatadir: Path, configOverrides: Vector[Config] )(implicit val system: ActorSystem) - extends AppConfig { + extends AppConfig + with CallbackConfig[BitcoindCallbacks] { import system.dispatcher @@ -180,12 +184,13 @@ case class BitcoindRpcAppConfig( bitcoindInstance match { case local: BitcoindInstanceLocal => val version = versionOpt.getOrElse(local.getVersion) - val client = BitcoindRpcClient.fromVersion(version, bitcoindInstance) + val client = + BitcoindRpcClient.fromVersion(version, local) Future.successful(client) - case _: BitcoindInstanceRemote => + case remote: BitcoindInstanceRemote => // first get a generic rpc client so we can retrieve // the proper version of the remote running bitcoind - val noVersionRpc = new BitcoindRpcClient(bitcoindInstance) + val noVersionRpc = new BitcoindRpcClient(remote)(system, this) val versionF = getBitcoindVersion(noVersionRpc) // if we don't retrieve the proper version, we can @@ -194,7 +199,8 @@ case class BitcoindRpcAppConfig( // such as blockfilters // see: https://github.com/bitcoin-s/bitcoin-s/issues/3695#issuecomment-929492945 versionF.map { version => - BitcoindRpcClient.fromVersion(version, instance = bitcoindInstance) + BitcoindRpcClient.fromVersion(version, instance = remote)(system, + this) } } } @@ -227,6 +233,9 @@ case class BitcoindRpcAppConfig( version } } + + override def callbackFactory: CallbackFactory[BitcoindCallbacks] = + BitcoindCallbacks } object BitcoindRpcAppConfig diff --git a/core/src/main/scala/org/bitcoins/core/api/callback/NodeApiCallbacks.scala b/core/src/main/scala/org/bitcoins/core/api/callback/NodeApiCallbacks.scala new file mode 100644 index 0000000000..bca9289dd2 --- /dev/null +++ b/core/src/main/scala/org/bitcoins/core/api/callback/NodeApiCallbacks.scala @@ -0,0 +1,18 @@ +package org.bitcoins.core.api.callback + +import org.bitcoins.core.api.{Callback, CallbackHandler} +import org.bitcoins.core.protocol.blockchain.Block + +import scala.concurrent.{ExecutionContext, Future} + +/** Callback for handling a received block */ +trait OnBlockReceived extends Callback[Block] + +trait NodeApiCallbacks { + def onBlockReceived: CallbackHandler[Block, OnBlockReceived] + def executeOnBlockReceivedCallbacks( + block: Block + )(implicit ec: ExecutionContext): Future[Unit] = { + onBlockReceived.execute(block) + } +} diff --git a/docs/chain/chain-query-api.md b/docs/chain/chain-query-api.md index 071893c830..d615702384 100644 --- a/docs/chain/chain-query-api.md +++ b/docs/chain/chain-query-api.md @@ -5,6 +5,7 @@ title: Chain Query API ```scala mdoc:invisible import org.apache.pekko.actor.ActorSystem +import org.bitcoins.core.api.callback.OnBlockReceived import org.bitcoins.core.api.chain.ChainQueryApi import org.bitcoins.core.api.chain.ChainQueryApi.FilterResponse import org.bitcoins.crypto._ diff --git a/docs/node/node-api.md b/docs/node/node-api.md index 5f6103a5b8..50071a1b10 100644 --- a/docs/node/node-api.md +++ b/docs/node/node-api.md @@ -4,6 +4,7 @@ id: node-api title: Node API ```scala mdoc:invisible import org.apache.pekko.actor.ActorSystem +import org.bitcoins.core.api.callback.OnBlockReceived import org.bitcoins.core.api.node._ import org.bitcoins.crypto._ import org.bitcoins.core.protocol.blockchain.Block diff --git a/docs/node/node.md b/docs/node/node.md index c400432b6f..d766114a5b 100644 --- a/docs/node/node.md +++ b/docs/node/node.md @@ -43,6 +43,7 @@ For your node to be able to service these filters you will need set ```scala mdoc:invisible import org.apache.pekko.actor.ActorSystem import org.bitcoins.chain.config.ChainAppConfig +import org.bitcoins.core.api.callback.OnBlockReceived import org.bitcoins.core.protocol.blockchain.Block import org.bitcoins.node._ import org.bitcoins.node.config.NodeAppConfig diff --git a/docs/rpc/bitcoind.md b/docs/rpc/bitcoind.md index ca9cbaee1f..e03a4cdf14 100644 --- a/docs/rpc/bitcoind.md +++ b/docs/rpc/bitcoind.md @@ -130,8 +130,8 @@ class is only intended to cover errors returned by Bitcoin Core. An example of h handling could look: ```scala mdoc:compile-only - -implicit val ec: ExecutionContext = ExecutionContext.global +implicit val system: ActorSystem = ActorSystem() +implicit val ec: ExecutionContext = system.dispatcher // let's assume you have an already running client, // so there's no need to start this one diff --git a/node-test/src/test/scala/org/bitcoins/node/networking/peer/DataMessageHandlerTest.scala b/node-test/src/test/scala/org/bitcoins/node/networking/peer/DataMessageHandlerTest.scala index bb85b850a1..2b8cfdf03d 100644 --- a/node-test/src/test/scala/org/bitcoins/node/networking/peer/DataMessageHandlerTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/networking/peer/DataMessageHandlerTest.scala @@ -3,15 +3,16 @@ package org.bitcoins.node.networking.peer import com.typesafe.config.ConfigFactory import org.bitcoins.asyncutil.AsyncUtil import org.bitcoins.chain.blockchain.ChainHandler +import org.bitcoins.core.api.callback.OnBlockReceived import org.bitcoins.core.config.SigNet -import org.bitcoins.core.currency._ +import org.bitcoins.core.currency.* import org.bitcoins.core.gcs.{FilterType, GolombFilter} import org.bitcoins.core.p2p.HeadersMessage import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader} import org.bitcoins.core.protocol.transaction.Transaction import org.bitcoins.crypto.DoubleSha256DigestBE import org.bitcoins.node.NodeState.{FilterHeaderSync, HeaderSync} -import org.bitcoins.node._ +import org.bitcoins.node.* import org.bitcoins.server.BitcoinSAppConfig import org.bitcoins.testkit.BitcoinSTestAppConfig import org.bitcoins.testkit.node.fixture.NeutrinoNodeConnectedWithBitcoind diff --git a/node/src/main/scala/org/bitcoins/node/NodeCallbacks.scala b/node/src/main/scala/org/bitcoins/node/NodeCallbacks.scala index 3a0b938995..1531ccb10a 100644 --- a/node/src/main/scala/org/bitcoins/node/NodeCallbacks.scala +++ b/node/src/main/scala/org/bitcoins/node/NodeCallbacks.scala @@ -2,7 +2,12 @@ package org.bitcoins.node import org.apache.pekko.actor.ActorSystem import org.bitcoins.commons.util.BitcoinSLogger -import org.bitcoins.core.api.callback.{CallbackFactory, ModuleCallbacks} +import org.bitcoins.core.api.callback.{ + CallbackFactory, + ModuleCallbacks, + NodeApiCallbacks, + OnBlockReceived +} import org.bitcoins.core.api.{Callback, Callback2, CallbackHandler} import org.bitcoins.core.gcs.GolombFilter import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader, MerkleBlock} @@ -15,7 +20,10 @@ import scala.concurrent.{ExecutionContext, Future} /** Callbacks for responding to events in the node. The appropriate callback is * executed whenever the node receives a `getdata` message matching it. */ -trait NodeCallbacks extends ModuleCallbacks[NodeCallbacks] with BitcoinSLogger { +trait NodeCallbacks + extends ModuleCallbacks[NodeCallbacks] + with NodeApiCallbacks + with BitcoinSLogger { def onCompactFiltersReceived : CallbackHandler[Vector[ @@ -25,8 +33,6 @@ trait NodeCallbacks extends ModuleCallbacks[NodeCallbacks] with BitcoinSLogger { def onTxReceived: CallbackHandler[Transaction, OnTxReceived] - def onBlockReceived: CallbackHandler[Block, OnBlockReceived] - def onMerkleBlockReceived: CallbackHandler[ (MerkleBlock, Vector[Transaction]), OnMerkleBlockReceived @@ -47,7 +53,7 @@ trait NodeCallbacks extends ModuleCallbacks[NodeCallbacks] with BitcoinSLogger { ) } - def executeOnBlockReceivedCallbacks( + override def executeOnBlockReceivedCallbacks( block: Block )(implicit ec: ExecutionContext): Future[Unit] = { onBlockReceived.execute( @@ -101,9 +107,6 @@ trait NodeCallbacks extends ModuleCallbacks[NodeCallbacks] with BitcoinSLogger { } } -/** Callback for handling a received block */ -trait OnBlockReceived extends Callback[Block] - /** Callback for handling a received Merkle block with its corresponding TXs */ trait OnMerkleBlockReceived extends Callback2[MerkleBlock, Vector[Transaction]] diff --git a/node/src/main/scala/org/bitcoins/node/callback/NodeCallbackStreamManager.scala b/node/src/main/scala/org/bitcoins/node/callback/NodeCallbackStreamManager.scala index d6b8909214..e12a64f8ad 100644 --- a/node/src/main/scala/org/bitcoins/node/callback/NodeCallbackStreamManager.scala +++ b/node/src/main/scala/org/bitcoins/node/callback/NodeCallbackStreamManager.scala @@ -11,12 +11,13 @@ import org.apache.pekko.stream.scaladsl.{ } import org.bitcoins.commons.util.BitcoinSLogger import org.bitcoins.core.api.CallbackHandler +import org.bitcoins.core.api.callback.OnBlockReceived import org.bitcoins.core.gcs.GolombFilter import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader, MerkleBlock} import org.bitcoins.core.protocol.transaction.Transaction import org.bitcoins.core.util.StartStopAsync import org.bitcoins.crypto.DoubleSha256DigestBE -import org.bitcoins.node._ +import org.bitcoins.node.* import java.util.concurrent.atomic.AtomicBoolean import scala.concurrent.{ExecutionContext, Future} diff --git a/testkit/src/main/scala/org/bitcoins/testkit/eclair/rpc/EclairRpcTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/eclair/rpc/EclairRpcTestUtil.scala index 054bec7e5e..317cd367a4 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/eclair/rpc/EclairRpcTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/eclair/rpc/EclairRpcTestUtil.scala @@ -18,7 +18,7 @@ import org.bitcoins.core.protocol.ln.channel.{ import org.bitcoins.core.protocol.ln.currency.MilliSatoshis import org.bitcoins.core.protocol.ln.node.NodeId import org.bitcoins.crypto.Sha256Digest -import org.bitcoins.eclair.rpc.api._ +import org.bitcoins.eclair.rpc.api.* import org.bitcoins.eclair.rpc.client.EclairRpcClient import org.bitcoins.eclair.rpc.config.EclairInstanceLocal import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion} @@ -768,7 +768,7 @@ trait EclairRpcTestUtil extends BitcoinSLogger { authCredentials = auth.bitcoinAuthOpt.get, binary = BitcoindRpcTestUtil.getBinary(bitcoindVersion) ) - BitcoindRpcClient.withActorSystem(bitcoindInstance) + BitcoindRpcClient(bitcoindInstance) } bitcoindRpc } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSFixture.scala index d62e513f54..2007d02a60 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSFixture.scala @@ -2,9 +2,10 @@ package org.bitcoins.testkit.fixtures import org.apache.pekko.actor.ActorSystem import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion} +import org.bitcoins.rpc.config.BitcoindRpcAppConfig import org.bitcoins.testkit.rpc.BitcoindRpcTestUtil import org.bitcoins.testkit.util.BitcoinSAsyncFixtureTest -import org.scalatest._ +import org.scalatest.* import scala.concurrent.{ExecutionContext, Future, Promise} import scala.util.{Failure, Success} @@ -125,9 +126,11 @@ object BitcoinSFixture { versionOpt = versionOpt, enableNeutrino = enableNeutrino ) + val appConfig = BitcoindRpcAppConfig.fromDatadir(instance.datadir.toPath) val bitcoind = versionOpt match { - case Some(v) => BitcoindRpcClient.fromVersion(v, instance) - case None => new BitcoindRpcClient(instance) + case Some(v) => + BitcoindRpcClient.fromVersion(v, instance) + case None => new BitcoindRpcClient(instance)(system, appConfig) } BitcoindRpcTestUtil.startServers(Vector(bitcoind)).map(_ => bitcoind) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala index 3c16af9232..96bfb52cc4 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala @@ -618,10 +618,12 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { system: ActorSystem ): Future[(BitcoindRpcClient, BitcoindRpcClient)] = { implicit val ec: ExecutionContextExecutor = system.getDispatcher + val instance1 = instance() + val instance2 = instance() val client1: BitcoindRpcClient = - BitcoindRpcClient.withActorSystem(instance()) + BitcoindRpcClient(instance1) val client2: BitcoindRpcClient = - BitcoindRpcClient.withActorSystem(instance()) + BitcoindRpcClient(instance2) startServers(Vector(client1, client2)).map { _ => clientAccum ++= List(client1, client2) @@ -673,16 +675,17 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { val clients: Vector[T] = (0 until numNodes).map { _ => val rpc = version match { case BitcoindVersion.Unknown => - BitcoindRpcClient.withActorSystem(BitcoindRpcTestUtil.instance()) + val instance = BitcoindRpcTestUtil.instance() + BitcoindRpcClient(instance) case BitcoindVersion.V25 => - BitcoindV25RpcClient.withActorSystem( - BitcoindRpcTestUtil.v25Instance()) + val instance = BitcoindRpcTestUtil.v25Instance() + BitcoindV25RpcClient(instance) case BitcoindVersion.V26 => - BitcoindV26RpcClient.withActorSystem( - BitcoindRpcTestUtil.v26Instance()) + val instance = BitcoindRpcTestUtil.v26Instance() + BitcoindV26RpcClient(instance) case BitcoindVersion.V27 => - BitcoindV27RpcClient.withActorSystem( - BitcoindRpcTestUtil.v27Instance()) + val instance = BitcoindRpcTestUtil.v27Instance() + BitcoindV27RpcClient(instance) } // this is safe as long as this method is never @@ -1071,7 +1074,7 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { ) // start the bitcoind instance so eclair can properly use it - val rpc = BitcoindRpcClient.withActorSystem(instance) + val rpc = BitcoindRpcClient(instance) val startedF = startServers(Vector(rpc)) val blocksToGenerate = 102