bitcoin-s/docs/rpc/bitcoind.md
rorp 7e19a706de Make tests to not require pre-installed bitcoind (#766)
* Make tests to not require pre-installed bitcoind

* update docs
2019-10-01 06:19:11 -05:00

3.9 KiB

id title
rpc-bitcoind bitcoind/Bitcoin Core

Note: bitcoin-s-bitcoind-rpc requires you to have bitcoind (Bitcoin Core daemon) installed. Grab this at bitcoincore.org

The Bitcoin Core RPC client in Bitcoin-S currently supports the Bitcoin Core 0.16 and 0.17 version lines. It can be set up to work with both local and remote Bitcoin Core servers.

Connecting to a local bitcoind instance

Getting started quickly, with default options:

import scala.concurrent._

import org.bitcoins.{rpc, core}
import core.currency.Bitcoins
import rpc.client.common._
import java.io._

implicit val ec: ExecutionContext = ExecutionContext.global

// this reads authentication credentials and
// connection details from the default data
// directory on your platform
val client = BitcoindRpcClient.fromDatadir(binary=new File("/path/to/bitcoind"), datadir=new File("/path/to/bitcoind-datadir"))

val balance: Future[Bitcoins] = for {
  _ <- client.start()
  balance <- client.getBalance
} yield balance

Connecting to a remote bitcoind

First, we create a secure connection to our bitcoind instance by setting up a SSH tunnel:

$ ssh -L 8332:localhost:8332  \
         my-cool-user@my-cool-website.com

Note: the port number '8332' is the default for mainnet. If you want to connect to a testnet bitcoind, the default port is '18332'

Now that we have a secure connection between our remote bitcoind, we're ready to create the connection with our RPC client

import java.net.URI
import scala.concurrent._

import org.bitcoins.core.config._
import org.bitcoins.rpc.config._
import org.bitcoins.rpc.client.common._

val username = "FILL_ME_IN" //this username comes from 'rpcuser' in your bitcoin.conf file
val password = "FILL_ME_IN" //this password comes from your 'rpcpassword' in your bitcoin.conf file

val authCredentials = BitcoindAuthCredentials.PasswordBased(
  username = username,
  password = password
)

val bitcoindInstance = {
  BitcoindInstance (
    network = MainNet,
    uri = new URI(s"http://localhost:${MainNet.port}"),
    rpcUri = new URI(s"http://localhost:${MainNet.rpcPort}"),
    authCredentials = authCredentials
  )
}

implicit val ec: ExecutionContext = ExecutionContext.global

val rpcCli = BitcoindRpcClient(bitcoindInstance)

rpcCli.getBalance.onComplete { case balance =>
  println(s"Wallet balance=${balance}")
}

Error handling

All errors returned by Bitcoin Core are mapped to a corresponding BitcoindException. These exceptions contain an error code and a message. BitcoindException is a sealed trait, which means you can easily pattern match exhaustively. Of course, other errors could also happen: network errors, stack overflows or out-of-memory errors. The provided class is only intended to cover errors returned by Bitcoin Core. An example of how error handling could look:

import org.bitcoins.rpc.client.common._
import org.bitcoins.rpc.BitcoindWalletException
import org.bitcoins.core.crypto._
import org.bitcoins.core.protocol._
import org.bitcoins.core.currency._
import java.io._

import scala.concurrent._

implicit val ec = ExecutionContext.global

// let's assume you have an already running client,
// so there's no need to start this one
val cli = BitcoindRpcClient.fromDatadir(binary=new File("/path/to/bitcoind"), datadir=new File("/path/to/bitcoind-datadir"))

// let's also assume you have a bitcoin address
val address: BitcoinAddress = ???

val txid: Future[DoubleSha256DigestBE] =
  cli.sendToAddress(address, 3.bitcoins).recoverWith {
    case BitcoindWalletException.UnlockNeeded(_) =>
      cli.walletPassphrase("my_passphrase", 60).flatMap { _ =>
        cli.sendToAddress(address, 3.bitcoins)
      }
  }