2020-03-11 11:07:30 -05:00
|
|
|
---
|
2021-04-07 08:13:43 -05:00
|
|
|
id: node-api title: Node API
|
2020-03-11 11:07:30 -05:00
|
|
|
---
|
|
|
|
|
|
|
|
```scala mdoc:invisible
|
|
|
|
import akka.actor.ActorSystem
|
2020-08-12 06:13:23 -05:00
|
|
|
import org.bitcoins.core.api.node._
|
2020-11-06 07:00:18 -06:00
|
|
|
import org.bitcoins.crypto._
|
2020-03-11 11:07:30 -05:00
|
|
|
import org.bitcoins.core.protocol.blockchain.Block
|
2020-04-21 13:14:02 -05:00
|
|
|
import org.bitcoins.core.protocol.transaction.Transaction
|
2020-05-29 13:01:20 -05:00
|
|
|
import org.bitcoins.core.wallet.fee._
|
2021-04-07 08:13:43 -05:00
|
|
|
import org.bitcoins.core.util._
|
2020-05-29 13:01:20 -05:00
|
|
|
import org.bitcoins.feeprovider._
|
2020-06-15 17:30:08 -05:00
|
|
|
import org.bitcoins.node._
|
2020-03-11 11:07:30 -05:00
|
|
|
import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient
|
2021-09-07 19:19:01 +05:30
|
|
|
import org.bitcoins.rpc.config._
|
2020-03-11 11:07:30 -05:00
|
|
|
import org.bitcoins.testkit.BitcoinSTestAppConfig
|
|
|
|
import org.bitcoins.testkit.wallet.BitcoinSWalletTest
|
|
|
|
import org.bitcoins.wallet.Wallet
|
|
|
|
import org.bitcoins.wallet.config.WalletAppConfig
|
|
|
|
|
2020-04-29 09:49:41 -05:00
|
|
|
|
2020-03-11 11:07:30 -05:00
|
|
|
import scala.concurrent.{ExecutionContextExecutor, Future}
|
|
|
|
```
|
|
|
|
|
2020-03-13 09:54:07 -05:00
|
|
|
### NodeAPI
|
2020-03-11 11:07:30 -05:00
|
|
|
|
2021-04-07 08:13:43 -05:00
|
|
|
The NodeApi is how the wallet project retrieves relevant node data like blocks. This allows the wallet for example to
|
|
|
|
retrieve blocks for finding its relevant transactions.
|
2020-03-11 11:07:30 -05:00
|
|
|
|
2021-04-07 08:13:43 -05:00
|
|
|
Since this is an API it can be hooked up to the `node` module of bitcoin-s but it can also be linked to any other
|
|
|
|
implementation of your choosing. This allows you to use the bitcoin-s wallet in any schema that you want.
|
2020-03-11 11:07:30 -05:00
|
|
|
|
|
|
|
The functions that the NodeApi supports are:
|
|
|
|
|
|
|
|
```scala mdoc:compile-only
|
|
|
|
trait NodeApi {
|
|
|
|
|
|
|
|
/** Request the underlying node to download the given blocks from its peers and feed the blocks to [[org.bitcoins.node.NodeCallbacks]] */
|
|
|
|
def downloadBlocks(blockHashes: Vector[DoubleSha256Digest]): Future[Unit]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Downloading blocks with bitcoind
|
|
|
|
|
|
|
|
As an example, we will show you how to use the `NodeApi` and bitcoind to download blocks for a wallet.
|
|
|
|
|
|
|
|
```scala mdoc:compile-only
|
|
|
|
implicit val system: ActorSystem = ActorSystem(s"node-api-example")
|
|
|
|
implicit val ec: ExecutionContextExecutor = system.dispatcher
|
|
|
|
implicit val walletConf: WalletAppConfig =
|
|
|
|
BitcoinSTestAppConfig.getSpvTestConfig().walletConf
|
|
|
|
|
|
|
|
// let's use a helper method to get a v19 bitcoind
|
|
|
|
// and a ChainApi
|
2021-09-07 19:19:01 +05:30
|
|
|
val instance = BitcoindInstanceLocal.fromConfigFile(BitcoindConfig.DEFAULT_CONF_FILE)
|
|
|
|
val bitcoind = BitcoindV19RpcClient(instance)
|
2020-03-11 11:07:30 -05:00
|
|
|
val chainApi = BitcoinSWalletTest.MockChainQueryApi
|
2020-11-06 07:00:18 -06:00
|
|
|
val aesPasswordOpt = Some(AesPassword.fromString("password"))
|
2020-03-11 11:07:30 -05:00
|
|
|
|
|
|
|
// This function can be used to create a callback for when our node api calls downloadBlocks,
|
|
|
|
// more specifically it will call the function every time we receive a block, the returned
|
|
|
|
// NodeCallbacks will contain the necessary items to initialize the callbacks
|
2020-04-03 08:57:41 -05:00
|
|
|
def createCallback(processBlock: Block => Future[Unit]): NodeCallbacks = {
|
2020-03-11 11:07:30 -05:00
|
|
|
lazy val onBlock: OnBlockReceived = { block =>
|
|
|
|
processBlock(block)
|
|
|
|
}
|
2020-06-15 17:30:08 -05:00
|
|
|
NodeCallbacks(onBlockReceived = Vector(onBlock))
|
2020-03-11 11:07:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Here is a super simple example of a callback, this could be replaced with anything, from
|
|
|
|
// relaying the block on the network, finding relevant wallet transactions, verifying the block,
|
|
|
|
// or writing it to disk
|
|
|
|
val exampleProcessBlock = (block: Block) =>
|
2020-04-03 08:57:41 -05:00
|
|
|
Future.successful(println(s"Received block: ${block.blockHeader.hashBE}"))
|
2020-03-11 11:07:30 -05:00
|
|
|
val exampleCallback = createCallback(exampleProcessBlock)
|
|
|
|
|
|
|
|
// Here is where we are defining our actual node api, Ideally this could be it's own class
|
|
|
|
// but for the examples sake we will keep it small.
|
|
|
|
val nodeApi = new NodeApi {
|
2020-04-21 13:14:02 -05:00
|
|
|
|
2021-04-07 08:13:43 -05:00
|
|
|
override def broadcastTransactions(transactions: Vector[Transaction]): Future[Unit] = {
|
|
|
|
FutureUtil.sequentially(transactions)(bitcoind.sendRawTransaction(_)).map(_ => ())
|
2020-04-21 13:14:02 -05:00
|
|
|
}
|
|
|
|
|
2020-03-11 11:07:30 -05:00
|
|
|
override def downloadBlocks(
|
|
|
|
blockHashes: Vector[DoubleSha256Digest]): Future[Unit] = {
|
|
|
|
val blockFs = blockHashes.map(hash => bitcoind.getBlockRaw(hash))
|
|
|
|
Future.sequence(blockFs).map(_ => ())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, we can initialize our wallet with our own node api
|
|
|
|
val wallet =
|
2021-09-18 09:49:11 -05:00
|
|
|
Wallet(nodeApi = nodeApi, chainQueryApi = chainApi, feeRateApi = ConstantFeeRateProvider(SatoshisPerVirtualByte.one))
|
2020-03-11 11:07:30 -05:00
|
|
|
|
|
|
|
// Then to trigger the event we can run
|
|
|
|
val exampleBlock = DoubleSha256Digest(
|
|
|
|
"000000000010dc23dc0d5acad64667a7a2b3010b6e02da4868bf392c90b6431d")
|
|
|
|
wallet.nodeApi.downloadBlocks(Vector(exampleBlock))
|
|
|
|
|
2021-04-07 08:13:43 -05:00
|
|
|
```
|