--- id: node-api title: Node API --- ```scala mdoc:invisible import akka.actor.ActorSystem import org.bitcoins.core.api._ import org.bitcoins.core.api.node._ import org.bitcoins.crypto._ import org.bitcoins.core.protocol.blockchain.Block import org.bitcoins.core.protocol.transaction.Transaction import org.bitcoins.core.wallet.fee._ import org.bitcoins.feeprovider._ import org.bitcoins.keymanager.bip39.BIP39KeyManager import org.bitcoins.node._ import org.bitcoins.node.networking.peer.DataMessageHandler._ import org.bitcoins.rpc.client.v19.BitcoindV19RpcClient import org.bitcoins.rpc.config.BitcoindInstance import org.bitcoins.testkit.BitcoinSTestAppConfig import org.bitcoins.testkit.wallet.BitcoinSWalletTest import org.bitcoins.wallet.Wallet import org.bitcoins.wallet.config.WalletAppConfig import java.time.Instant import scala.concurrent.{ExecutionContextExecutor, Future} ``` ### NodeAPI 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. 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. 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 val bitcoind = BitcoindV19RpcClient(BitcoindInstance.fromConfigFile()) val chainApi = BitcoinSWalletTest.MockChainQueryApi val aesPasswordOpt = Some(AesPassword.fromString("password")) // Create our key manager val keyManagerE = BIP39KeyManager.initialize(aesPasswordOpt = aesPasswordOpt, kmParams = walletConf.kmParams, bip39PasswordOpt = None) val keyManager = keyManagerE match { case Right(keyManager) => keyManager case Left(err) => throw new RuntimeException(s"Cannot initialize key manager err=$err") } // 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 def createCallback(processBlock: Block => Future[Unit]): NodeCallbacks = { lazy val onBlock: OnBlockReceived = { block => processBlock(block) } NodeCallbacks(onBlockReceived = Vector(onBlock)) } // 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) => Future.successful(println(s"Received block: ${block.blockHeader.hashBE}")) 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 { override def broadcastTransaction(transaction: Transaction): Future[Unit] = { bitcoind.sendRawTransaction(transaction).map(_ => ()) } 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 = Wallet(keyManager = keyManager, nodeApi = nodeApi, chainQueryApi = chainApi, feeRateApi = ConstantFeeRateProvider(SatoshisPerVirtualByte.one), creationTime = Instant.now) // Then to trigger the event we can run val exampleBlock = DoubleSha256Digest( "000000000010dc23dc0d5acad64667a7a2b3010b6e02da4868bf392c90b6431d") wallet.nodeApi.downloadBlocks(Vector(exampleBlock)) ```