mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 21:34:39 +01:00
Add missing website docs (#3379)
This commit is contained in:
parent
79175cc097
commit
895eb88e93
270
website/versioned_docs/version-1.7.0/applications/server.md
Normal file
270
website/versioned_docs/version-1.7.0/applications/server.md
Normal file
@ -0,0 +1,270 @@
|
||||
---
|
||||
id: version-1.7.0-server
|
||||
title: Application Server
|
||||
original_id: server
|
||||
---
|
||||
|
||||
|
||||
## App server
|
||||
|
||||
The server project is the aggregation of these three sub projects
|
||||
|
||||
1. [Wallet](../wallet/wallet.md)
|
||||
2. [Chain](../chain/chain.md)
|
||||
3. [Node](../node/node.md)
|
||||
|
||||
The server project provides a away to access information from these three projects via a JSON RPC.
|
||||
|
||||
## Building the server
|
||||
|
||||
### Java binary
|
||||
You can build the server with the [sbt native packager](https://github.com/sbt/sbt-native-packager).
|
||||
The native packager offers [numerous ways to package the project](https://github.com/sbt/sbt-native-packager#examples).
|
||||
|
||||
In this example we are going to use `stage` which will produce bash scripts we can easily execute. You can stage the server with the following command.
|
||||
|
||||
```bash
|
||||
sbt appServer/universal:stage
|
||||
```
|
||||
|
||||
This will produce a script to execute bitcoin-s which you can start with
|
||||
|
||||
```bash
|
||||
./app/server/target/universal/stage/bin/bitcoin-s-server
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
The oracle server also has docker support. You can build a docker image with the following commands
|
||||
|
||||
#### Using an existing docker image
|
||||
|
||||
We publish docker images on every PR that is merged to bitcoin-s.
|
||||
|
||||
You can find the docker repo for the app server [here](https://hub.docker.com/r/bitcoinscala/bitcoin-s-server/tags?page=1&ordering=last_updated)
|
||||
|
||||
#### Building a docker image
|
||||
```
|
||||
sbt "appServer/docker:stage"
|
||||
```
|
||||
|
||||
This will build a `Dockerfile` that is located in `app/server/target/docker/stage`
|
||||
|
||||
You can now build the docker image with
|
||||
|
||||
```
|
||||
docker build app/server/target/docker/stage/ -t bitcoin-s-server:latest
|
||||
```
|
||||
|
||||
Finally, let's run the image! It's important that you correctly configure port forwarding with the docker container so
|
||||
you can interact with the running container with `bitcoin-s-cli` or `curl`. By default, our oracle
|
||||
server listens for requests on port `9999`.
|
||||
|
||||
This means we need to forward requests on the host machine to the docker container correctly.
|
||||
|
||||
This can be done with the following command
|
||||
```
|
||||
docker run -d -p 9999:9999 bitcoin-s-server:latest:latest
|
||||
```
|
||||
|
||||
Now you can send requests with `bitcoin-s-cli` or `curl`.
|
||||
Here is an example with `bitcoin-s-cli`
|
||||
```
|
||||
./bitcoin-s-cli getblockcount
|
||||
10000
|
||||
```
|
||||
|
||||
For more information on build configuration options with `sbt` please see the [sbt native packager docs](https://sbt-native-packager.readthedocs.io/en/latest/formats/docker.html#tasks)
|
||||
|
||||
## Configuration
|
||||
|
||||
### Java binary configuration
|
||||
If you would like to pass in a custom datadir for your server, you can do
|
||||
|
||||
```bash
|
||||
./app/server/target/universal/stage/bin/bitcoin-s-server --datadir /path/to/datadir/
|
||||
```
|
||||
|
||||
To use a config file that is not the `bitcoin-s.conf` file in your datadir, you can do
|
||||
|
||||
```bash
|
||||
./app/server/target/universal/stage/bin/bitcoin-s-server --conf /path/to/file.conf
|
||||
```
|
||||
|
||||
You can also pass in a custom `rpcport` to bind to
|
||||
|
||||
```bash
|
||||
./app/server/target/universal/stage/bin/bitcoin-s-server --rpcport 12345
|
||||
```
|
||||
|
||||
For more information on configuring the server please see our [configuration](../config/configuration.md) document
|
||||
|
||||
For more information on how to use our built in `cli` to interact with the server please see [cli.md](cli.md)
|
||||
|
||||
### Docker configuration
|
||||
|
||||
In this example, we are using the latest docker image published to our [docker hub](https://hub.docker.com/repository/docker/bitcoinscala/bitcoin-s-oracle-server/tags?page=1&ordering=last_updated)
|
||||
which is referenced by `bitcoinscala/bitcoin-s-server:latest`
|
||||
|
||||
You can use bitcoin-s with docker volumes. You can also pass in a custom configuration at container runtime.
|
||||
|
||||
#### Using a docker volume
|
||||
|
||||
```basrc
|
||||
docker volume create bitcoin-s
|
||||
docker run -p 9999:9999 \
|
||||
--mount source=bitcoin-s,target=/home/bitcoin-s/ bitcoinscala/bitcoin-s-server:latest
|
||||
```
|
||||
|
||||
Now you can re-use this volume across container runs. It will keep the same oracle database
|
||||
and seeds directory located at `/home/bitcoin-s/.bitcoin-s/seeds` in the volume.
|
||||
|
||||
#### Using a custom bitcoin-s configuration with docker
|
||||
|
||||
You can also specify a custom bitcoin-s configuration at container runtime.
|
||||
You can mount the configuration file on the docker container and that
|
||||
configuration will be used in the docker container runtime rather than
|
||||
the default one we provide [here](https://github.com/bitcoin-s/bitcoin-s/blob/master/app/oracle-server/src/universal/docker-application.conf)
|
||||
|
||||
You can do this with the following command
|
||||
|
||||
```bashrc
|
||||
docker run -p 9999:9999 \
|
||||
--mount type=bind,source=/my/new/config/,target=/home/bitcoin-s/.bitcoin-s/ \
|
||||
bitcoinscala/bitcoin-s-server:latest --conf /home/bitcoin-s/.bitcoin-s/bitcoin-s.conf
|
||||
```
|
||||
|
||||
Note: If you adjust the `bitcoin-s.server.rpcport` setting you will need to adjust
|
||||
the `-p 9999:9999` port mapping on the docker container to adjust for this.
|
||||
|
||||
## Server Endpoints
|
||||
|
||||
### Blockchain
|
||||
|
||||
- `getblockcount` - Get the current block height
|
||||
- `getfiltercount` - Get the number of filters
|
||||
- `getfilterheadercount` - Get the number of filter headers
|
||||
- `getbestblockhash` - Get the best block hash
|
||||
- `getblockheader` - Returns information about block header <hash>
|
||||
- `hash` - The block hash
|
||||
- `decoderawtransaction` `tx` - `Decode the given raw hex transaction`
|
||||
- `tx` - Transaction encoded in hex to decode
|
||||
|
||||
### Wallet
|
||||
- `rescan` `[options]` - Rescan for wallet UTXOs
|
||||
- `--force` - Clears existing wallet records. Warning! Use with caution!
|
||||
- `--batch-size <value>` - Number of filters that can be matched in one batch
|
||||
- `--start <value>` - Start height
|
||||
- `--end <value>` - End height
|
||||
- `--ignorecreationtime` - Ignores the wallet creation date and will instead do a full rescan
|
||||
- `isempty` - Checks if the wallet contains any data
|
||||
- `walletinfo` - Returns data about the current wallet being used
|
||||
- `getbalance` `[options]` - Get the wallet balance
|
||||
- `--sats ` - Display balance in satoshis
|
||||
- `getconfirmedbalance` `[options]` - Get the wallet balance of confirmed utxos
|
||||
- `--sats ` - Display balance in satoshis
|
||||
- `getunconfirmedbalance` `[options]` - Get the wallet balance of unconfirmed utxos
|
||||
- `--sats ` - Display balance in satoshis
|
||||
- `getbalances` `[options]` - Get the wallet balance by utxo state
|
||||
- `--sats ` - Display balance in satoshis
|
||||
- `getutxos` - Returns list of all wallet utxos
|
||||
- `getaddresses` - Returns list of all wallet addresses currently being watched
|
||||
- `getspentaddresses` - Returns list of all wallet addresses that have received funds and been spent
|
||||
- `getfundedaddresses` - Returns list of all wallet addresses that are holding funds
|
||||
- `getunusedaddresses` - Returns list of all wallet addresses that have not been used
|
||||
- `getaccounts` - Returns list of all wallet accounts
|
||||
- `walletinfo` - Returns meta information about the wallet
|
||||
- `createnewaccount` - Creates a new wallet account
|
||||
- `getaddressinfo` `address` - Returns list of all wallet accounts
|
||||
- `address` - Address to get information about
|
||||
- `getnewaddress` - Get a new address
|
||||
- `listreservedutxos` - lists all utxos that are reserved in the wallet
|
||||
- `sendtoaddress` `address` `amount` `[options]` - Send money to the given address
|
||||
- `address` - Address to send to
|
||||
- `amount` - Amount to send in BTC
|
||||
- `--feerate <value>` - Fee rate in sats per virtual byte
|
||||
- `sendfromoutpoints` `outpoints` `address` `amount` `[options]` - Send money to the given address
|
||||
- `outpoints` - Out Points to send from
|
||||
- `address` - Address to send to
|
||||
- `amount` - Amount to send in BTC
|
||||
- `--feerate <value>` - Fee rate in sats per virtual byte
|
||||
- `sweepwallet` `address` `[options]` - Sends the entire wallet balance to the given address
|
||||
- `address` - Address to send to
|
||||
- `--feerate <value>` - Fee rate in sats per virtual byte
|
||||
- `sendwithalgo` `address` `amount` `algo` `[options]` - Send money to the given address using a specific coin selection algo
|
||||
- `address` - Address to send to
|
||||
- `amount` - Amount to send in BTC
|
||||
- `algo` - Coin selection algo
|
||||
- `--feerate <value>` - Fee rate in sats per virtual byte
|
||||
- `signpsbt` `psbt` - Signs the PSBT's inputs with keys that are associated with the wallet
|
||||
- `psbt` - PSBT to sign
|
||||
- `opreturncommit` `message` `[options]` - Creates OP_RETURN commitment transaction
|
||||
- `message` - message to put into OP_RETURN commitment
|
||||
- `--hashMessage` - should the message be hashed before commitment
|
||||
- `--feerate <value>` - Fee rate in sats per virtual byte
|
||||
- `bumpfeecpfp` `txid` `feerate` - Bump the fee of the given transaction id with a child tx using the given fee rate
|
||||
- `txid` - Id of transaction to bump fee
|
||||
- `feerate` - Fee rate in sats per virtual byte of the child transaction
|
||||
- `bumpfeerbf` `txid` `feerate` - Replace given transaction with one with the new fee rate
|
||||
- `txid` - Id of transaction to bump fee
|
||||
- `feerate` - New fee rate in sats per virtual byte
|
||||
- `gettransaction` `txid` - Get detailed information about in-wallet transaction <txid>
|
||||
- `txid` - The transaction id
|
||||
- `lockunspent` `unlock` `transactions` - Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.
|
||||
- `unlock` - Whether to unlock (true) or lock (false) the specified transactions
|
||||
- `transactions` - The transaction outpoints to unlock/lock, empty to apply to all utxos
|
||||
- `importseed` `walletname` `words` `passphrase` - Imports a mnemonic seed as a new seed file
|
||||
- `walletname` - Name to associate with this seed
|
||||
- `words` - Mnemonic seed words, space separated
|
||||
- `passphrase` - Passphrase to encrypt this seed with
|
||||
- `importxprv` `walletname` `xprv` `passphrase` - Imports a mnemonic seed as a new seed file
|
||||
- `walletname` - Name to associate with this seed
|
||||
- `xprv` - base58 encoded extended private key
|
||||
- `passphrase` - Passphrase to encrypt this seed with
|
||||
- `keymanagerpassphrasechange` `oldpassphrase` `newpassphrase` - Changes the wallet passphrase
|
||||
- `oldpassphrase` - The current passphrase
|
||||
- `newpassphrase` - The new passphrase
|
||||
- `keymanagerpassphraseset` `passphrase` - Encrypts the wallet with the given passphrase
|
||||
- `passphrase` - The passphrase to encrypt the wallet with
|
||||
|
||||
### Network
|
||||
- `getpeers` - List the connected peers
|
||||
- `stop` - Request a graceful shutdown of Bitcoin-S
|
||||
- `sendrawtransaction` `tx` `Broadcasts the raw transaction`
|
||||
- `tx` - Transaction serialized in hex
|
||||
|
||||
### PSBT
|
||||
- `decodepsbt` `psbt` - Return a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.
|
||||
- `psbt` - PSBT serialized in hex or base64 format
|
||||
- `combinepsbts` `psbts` - Combines all the given PSBTs
|
||||
- `psbts` - PSBTs serialized in hex or base64 format
|
||||
- `joinpsbts` `psbts` - Combines all the given PSBTs
|
||||
- `psbts` - PSBTs serialized in hex or base64 format
|
||||
- `finalizepsbt` `psbt` - Finalizes the given PSBT if it can
|
||||
- `psbt` - PSBT serialized in hex or base64 format
|
||||
- `extractfrompsbt` `psbt` - Extracts a transaction from the given PSBT if it can
|
||||
- `psbt` - PSBT serialized in hex or base64 format
|
||||
- `converttopsbt` `unsignedTx` - Creates an empty psbt from the given transaction
|
||||
- `unsignedTx` - serialized unsigned transaction in hex
|
||||
|
||||
### Util
|
||||
- `createmultisig` `nrequired` `keys` `[address_type]` - Creates a multi-signature address with n signature of m keys required.
|
||||
- `nrequired` - The number of required signatures out of the n keys.
|
||||
- `keys` - The hex-encoded public keys.
|
||||
- `address_type` -The address type to use. Options are "legacy", "p2sh-segwit", and "bech32"
|
||||
- `estimatefee` - Returns the recommended fee rate using the fee provider
|
||||
|
||||
## Sign PSBT with Wallet Example
|
||||
|
||||
Bitcoin-S CLI:
|
||||
|
||||
```bash
|
||||
$ bitcoin-s-cli signpsbt cHNidP8BAP0FAQIAAAABWUWxYiPKgdGfXcIxJ6MRDxEpUecw59Gk4NpROI5oukoBAAAAAAAAAAAEPttkvdwAAAAXqRSOVAp6Qe/u2hq74e/ThB8foBKn7IfZYMgGCAAAAADbmaQ2nwAAAEdRIQLpfVqyaL9Jb/IkveatNyVeONE8Q/6TzXAWosxLo9e21SECc5G3XiK7xKLlkBG7prMx7p0fMeQwMH5e9H10mBon39JSrtgtgjjLAQAAUGMhAn2YaZnv25I6d6vbb1kw6Xp5IToDrEzl/0VBIW21gHrTZwXg5jGdALJ1IQKyNpDNiOiN6lWpYethib04+XC9bpFXrdpec+xO3U5IM2is9ckf5AABAD0CAAAAAALuiOL0rRcAABYAFPnpLByQq1Gg3vwiP6qR8FmOOjwxvVllM08DAAALBfXJH+QAsXUAAK4AAAAAAQcBAAAAAAAA
|
||||
cHNidP8BAP0FAQIAAAABWUWxYiPKgdGfXcIxJ6MRDxEpUecw59Gk4NpROI5oukoBAAAAAAAAAAAEPttkvdwAAAAXqRSOVAp6Qe/u2hq74e/ThB8foBKn7IfZYMgGCAAAAADbmaQ2nwAAAEdRIQLpfVqyaL9Jb/IkveatNyVeONE8Q/6TzXAWosxLo9e21SECc5G3XiK7xKLlkBG7prMx7p0fMeQwMH5e9H10mBon39JSrtgtgjjLAQAAUGMhAn2YaZnv25I6d6vbb1kw6Xp5IToDrEzl/0VBIW21gHrTZwXg5jGdALJ1IQKyNpDNiOiN6lWpYethib04+XC9bpFXrdpec+xO3U5IM2is9ckf5AABAD0CAAAAAALuiOL0rRcAABYAFPnpLByQq1Gg3vwiP6qR8FmOOjwxvVllM08DAAALBfXJH+QAsXUAAK4AAAAAAQcBAAAAAAAA
|
||||
```
|
||||
|
||||
CURL:
|
||||
```bash
|
||||
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "signpsbt", "params": ["cHNidP8BAP0FAQIAAAABWUWxYiPKgdGfXcIxJ6MRDxEpUecw59Gk4NpROI5oukoBAAAAAAAAAAAEPttkvdwAAAAXqRSOVAp6Qe/u2hq74e/ThB8foBKn7IfZYMgGCAAAAADbmaQ2nwAAAEdRIQLpfVqyaL9Jb/IkveatNyVeONE8Q/6TzXAWosxLo9e21SECc5G3XiK7xKLlkBG7prMx7p0fMeQwMH5e9H10mBon39JSrtgtgjjLAQAAUGMhAn2YaZnv25I6d6vbb1kw6Xp5IToDrEzl/0VBIW21gHrTZwXg5jGdALJ1IQKyNpDNiOiN6lWpYethib04+XC9bpFXrdpec+xO3U5IM2is9ckf5AABAD0CAAAAAALuiOL0rRcAABYAFPnpLByQq1Gg3vwiP6qR8FmOOjwxvVllM08DAAALBfXJH+QAsXUAAK4AAAAAAQcBAAAAAAAA"]}' -H "Content-Type: application/json" http://127.0.0.1:9999/
|
||||
{"result":"cHNidP8BAP0FAQIAAAABWUWxYiPKgdGfXcIxJ6MRDxEpUecw59Gk4NpROI5oukoBAAAAAAAAAAAEPttkvdwAAAAXqRSOVAp6Qe/u2hq74e/ThB8foBKn7IfZYMgGCAAAAADbmaQ2nwAAAEdRIQLpfVqyaL9Jb/IkveatNyVeONE8Q/6TzXAWosxLo9e21SECc5G3XiK7xKLlkBG7prMx7p0fMeQwMH5e9H10mBon39JSrtgtgjjLAQAAUGMhAn2YaZnv25I6d6vbb1kw6Xp5IToDrEzl/0VBIW21gHrTZwXg5jGdALJ1IQKyNpDNiOiN6lWpYethib04+XC9bpFXrdpec+xO3U5IM2is9ckf5AABAD0CAAAAAALuiOL0rRcAABYAFPnpLByQq1Gg3vwiP6qR8FmOOjwxvVllM08DAAALBfXJH+QAsXUAAK4AAAAAAQcBAAAAAAAA","error":null}
|
||||
```
|
181
website/versioned_docs/version-1.7.0/chain/chain-query-api.md
Normal file
181
website/versioned_docs/version-1.7.0/chain/chain-query-api.md
Normal file
@ -0,0 +1,181 @@
|
||||
---
|
||||
id: version-1.7.0-chain-query-api
|
||||
title: Chain Query API
|
||||
original_id: chain-query-api
|
||||
---
|
||||
|
||||
|
||||
### ChainQueryAPI
|
||||
|
||||
The ChainQueryApi is how the wallet project stays aware of the current best chain.
|
||||
This allows the wallet for example to calculate the number of confirmations for a transaction,
|
||||
get the current chain tip, or even retrieve block filters for a given set of blocks.
|
||||
|
||||
Since this is an API it can be hooked up to the `chain` 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 ChainQueryApi supports are:
|
||||
|
||||
```scala
|
||||
trait ChainQueryApi {
|
||||
|
||||
/** Gets the height of the given block */
|
||||
def getBlockHeight(blockHash: DoubleSha256DigestBE): Future[Option[Int]]
|
||||
|
||||
/** Gets the hash of the block that is what we consider "best" */
|
||||
def getBestBlockHash(): Future[DoubleSha256DigestBE]
|
||||
|
||||
/** Gets number of confirmations for the given block hash*/
|
||||
def getNumberOfConfirmations(
|
||||
blockHashOpt: DoubleSha256DigestBE): Future[Option[Int]]
|
||||
|
||||
/** Gets the number of compact filters in the database */
|
||||
def getFilterCount: Future[Int]
|
||||
|
||||
/** Returns the block height of the given block stamp */
|
||||
def getHeightByBlockStamp(blockStamp: BlockStamp): Future[Int]
|
||||
|
||||
def getFiltersBetweenHeights(
|
||||
startHeight: Int,
|
||||
endHeight: Int): Future[Vector[FilterResponse]]
|
||||
}
|
||||
```
|
||||
|
||||
## Chain query with bitcoind
|
||||
|
||||
As an example, we will show you how to use the `ChainQueryApi` and bitcoind to query chain data.
|
||||
|
||||
```scala
|
||||
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 nodeApi = BitcoinSWalletTest.MockNodeApi
|
||||
|
||||
// Create our key manager
|
||||
val keyManagerE = BIP39KeyManager.initialize(aesPasswordOpt = Some(AesPassword.fromString("password")),
|
||||
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 chain api receives a transaction, block, or
|
||||
// a block filter, the returned NodeCallbacks will contain the necessary items to initialize the callbacks
|
||||
def createCallbacks(
|
||||
processTransaction: Transaction => Future[Unit],
|
||||
processCompactFilters: (Vector[(DoubleSha256Digest, GolombFilter)]) => Future[Unit],
|
||||
processBlock: Block => Future[Unit]): NodeCallbacks = {
|
||||
lazy val onTx: OnTxReceived = { tx =>
|
||||
processTransaction(tx)
|
||||
}
|
||||
lazy val onCompactFilters: OnCompactFiltersReceived = {
|
||||
blockFilters =>
|
||||
processCompactFilters(blockFilters)
|
||||
}
|
||||
lazy val onBlock: OnBlockReceived = { block =>
|
||||
processBlock(block)
|
||||
}
|
||||
NodeCallbacks(onTxReceived = Vector(onTx),
|
||||
onBlockReceived = Vector(onBlock),
|
||||
onCompactFiltersReceived = Vector(onCompactFilters))
|
||||
}
|
||||
|
||||
// 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 exampleProcessTx = (tx: Transaction) =>
|
||||
Future.successful(println(s"Received tx: ${tx.txIdBE}"))
|
||||
|
||||
val exampleProcessBlock = (block: Block) =>
|
||||
Future.successful(println(s"Received block: ${block.blockHeader.hashBE}"))
|
||||
|
||||
val exampleProcessFilters =
|
||||
(filters: Vector[(DoubleSha256Digest, GolombFilter)]) =>
|
||||
Future.successful(println(s"Received filter: ${filters.head._1.flip.hex} ${filters.head._2.hash.flip.hex}"))
|
||||
|
||||
val exampleCallbacks =
|
||||
createCallbacks(exampleProcessTx, exampleProcessFilters, exampleProcessBlock)
|
||||
|
||||
// Here is where we are defining our actual chain api, Ideally this could be it's own class
|
||||
// but for the examples sake we will keep it small.
|
||||
val chainApi = new ChainQueryApi {
|
||||
|
||||
override def epochSecondToBlockHeight(time: Long): Future[Int] =
|
||||
Future.successful(0)
|
||||
|
||||
/** Gets the height of the given block */
|
||||
override def getBlockHeight(
|
||||
blockHash: DoubleSha256DigestBE): Future[Option[Int]] = {
|
||||
bitcoind.getBlock(blockHash).map(block => Some(block.height))
|
||||
}
|
||||
|
||||
/** Gets the hash of the block that is what we consider "best" */
|
||||
override def getBestBlockHash(): Future[DoubleSha256DigestBE] = {
|
||||
bitcoind.getBestBlockHash
|
||||
}
|
||||
|
||||
/** Gets number of confirmations for the given block hash */
|
||||
override def getNumberOfConfirmations(
|
||||
blockHash: DoubleSha256DigestBE): Future[Option[Int]] = {
|
||||
for {
|
||||
tip <- bitcoind.getBlockCount
|
||||
block <- bitcoind.getBlock(blockHash)
|
||||
} yield {
|
||||
Some(tip - block.height + 1)
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the number of compact filters in the database */
|
||||
override def getFilterCount(): Future[Int] = {
|
||||
// since bitcoind should have the filter for
|
||||
// every block we can just return the block height
|
||||
bitcoind.getBlockCount
|
||||
}
|
||||
|
||||
/** Returns the block height of the given block stamp */
|
||||
override def getHeightByBlockStamp(blockStamp: BlockStamp): Future[Int] = {
|
||||
blockStamp match {
|
||||
case blockHeight: BlockStamp.BlockHeight =>
|
||||
Future.successful(blockHeight.height)
|
||||
case blockHash: BlockStamp.BlockHash =>
|
||||
getBlockHeight(blockHash.hash).map(_.get)
|
||||
case blockTime: BlockStamp.BlockTime =>
|
||||
Future.failed(new RuntimeException(s"Not implemented: $blockTime"))
|
||||
}
|
||||
}
|
||||
|
||||
override def getFiltersBetweenHeights(
|
||||
startHeight: Int,
|
||||
endHeight: Int): Future[Vector[FilterResponse]] = {
|
||||
val filterFs = startHeight
|
||||
.until(endHeight)
|
||||
.map { height =>
|
||||
for {
|
||||
hash <- bitcoind.getBlockHash(height)
|
||||
filter <- bitcoind.getBlockFilter(hash, FilterType.Basic)
|
||||
} yield {
|
||||
FilterResponse(filter.filter, hash, height)
|
||||
}
|
||||
}
|
||||
.toVector
|
||||
|
||||
Future.sequence(filterFs)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 one of the events we can run
|
||||
wallet.chainQueryApi.getFiltersBetweenHeights(100, 150)
|
||||
```
|
399
website/versioned_docs/version-1.7.0/config/configuration.md
Normal file
399
website/versioned_docs/version-1.7.0/config/configuration.md
Normal file
@ -0,0 +1,399 @@
|
||||
---
|
||||
title: Application Configuration
|
||||
id: version-1.7.0-configuration
|
||||
original_id: configuration
|
||||
---
|
||||
|
||||
Bitcoin-S uses [HOCON](https://github.com/lightbend/config/blob/master/HOCON.md)
|
||||
to configure various parts of the application the library offers. HOCON is a superset of JSON, that is, all valid JSON
|
||||
is valid HOCON.
|
||||
|
||||
All configuration for Bitcoin-S is under the `bitcoin-s` key.
|
||||
|
||||
If you have a file `application.conf` anywhere on your classpath when using bitcoin-s, the values there take precedence
|
||||
over the ones found in our
|
||||
`reference.conf`. We also look for the file `bitcoin-s.conf` in the current Bitcoin-S data directory.
|
||||
|
||||
The resolved configuration gets parsed by
|
||||
[`AppConfig`](/api/org/bitcoins/db/AppConfig).
|
||||
`AppConfig` is an abstract class that's implemented by corresponding case classes in the `wallet`, `chain` and `node`
|
||||
projects. Here's some examples of how to construct a wallet configuration:
|
||||
|
||||
```scala
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import java.nio.file.Paths
|
||||
import scala.util.Properties
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
// reads $HOME/.bitcoin-s/
|
||||
val defaultConfig = WalletAppConfig.fromDefaultDatadir()
|
||||
|
||||
|
||||
// reads a custom data directory
|
||||
val customDirectory = Paths.get(Properties.userHome, "custom-bitcoin-s-directory")
|
||||
val configFromCustomDatadir = WalletAppConfig(customDirectory)
|
||||
|
||||
// reads a custom data directory and overrides the network to be testnet3
|
||||
val customOverride = ConfigFactory.parseString("bitcoin-s.network = testnet3")
|
||||
val configFromCustomDirAndOverride = WalletAppConfig(customDirectory, customOverride)
|
||||
```
|
||||
|
||||
You can pass as many `com.typesafe.config.Config`s as you'd like. If any keys appear multiple times the last one
|
||||
encountered takes precedence.
|
||||
|
||||
## Command Line Options
|
||||
|
||||
There are a few command line options available that take precedence over configuration file.
|
||||
|
||||
- `--datadir <directory>`
|
||||
|
||||
`datadir` sets the data directory instead of using the default `$HOME/.bitcoin-s`
|
||||
|
||||
- `--rpcbind <ip>`
|
||||
|
||||
`rpcbind` sets the interface the rpc server binds to instead of using the default `127.0.0.1`
|
||||
|
||||
- `--rpcport <port>`
|
||||
|
||||
`rpcport` sets the port the rpc server binds to instead of using the default `9999`
|
||||
|
||||
- `--force-recalc-chainwork`
|
||||
|
||||
`force-recalc-chainwork` will force a recalculation of the entire chain's chain work, this can be useful if there is
|
||||
an incompatible migration or if it got out of sync.
|
||||
|
||||
- `-Dlogback.configurationFile=/path/to/config.xml`
|
||||
|
||||
You can set a custom logback configuration. If you need help creating a custom logback file you can
|
||||
read [the logback configuration documentation](http://logback.qos.ch/manual/configuration.html).
|
||||
|
||||
## Internal configuration
|
||||
|
||||
Database connections are also configured by using HOCON. This is done
|
||||
in [`reference.conf`](https://github.com/bitcoin-s/bitcoin-s/blob/master/db-commons/src/main/resources/reference.conf)
|
||||
inside the `db-commons` module. The options exposed here are **not** intended to be used by users of Bitcoin-S, and are
|
||||
internal only.
|
||||
|
||||
## Database Migrations
|
||||
|
||||
All of our modules that require databases now have database migrations. The tool we use for these migrations is
|
||||
called [flyway](https://flywaydb.org/). To find your projects migraitons, you need to look inside of the
|
||||
`[project-name]/src/main/resources/[database-name]/migration/`. For example, the chain projects migrations live under
|
||||
the path `chain/src/main/resources/chaindb/migration/V1__chain_db_baseline.sql`.
|
||||
|
||||
Migrations can be executed by calling
|
||||
the [`DbManagement.migrate()`](https://github.com/bitcoin-s/bitcoin-s/blob/e387d075b0ff2e0a0fec15788fcb48e4ddc4d9d5/db-commons/src/main/scala/org/bitcoins/db/DbManagement.scala#L92)
|
||||
method. Migrations are applied by default on server startup, via
|
||||
the [`AppConfig.start()`](https://github.com/bitcoin-s/bitcoin-s/blob/master/db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala#L49)
|
||||
method.
|
||||
|
||||
These migrations are setup so that project's databases and migrations are independent of each other. Therefore if you
|
||||
want to use the `bitcoin-s-chain` project, but not the `bitcoin-s-wallet` project, wallet migrations are not applied. It
|
||||
should be noted if you are using a module as a library, you are responsible for configuring the database via
|
||||
[slick's configuration](https://scala-slick.org/doc/3.3.1/database.html#using-typesafe-config) and calling
|
||||
[`AppConfig.start()`](https://github.com/bitcoin-s/bitcoin-s/blob/master/db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala#L49)
|
||||
to ensure the entire module is initialized correctly.
|
||||
|
||||
## Example Configuration File
|
||||
|
||||
```$xslt
|
||||
bitcoin-s {
|
||||
datadir = ${HOME}/.bitcoin-s
|
||||
network = regtest # regtest, testnet3, mainnet, signet
|
||||
dbDefault = {
|
||||
dataSourceClass = slick.jdbc.DatabaseUrlDataSource
|
||||
profile = "slick.jdbc.SQLiteProfile$"
|
||||
|
||||
db {
|
||||
# for information on parameters available here see
|
||||
# https://scala-slick.org/doc/3.3.1/api/index.html#slick.jdbc.JdbcBackend$DatabaseFactoryDef@forConfig(String,Config,Driver,ClassLoader):Database
|
||||
path = ${bitcoin-s.datadir}/${bitcoin-s.network}/
|
||||
driver = org.sqlite.JDBC
|
||||
user = ""
|
||||
password = ""
|
||||
host = localhost
|
||||
port = 5432
|
||||
|
||||
# this needs to be set to 1 for SQLITE as it does not support concurrent database operations
|
||||
# see: https://github.com/bitcoin-s/bitcoin-s/pull/1840
|
||||
numThreads = 1
|
||||
queueSize=5000
|
||||
connectionPool = "HikariCP"
|
||||
registerMbeans = true
|
||||
}
|
||||
hikari-logging = false
|
||||
hikari-logging-interval = 10 minute
|
||||
}
|
||||
|
||||
bitcoind-rpc {
|
||||
# bitcoind rpc username
|
||||
rpcuser = user
|
||||
# bitcoind rpc password
|
||||
rpcpassword = password
|
||||
|
||||
# Binary location of bitcoind
|
||||
binary = ${HOME}/.bitcoin-s/binaries/bitcoind/bitcoin-0.20.1/bin/bitcoind
|
||||
# bitcoind datadir
|
||||
datadir = ${HOME}/.bitcoin
|
||||
# bitcoind network binding
|
||||
bind = localhost
|
||||
# bitcoind p2p port
|
||||
port = 8333
|
||||
# bitcoind rpc binding
|
||||
rpcbind = localhost
|
||||
# bitcoind rpc port
|
||||
rpcport = 8332
|
||||
# bitcoind zmq raw tx
|
||||
zmqpubrawtx = "tcp://127.0.0.1:28332"
|
||||
# bitcoind zmq raw block
|
||||
zmqpubrawblock = "tcp://127.0.0.1:28333"
|
||||
# bitcoind zmq hash tx
|
||||
zmqpubhashtx = "tcp://127.0.0.1:28330"
|
||||
# bitcoind zmq raw block
|
||||
zmqpubhashblock = "tcp://127.0.0.1:28331"
|
||||
}
|
||||
|
||||
node {
|
||||
mode = neutrino # neutrino, spv, bitcoind
|
||||
|
||||
peers = [] # a list of peer addresses in form "hostname:portnumber"
|
||||
# (e.g. "neutrino.testnet3.suredbits.com:18333")
|
||||
# Port number is optional, the default value is 8333 for mainnet,
|
||||
# 18333 for testnet and 18444 for regtest.
|
||||
|
||||
hikari-logging = true
|
||||
hikari-logging-interval = 10 minute
|
||||
}
|
||||
|
||||
chain {
|
||||
force-recalc-chainwork = false
|
||||
neutrino {
|
||||
filter-header-batch-size.default = 2000
|
||||
filter-header-batch-size.regtest = 10
|
||||
# You can set a network specific filter-header-batch-size
|
||||
# by adding a trailing `.networkId` (main, test, regtest)
|
||||
# It is recommended to keep the main and test batch size high
|
||||
# to keep the sync time fast, however, for regtest it should be small
|
||||
# so it does not exceed the chain size.
|
||||
|
||||
filter-batch-size = 1000
|
||||
}
|
||||
|
||||
hikari-logging = true
|
||||
hikari-logging-interval = 10 minute
|
||||
}
|
||||
|
||||
# settings for wallet module
|
||||
wallet {
|
||||
# You can have multiple wallets by setting a different
|
||||
# wallet name for each of them. They will each have
|
||||
# their own unique seed and database or schema,
|
||||
# depending on the database driver.
|
||||
# The wallet name can contain letters, numbers, and underscores '_'.
|
||||
# walletName = MyWallet0
|
||||
|
||||
defaultAccountType = segwit # legacy, segwit, nested-segwit
|
||||
|
||||
bloomFalsePositiveRate = 0.0001 # percentage
|
||||
|
||||
addressGapLimit = 20
|
||||
|
||||
discoveryBatchSize = 100
|
||||
|
||||
requiredConfirmations = 6
|
||||
|
||||
# How big the address queue size is before we throw an exception
|
||||
# because of an overflow
|
||||
addressQueueSize = 10
|
||||
|
||||
# How long we attempt to generate an address for
|
||||
# before we timeout
|
||||
addressQueueTimeout = 5 seconds
|
||||
|
||||
# How often the wallet will rebroadcast unconfirmed transactions
|
||||
rebroadcastFrequency = 4 hours
|
||||
|
||||
hikari-logging = true
|
||||
hikari-logging-interval = 10 minute
|
||||
}
|
||||
|
||||
keymanager {
|
||||
# You can optionally set a BIP 39 password
|
||||
# bip39password = "changeMe"
|
||||
|
||||
# Password that your seed is encrypted with
|
||||
aesPassword = changeMe
|
||||
}
|
||||
|
||||
# Bitcoin-S provides manny different fee providers
|
||||
# You can configure your server to use any of them
|
||||
# Below is some examples of different options
|
||||
fee-provider {
|
||||
# name = mempoolspace # Uses mempool.space's api
|
||||
# The target is optional for mempool.space
|
||||
# It refers to the expected number of blocks until confirmation
|
||||
# target = 6
|
||||
|
||||
# name = bitcoinerlive # Uses bitcoiner.live's api
|
||||
# The target is optional for Bitcoiner Live
|
||||
# It refers to the expected number of blocks until confirmation
|
||||
# target = 6
|
||||
|
||||
# name = bitgo # Uses BitGo's api
|
||||
# The target is optional for BitGo
|
||||
# It refers to the expected number of blocks until confirmation
|
||||
# target = 6
|
||||
|
||||
# name = constant # A constant fee rate in sats/vbyte
|
||||
# target = 1 # Will always use 1 sat/vbyte
|
||||
}
|
||||
|
||||
server {
|
||||
# The port we bind our rpc server on
|
||||
rpcport = 9999
|
||||
|
||||
# The ip address we bind our server too
|
||||
rpcbind = "127.0.0.1"
|
||||
}
|
||||
|
||||
oracle {
|
||||
# The port we bind our rpc server on
|
||||
rpcport = 9998
|
||||
|
||||
# The ip address we bind our server too
|
||||
rpcbind = "127.0.0.1"
|
||||
|
||||
hikari-logging = true
|
||||
hikari-logging-interval = 10 minute
|
||||
|
||||
db {
|
||||
path = ${bitcoin-s.datadir}/oracle/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
akka {
|
||||
loglevel = "OFF"
|
||||
stdout-loglevel = "OFF"
|
||||
http {
|
||||
client {
|
||||
# The time after which an idle connection will be automatically closed.
|
||||
# Set to `infinite` to completely disable idle connection timeouts.
|
||||
|
||||
# some requests potentially take a long time, like generate and prune
|
||||
idle-timeout = 5 minutes
|
||||
}
|
||||
|
||||
server {
|
||||
# The amount of time until a request times out on the server
|
||||
# If you have a large payload this may need to be bumped
|
||||
# https://doc.akka.io/docs/akka-http/current/common/timeouts.html#request-timeout
|
||||
request-timeout = 10s
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
actor {
|
||||
debug {
|
||||
# enable DEBUG logging of all AutoReceiveMessages (Kill, PoisonPill etc.)
|
||||
autoreceive= off
|
||||
# enable function of LoggingReceive, which is to log any received message at
|
||||
# DEBUG level
|
||||
receive = on
|
||||
# enable DEBUG logging of unhandled messages
|
||||
unhandled = off
|
||||
|
||||
# enable DEBUG logging of actor lifecycle changes
|
||||
lifecycle = off
|
||||
|
||||
event-stream=off
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Database configuration
|
||||
|
||||
By default, bitcoin-s uses Sqlite to store its data. It creates three Sqlite databases
|
||||
in `~/.bitcoin-s/${network}`: `chain.sqlite` for `chain` project,
|
||||
`node.sqlite` for `node` project and `wallet.sqlite` the wallet. This is the default configuration, it doesn't require
|
||||
additional changes in the config file.
|
||||
|
||||
`bitcoin-s` also supports PostgreSQL as a database backend. In order to use a PostgreSQL database for all project you
|
||||
need to add following into your config file:
|
||||
|
||||
```$xslt
|
||||
bitcoin-s {
|
||||
common {
|
||||
profile = "slick.jdbc.PostgresProfile$"
|
||||
db {
|
||||
driver = org.postgresql.Driver
|
||||
|
||||
# these 3 options will result into a jdbc url of
|
||||
# "jdbc:postgresql://localhost:5432/database"
|
||||
name = database
|
||||
host = localhost
|
||||
port = 5432
|
||||
|
||||
user = "user"
|
||||
password = "topsecret"
|
||||
numThreads = 5
|
||||
|
||||
# http://scala-slick.org/doc/3.3.3/database.html
|
||||
connectionPool = "HikariCP"
|
||||
registerMbeans = true
|
||||
}
|
||||
}
|
||||
|
||||
chain.profile = ${bitcoin-s.common.profile}
|
||||
chain.db = ${bitcoin-s.common.db}
|
||||
chain.db.poolName = "chain-connection-pool"
|
||||
|
||||
node.profile = ${bitcoin-s.common.profile}
|
||||
node.db = ${bitcoin-s.common.db}
|
||||
node.db.poolName = "node-connection-pool"
|
||||
|
||||
wallet.profile = ${bitcoin-s.common.profile}
|
||||
wallet.db = ${bitcoin-s.common.db}
|
||||
wallet.db.poolName = "wallet-connection-pool"
|
||||
|
||||
oracle.profile = ${bitcoin-s.common.profile}
|
||||
oracle.db = ${bitcoin-s.common.db}
|
||||
oracle.db.poolName = "oracle-connection-pool"
|
||||
}
|
||||
```
|
||||
|
||||
The database driver will create a separate SQL namespace for each sub-project: `chain`, `node` and `wallet`.
|
||||
|
||||
Also you can use mix databases and drivers in one configuration. For example, This configuration file enables Sqlite
|
||||
for `node` project (it's default, so its configuration is omitted), and `walletdb` and `chaindb` PostgreSQL databases
|
||||
for `wallet` and `chain` projects:
|
||||
|
||||
```$xslt
|
||||
bitcoin-s {
|
||||
chain {
|
||||
profile = "slick.jdbc.PostgresProfile$"
|
||||
db {
|
||||
driver = org.postgresql.Driver
|
||||
name = chaindb
|
||||
host = localhost
|
||||
port = 5432
|
||||
user = "user"
|
||||
password = "topsecret"
|
||||
}
|
||||
}
|
||||
wallet {
|
||||
profile = "slick.jdbc.PostgresProfile$"
|
||||
db {
|
||||
driver = org.postgresql.Driver
|
||||
name = walletdb
|
||||
host = localhost
|
||||
port = 5432
|
||||
user = "user"
|
||||
password = "topsecret"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
59
website/versioned_docs/version-1.7.0/core/addresses.md
Normal file
59
website/versioned_docs/version-1.7.0/core/addresses.md
Normal file
@ -0,0 +1,59 @@
|
||||
---
|
||||
id: version-1.7.0-addresses
|
||||
title: Generating Addresses
|
||||
original_id: addresses
|
||||
---
|
||||
|
||||
Almost all Bitcoin applications need to generate addresses
|
||||
for their users somehow. There's a lot going on in getting
|
||||
a correct bitcoin address, but our APIs make it possible to
|
||||
to get started with all types of addresses in a matter of
|
||||
minutes.
|
||||
|
||||
## Generating SegWit (bech32) addresses
|
||||
|
||||
Generating native SegWit addresses in the bech32 format
|
||||
is something that all Bitcoin applications should enable,
|
||||
as it makes the transaction fees less expensive, and also
|
||||
makes the addresses more readable by humans. However, it
|
||||
has seen slower than necessary adoption. With Bitcoin-S
|
||||
you can generate bech32 addresses in four(!) lines of code
|
||||
(not counting comments and imports), so now there's no
|
||||
reason to keep using legacy transaction formats.
|
||||
|
||||
|
||||
```scala
|
||||
// this generates a random private key
|
||||
val privkey = ECPrivateKey()
|
||||
// privkey: ECPrivateKey = Masked(ECPrivateKey)
|
||||
val pubkey = privkey.publicKey
|
||||
// pubkey: org.bitcoins.crypto.ECPublicKey = ECPublicKey(03f6707515be0721ff2fba357676dd36c5b3f2949d1edb3a5e69cb29f86b8c8d2a)
|
||||
|
||||
val segwitAddress = {
|
||||
// see https://bitcoin.org/en/glossary/pubkey-script
|
||||
// for reading resources on the details of scriptPubKeys
|
||||
// pay-to-witness-pubkey-hash scriptPubKey V0
|
||||
val scriptPubKey = P2WPKHWitnessSPKV0(pubkey)
|
||||
Bech32Address(scriptPubKey, TestNet3)
|
||||
}
|
||||
// segwitAddress: Bech32Address = tb1qffal7z6hxsyq2w7lp0pjesltdvhx7f0mzas9ee
|
||||
|
||||
println(segwitAddress.toString)
|
||||
// tb1qffal7z6hxsyq2w7lp0pjesltdvhx7f0mzas9ee
|
||||
```
|
||||
|
||||
## Generating legacy (base58) addresses
|
||||
|
||||
If you need to generate legacy addresses for backwards
|
||||
compatability reasons, that's also a walk in the park.
|
||||
Take a look:
|
||||
|
||||
```scala
|
||||
// we're reusing the same private/public key pair
|
||||
// from before. don't do this in an actual application!
|
||||
val legacyAddress = P2PKHAddress(pubkey, TestNet3)
|
||||
// legacyAddress: P2PKHAddress = mnJnqfJHXMwQHJPNH7N2tuBd9CJjSJwqay
|
||||
|
||||
println(legacyAddress.toString)
|
||||
// mnJnqfJHXMwQHJPNH7N2tuBd9CJjSJwqay
|
||||
```
|
108
website/versioned_docs/version-1.7.0/core/core-intro.md
Normal file
108
website/versioned_docs/version-1.7.0/core/core-intro.md
Normal file
@ -0,0 +1,108 @@
|
||||
---
|
||||
id: version-1.7.0-core-intro
|
||||
title: Core Module
|
||||
original_id: core-intro
|
||||
---
|
||||
|
||||
The `core` module is the core (duh!) functionality of Bitcoin-S. The goal is to provide basic
|
||||
data structures that are found in the Bitcoin and Lightning protocols while
|
||||
minimizing external dependencies for security purposes. We aim to have an extremely
|
||||
high level of test coverage in this module to flesh out bugs. We use property based
|
||||
testing heavily in this library to ensure high quality of code.
|
||||
|
||||
## The basics
|
||||
|
||||
Every bitcoin protocol data structure (and some other data structures) extends [`NetworkElement`](/api/org/bitcoins/crypto/NetworkElement). `NetworkElement` provides methods to convert the data structure to hex or byte representation. When paired with [`Factory`](/api/org/bitcoins/crypto/Factory) we can easily serialize and deserialize data structures.
|
||||
|
||||
Most data structures have companion objects that extends `Factory` to be able to easily create protocol data structures. An example of this is the [`ScriptPubKey`](/api/org/bitcoins/core/protocol/script/ScriptPubKey) companion object. You can use this companion object to create a `ScriptPubKey` from a hex string or a byte array.
|
||||
|
||||
## Main modules in `core`
|
||||
|
||||
1. [`protocol`](/api/org/bitcoins/core/protocol) - basic protocol data structures. Useful for serializing/deserializing things
|
||||
1. [`crypto`](/api/org/bitcoins/core/crypto) - cryptograhic functionality used in Bitcoin and Lightning
|
||||
1. [`script`](/api/org/bitcoins/core/script) - an implementation of [Script](https://en.bitcoin.it/wiki/Script) - the programming language in Bitcoin
|
||||
1. [`wallet`](/api/org/bitcoins/core/wallet) - implements signing logic for Bitcoin transactions. This module is not named well as there is **NO** functionality to persist wallet state to disk as it stands. This will most likely be renamed in the future.
|
||||
1. [`config`](/api/org/bitcoins/core/config) - Contains information about a chain's genesis block and DNS seeds
|
||||
1. [`number`](/api/org/bitcoins/core/number) - Implements number types that are native in C, i.e. `UInt8`, `UInt32`, `UInt64`, etc.
|
||||
1. [`currency`](/api/org/bitcoins/core/currency) - Implements currency units in the Bitcoin protocol
|
||||
1. [`bloom`](/api/org/bitcoins/core/bloom) - Implements [Bloom filters](https://en.wikipedia.org/wiki/Bloom_filter) and [merkle blocks](https://bitcoin.org/en/glossary/merkle-block) needed for [BIP37](https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki)
|
||||
1. [`hd`](/api/org/bitcoins/core/hd) - Contains implementations of hierarchical deterministic (HD) paths, that when combined with `ExtPrivKey` and `ExtPubKey` in `crypto` can implement BIP32, BIP44, BIP49 and BIP84.
|
||||
|
||||
## Examples
|
||||
|
||||
### Serializing and deserializing a `Transaction`
|
||||
|
||||
Here is an example scala console session with bitcoins-core
|
||||
|
||||
```scala
|
||||
import org.bitcoins.core.protocol.transaction._
|
||||
|
||||
val hexTx = "0100000002d8c8df6a6fdd2addaf589a83d860f18b44872d13ee6ec3526b2b470d42a96d4d000000008b483045022100b31557e47191936cb14e013fb421b1860b5e4fd5d2bc5ec1938f4ffb1651dc8902202661c2920771fd29dd91cd4100cefb971269836da4914d970d333861819265ba014104c54f8ea9507f31a05ae325616e3024bd9878cb0a5dff780444002d731577be4e2e69c663ff2da922902a4454841aa1754c1b6292ad7d317150308d8cce0ad7abffffffff2ab3fa4f68a512266134085d3260b94d3b6cfd351450cff021c045a69ba120b2000000008b4830450220230110bc99ef311f1f8bda9d0d968bfe5dfa4af171adbef9ef71678d658823bf022100f956d4fcfa0995a578d84e7e913f9bb1cf5b5be1440bcede07bce9cd5b38115d014104c6ec27cffce0823c3fecb162dbd576c88dd7cda0b7b32b0961188a392b488c94ca174d833ee6a9b71c0996620ae71e799fc7c77901db147fa7d97732e49c8226ffffffff02c0175302000000001976a914a3d89c53bb956f08917b44d113c6b2bcbe0c29b788acc01c3d09000000001976a91408338e1d5e26db3fce21b011795b1c3c8a5a5d0788ac00000000"
|
||||
// hexTx: String = 0100000002d8c8df6a6fdd2addaf589a83d860f18b44872d13ee6ec3526b2b470d42a96d4d000000008b483045022100b31557e47191936cb14e013fb421b1860b5e4fd5d2bc5ec1938f4ffb1651dc8902202661c2920771fd29dd91cd4100cefb971269836da4914d970d333861819265ba014104c54f8ea9507f31a05ae325616e3024bd9878cb0a5dff780444002d731577be4e2e69c663ff2da922902a4454841aa1754c1b6292ad7d317150308d8cce0ad7abffffffff2ab3fa4f68a512266134085d3260b94d3b6cfd351450cff021c045a69ba120b2000000008b4830450220230110bc99ef311f1f8bda9d0d968bfe5dfa4af171adbef9ef71678d658823bf022100f956d4fcfa0995a578d84e7e913f9bb1cf5b5be1440bcede07bce9cd5b38115d014104c6ec27cffce0823c3fecb162dbd576c88dd7cda0b7b32b0961188a392b488c94ca174d833ee6a9b71c0996620ae71e799fc7c77901db147fa7d97732e49c8226ffffffff02c0175302000000001976a914a3d89c53bb956f08917b44d113c6b2bcbe0c29b788acc01c3d09000000001976a91408338e1d5e26db3fce21b011795b1c3c8a5a5d0788ac00000000
|
||||
|
||||
val tx = Transaction.fromHex(hexTx)
|
||||
// tx: Transaction = BaseTransaction(Int32Impl(1),Vector(TransactionInputImpl(TransactionOutPoint(4d6da9420d472b6b52c36eee132d87448bf160d8839a58afdd2add6f6adfc8d8:0),P2PKHScriptSignature(ECPublicKeyBytes(ByteVector(65 bytes, 0x04c54f8ea9507f31a05ae325616e3024bd9878cb0a5dff780444002d731577be4e2e69c663ff2da922902a4454841aa1754c1b6292ad7d317150308d8cce0ad7ab)), ECDigitalSignature(3045022100b31557e47191936cb14e013fb421b1860b5e4fd5d2bc5ec1938f4ffb1651dc8902202661c2920771fd29dd91cd4100cefb971269836da4914d970d333861819265ba01)),UInt32Impl(4294967295)), TransactionInputImpl(TransactionOutPoint(b220a19ba645c021f0cf501435fd6c3b4db960325d0834612612a5684ffab32a:0),P2PKHScriptSignature(ECPublicKeyBytes(ByteVector(65 bytes, 0x04c6ec27cffce0823c3fecb162dbd576c88dd7cda0b7b32b0961188a392b488c94ca174d833ee6a9b71c0996620ae71e799fc7c77901db147fa7d97732e49c8226)), ECDigitalSignature(30450220230110bc99ef311f1f8bda9d0d968bfe5dfa4af171adbef9ef71678d658823bf022100f956d4fcfa0995a578d84e7e913f9bb1cf5b5be1440bcede07bce9cd5b38115d01)),UInt32Impl(4294967295))),Vector(TransactionOutput(39000000 sats,pkh(a3d89c53bb956f08917b44d113c6b2bcbe0c29b7)), TransactionOutput(155000000 sats,pkh(08338e1d5e26db3fce21b011795b1c3c8a5a5d07))),UInt32Impl(0))
|
||||
|
||||
tx.hex == hexTx
|
||||
// res0: Boolean = true
|
||||
```
|
||||
|
||||
This gives us an example of a hex encoded Bitcoin transaction that is deserialized to a native Scala object called a [`Transaction`](/api/org/bitcoins/core/protocol/transaction/Transaction). You could also serialize the transaction to bytes using `tx.bytes` instead of `tx.hex`. These methods are available on every data structure that extends NetworkElement, like [`ECPrivateKey`](/api/org/bitcoins/crypto/ECPrivateKey), [`ScriptPubKey`](/api/org/bitcoins/core/protocol/script/ScriptPubKey), [`ScriptWitness`](/api/org/bitcoins/core/protocol/script/ScriptWitness), and [`Block`](/api/org/bitcoins/core/protocol/blockchain/Block).
|
||||
|
||||
#### Generating a BIP39 mnemonic phrase and an `xpriv`
|
||||
|
||||
See our [HD example](hd-keys)
|
||||
|
||||
### Building a signed transaction
|
||||
|
||||
Bitcoin Core supports building unsigned transactions and then signing them with a set of private keys. The first important thing to look at is [`UTXOSpendingInfo`](/api/org/bitcoins/core/wallet/utxo/UTXOSpendingInfo). This contains all of the information needed to create a validly signed [`ScriptSignature`](/api/org/bitcoins/core/protocol/script/ScriptSignature) that spends this output.
|
||||
|
||||
Our [`RawTxBuilder`](/api/org/bitcoins/core/wallet/builder/RawTxBuilder) class requires you to provide the following:
|
||||
|
||||
1. `destinations` - the places we are sending bitcoin to. These are [TransactionOutputs](/api/org/bitcoins/core/protocol/transaction/TransactionOutput) you are sending coins too
|
||||
2. `utxos` - these are the [InputSigningInfo](/api/org/bitcoins/core/wallet/utxo/InputSigningInfo) used to fund your transaction. These must exist in your wallet, and you must know how to spend them (i.e. have the private key)
|
||||
3. `feeRate` - the fee rate you want to pay for this transaction
|
||||
4. `changeSPK` - where the change (i.e. `creditingAmount - destinationAmount - fee`) from the transaction will be sent
|
||||
5. `network` - the [network](/api/org/bitcoins/core/config/NetworkParameters) we are transacting on
|
||||
|
||||
After providing this information, you can generate a validly signed bitcoin transaction by calling the `sign` method.
|
||||
|
||||
To see a complete example of this, see [our `TxBuilder` example](txbuilder.md)
|
||||
|
||||
### Verifying a transaction's script is valid (does not check if UTXO is valid)
|
||||
|
||||
Transactions are run through the interpreter to check their validity. These are packaged up into an object called `ScriptProgram`, which contains the following:
|
||||
|
||||
- The transaction that is being checked
|
||||
- The specific input index that it is checking
|
||||
- The `scriptPubKey` for the crediting transaction
|
||||
- The flags used to verify the script
|
||||
|
||||
Here is an example of a transaction spending a `scriptPubKey` which is correctly evaluated with our interpreter implementation:
|
||||
|
||||
|
||||
```scala
|
||||
val spendingTx = Transaction.fromHex("0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000")
|
||||
// spendingTx: Transaction = BaseTransaction(Int32Impl(1),Vector(TransactionInputImpl(TransactionOutPoint(b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc:0),P2PKHScriptSignature(ECPublicKeyBytes(ByteVector(33 bytes, 0x0241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353)), ECDigitalSignature(30450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01)),UInt32Impl(4294967295))),Vector(TransactionOutput(89994000 sats,pkh(b1d7591b69e9def0feb13254bace942923c7922d)), TransactionOutput(840 sats,pkh(5e690c865c2f6f7a9710a474154ab1423abb5b92))),UInt32Impl(0))
|
||||
|
||||
val scriptPubKey = ScriptPubKey.fromAsmHex("76a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac")
|
||||
// scriptPubKey: ScriptPubKey = pkh(31a420903c05a0a7de2de40c9f02ebedbacdc172)
|
||||
|
||||
val output = TransactionOutput(CurrencyUnits.zero, scriptPubKey)
|
||||
// output: TransactionOutput = TransactionOutput(0 sats,pkh(31a420903c05a0a7de2de40c9f02ebedbacdc172))
|
||||
|
||||
val inputIndex = UInt32.zero
|
||||
// inputIndex: UInt32 = UInt32Impl(0)
|
||||
|
||||
val btxsc = BaseTxSigComponent(spendingTx,inputIndex,output,Policy.standardScriptVerifyFlags)
|
||||
// btxsc: BaseTxSigComponent = BaseTxSigComponentImpl(BaseTransaction(Int32Impl(1),Vector(TransactionInputImpl(TransactionOutPoint(b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc:0),P2PKHScriptSignature(ECPublicKeyBytes(ByteVector(33 bytes, 0x0241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353)), ECDigitalSignature(30450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01)),UInt32Impl(4294967295))),Vector(TransactionOutput(89994000 sats,pkh(b1d7591b69e9def0feb13254bace942923c7922d)), TransactionOutput(840 sats,pkh(5e690c865c2f6f7a9710a474154ab1423abb5b92))),UInt32Impl(0)),UInt32Impl(0),TransactionOutput(0 sats,pkh(31a420903c05a0a7de2de40c9f02ebedbacdc172)),List(ScriptVerifyP2SH, ScriptVerifyDerSig, ScriptVerifyStrictEnc, ScriptVerifyMinimalData, ScriptVerifyDiscourageUpgradableNOPs, ScriptVerifyCleanStack, ScriptVerifyCheckLocktimeVerify, ScriptVerifyCheckSequenceVerify, ScriptVerifyLowS, ScriptVerifyWitness, ScriptVerifyMinimalIf, ScriptVerifyNullFail, ScriptVerifyNullDummy, ScriptVerifyWitnessPubKeyType, ScriptVerifyDiscourageUpgradableWitnessProgram))
|
||||
|
||||
val preExecution = PreExecutionScriptProgram(btxsc)
|
||||
// preExecution: PreExecutionScriptProgram = PreExecutionScriptProgram(BaseTxSigComponentImpl(BaseTransaction(Int32Impl(1),Vector(TransactionInputImpl(TransactionOutPoint(b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc:0),P2PKHScriptSignature(ECPublicKeyBytes(ByteVector(33 bytes, 0x0241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353)), ECDigitalSignature(30450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01)),UInt32Impl(4294967295))),Vector(TransactionOutput(89994000 sats,pkh(b1d7591b69e9def0feb13254bace942923c7922d)), TransactionOutput(840 sats,pkh(5e690c865c2f6f7a9710a474154ab1423abb5b92))),UInt32Impl(0)),UInt32Impl(0),TransactionOutput(0 sats,pkh(31a420903c05a0a7de2de40c9f02ebedbacdc172)),List(ScriptVerifyP2SH, ScriptVerifyDerSig, ScriptVerifyStrictEnc, ScriptVerifyMinimalData, ScriptVerifyDiscourageUpgradableNOPs, ScriptVerifyCleanStack, ScriptVerifyCheckLocktimeVerify, ScriptVerifyCheckSequenceVerify, ScriptVerifyLowS, ScriptVerifyWitness, ScriptVerifyMinimalIf, ScriptVerifyNullFail, ScriptVerifyNullDummy, ScriptVerifyWitnessPubKeyType, ScriptVerifyDiscourageUpgradableWitnessProgram)),List(),List(BytesToPushOntoStackImpl(72), ScriptConstantImpl(ByteVector(72 bytes, 0x30450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01)), BytesToPushOntoStackImpl(33), ScriptConstantImpl(ByteVector(33 bytes, 0x0241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353))),List(BytesToPushOntoStackImpl(72), ScriptConstantImpl(ByteVector(72 bytes, 0x30450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01)), BytesToPushOntoStackImpl(33), ScriptConstantImpl(ByteVector(33 bytes, 0x0241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353))),List(),List(ScriptVerifyP2SH, ScriptVerifyDerSig, ScriptVerifyStrictEnc, ScriptVerifyMinimalData, ScriptVerifyDiscourageUpgradableNOPs, ScriptVerifyCleanStack, ScriptVerifyCheckLocktimeVerify, ScriptVerifyCheckSequenceVerify, ScriptVerifyLowS, ScriptVerifyWitness, ScriptVerifyMinimalIf, ScriptVerifyNullFail, ScriptVerifyNullDummy, ScriptVerifyWitnessPubKeyType, ScriptVerifyDiscourageUpgradableWitnessProgram))
|
||||
|
||||
val result = ScriptInterpreter.run(preExecution)
|
||||
// result: org.bitcoins.core.script.result.ScriptResult = ScriptOk
|
||||
|
||||
println(s"Script execution result=${result}")
|
||||
// Script execution result=ScriptOk
|
||||
```
|
224
website/versioned_docs/version-1.7.0/core/dlc.md
Normal file
224
website/versioned_docs/version-1.7.0/core/dlc.md
Normal file
File diff suppressed because one or more lines are too long
145
website/versioned_docs/version-1.7.0/core/hd-keys.md
Normal file
145
website/versioned_docs/version-1.7.0/core/hd-keys.md
Normal file
@ -0,0 +1,145 @@
|
||||
---
|
||||
id: version-1.7.0-hd-keys
|
||||
title: HD Key Generation
|
||||
original_id: hd-keys
|
||||
---
|
||||
|
||||
In modern Bitcoin wallets, users only need to write down
|
||||
a sequence of words, and that sequence is a complete backup
|
||||
of their wallet. This is thanks to what's called Hierarchical
|
||||
Deterministic key generation. In short, every wallet using HD
|
||||
key generation has a root seed for each wallet, and this
|
||||
seed can be used to generate an arbitrary amount of later
|
||||
private and public keys. This is done in a standardized manner,
|
||||
so different wallets can operate with the same standard.
|
||||
|
||||
> If you want to jump into the details of how this work,
|
||||
> you should check out
|
||||
> [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki).
|
||||
|
||||
Bitcoin-S supports generating keys in this fashion. Here's a
|
||||
full example of how to obtain a wallet seed, and then
|
||||
use that to generate further private and public keys:
|
||||
|
||||
```scala
|
||||
import scodec.bits._
|
||||
import org.bitcoins.core.crypto._
|
||||
import org.bitcoins.core.hd._
|
||||
|
||||
// the length of the entropy bit vector determine
|
||||
// how long our phrase ends up being
|
||||
// 256 bits of entropy results in 24 words
|
||||
val entropy: BitVector = MnemonicCode.getEntropy256Bits
|
||||
// entropy: BitVector = BitVector(256 bits, 0x16dd4939bdf5acd606e2542a52110df822554fa98ef0574995facad06d41d73a)
|
||||
|
||||
val mnemonicCode = MnemonicCode.fromEntropy(entropy)
|
||||
// mnemonicCode: MnemonicCode = Masked(MnemonicCodeImpl)
|
||||
|
||||
mnemonicCode.words // the phrase the user should write down
|
||||
// res0: Vector[String] = Vector(bitter, tumble, example, know, food, help, breeze, enhance, clean, mountain, drop, utility, census, pond, plate, task, firm, erosion, leaf, noble, almost, path, friend, flush) // the phrase the user should write down
|
||||
|
||||
// the password argument is an optional, extra security
|
||||
// measure. all MnemonicCode instances will give you a
|
||||
// valid BIP39 seed, but different passwords will give
|
||||
// you different seeds. So you could have as many wallets
|
||||
// from the same seed as you'd like, by simply giving them
|
||||
// different passwords.
|
||||
val bip39Seed = BIP39Seed.fromMnemonic(mnemonicCode,
|
||||
password = "secret password")
|
||||
// bip39Seed: BIP39Seed = Masked(BIP39SeedImpl)
|
||||
|
||||
val xpriv = ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.SegWitMainNetPriv,
|
||||
bip39Seed)
|
||||
// xpriv: ExtPrivateKey = Masked(ExtPrivateKeyImpl)
|
||||
val xpub = xpriv.extPublicKey
|
||||
// xpub: ExtPublicKey = zpub6jftahH18ngZwG89hnVr5pvsDrFSTgGTBqCj7E9qDrZnhojyrzm3SJVTGGAjfhDefGDHKNqxGf9dJP9QKLLzVmomjcoph76mfGaWCzJ8YuG
|
||||
|
||||
// you can now use the generated xpriv to derive further
|
||||
// private or public keys
|
||||
|
||||
// this can be done with BIP89 paths (called SegWitHDPath in bitcoin-s)
|
||||
val segwitPath = SegWitHDPath.fromString("m/84'/0'/0'/0/0")
|
||||
// segwitPath: SegWitHDPath = m/84'/0'/0'/0/0
|
||||
|
||||
// alternatively:
|
||||
val otherSegwitPath =
|
||||
SegWitHDPath(HDCoinType.Bitcoin,
|
||||
accountIndex = 0,
|
||||
HDChainType.External,
|
||||
addressIndex = 0)
|
||||
// otherSegwitPath: SegWitHDPath = m/84'/0'/0'/0/0
|
||||
|
||||
segwitPath == otherSegwitPath
|
||||
// res1: Boolean = true
|
||||
```
|
||||
|
||||
## Generating new addresses without having access to the private key
|
||||
|
||||
One the coolest features of HD wallets is that it's possible
|
||||
to generate addresses offline, without having access to the
|
||||
private keys. This feature is commonly called watch-only
|
||||
wallets, where a wallet can import information about all
|
||||
your past and future transactions, without being able to
|
||||
spend or steal any of your money.
|
||||
|
||||
Let's see an example of this:
|
||||
|
||||
```scala
|
||||
import scala.util.Success
|
||||
import org.bitcoins.core.protocol.script._
|
||||
import org.bitcoins.core.protocol.Bech32Address
|
||||
import org.bitcoins.core.config.TestNet3
|
||||
|
||||
// first account -------┐
|
||||
// bitcoin ----------┐ |
|
||||
// segwit --------┐ | |
|
||||
val accountPath = BIP32Path.fromString("m/84'/0'/0'")
|
||||
// accountPath: BIP32Path = m/84'/0'/0'
|
||||
val accountXpub = {
|
||||
// this key is sensitive, keep away from prying eyes!
|
||||
val accountXpriv = xpriv.deriveChildPrivKey(accountPath)
|
||||
|
||||
// this key is not sufficient to spend from, but we
|
||||
// can generate addresses with it!
|
||||
accountXpriv.extPublicKey
|
||||
}
|
||||
// accountXpub: ExtPublicKey = zpub6remHJh4KL3G7YWJaynJXHzEbshNKrMF6HBxG653RfnqrtuUM8KShdEyrQFDmmXAyjmsThr9qNRAacckwj4H9FKtAPJMewihbH9wLkBC2rF
|
||||
|
||||
// address no. 0 ---------------┐
|
||||
// external address ----------┐ |
|
||||
val firstAddressPath = SegWitHDPath.fromString("m/84'/0'/0'/0/0")
|
||||
// firstAddressPath: SegWitHDPath = m/84'/0'/0'/0/0
|
||||
val firstAccountAddress = {
|
||||
// this is a bit quirky, but we're not interesting in
|
||||
// deriving the complete path from our account xpub
|
||||
// instead, we're only interested in the part after
|
||||
// the account level (3rd level). the .diff() method
|
||||
// achieves that
|
||||
val Some(pathDiff) = accountPath.diff(firstAddressPath)
|
||||
|
||||
// deriving public keys from hardened extended keys
|
||||
// is not possible, that's why .deriveChildPubKey()
|
||||
// returns a Try[ExtPublicKey]. A hardened key is marked
|
||||
// by a ' after the number in the notation we use above.
|
||||
val Success(extPubKey) = accountXpub.deriveChildPubKey(pathDiff)
|
||||
val pubkey = extPubKey.key
|
||||
val scriptPubKey = P2WPKHWitnessSPKV0(pubkey)
|
||||
Bech32Address(scriptPubKey, TestNet3)
|
||||
}
|
||||
// firstAccountAddress: Bech32Address = tb1qza5xu0zmmpmhzlsd8kh7tp6jy9zcd3ez0tgty7
|
||||
|
||||
// tada! We just generated an address you can send money to,
|
||||
// without having access to the private key!
|
||||
firstAccountAddress.value
|
||||
// res2: String = tb1qza5xu0zmmpmhzlsd8kh7tp6jy9zcd3ez0tgty7
|
||||
|
||||
// you can now continue deriving addresses from the same public
|
||||
// key, by imitating what we did above. To get the next
|
||||
// HD path to generate an address at:
|
||||
val nextAddressPath: SegWitHDPath = firstAddressPath.next
|
||||
// nextAddressPath: SegWitHDPath = m/84'/0'/0'/0/1
|
||||
```
|
||||
|
||||
### Signing things with HD keys
|
||||
|
||||
Please see [sign.md](../crypto/sign.md) for information on how to sign things with HD keys.
|
158
website/versioned_docs/version-1.7.0/core/txbuilder.md
Normal file
158
website/versioned_docs/version-1.7.0/core/txbuilder.md
Normal file
@ -0,0 +1,158 @@
|
||||
---
|
||||
id: version-1.7.0-txbuilder
|
||||
title: TxBuilder Example
|
||||
original_id: txbuilder
|
||||
---
|
||||
|
||||
Bitcoin-S features a transaction building API that allows you to construct and sign Bitcoin transactions. Here's an example of how to use it
|
||||
|
||||
|
||||
```scala
|
||||
implicit val ec: ExecutionContext = ExecutionContext.Implicits.global
|
||||
// ec: ExecutionContext = scala.concurrent.impl.ExecutionContextImpl$$anon$3@389bfe35[Running, parallelism = 16, size = 0, active = 0, running = 0, steals = 0, tasks = 0, submissions = 0]
|
||||
|
||||
// Initialize a transaction builder
|
||||
val builder = RawTxBuilder()
|
||||
// builder: RawTxBuilder = RawTxBuilder()
|
||||
|
||||
// generate a fresh private key that we are going to use in the scriptpubkey
|
||||
val privKey = ECPrivateKey.freshPrivateKey
|
||||
// privKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||
val pubKey = privKey.publicKey
|
||||
// pubKey: ECPublicKey = ECPublicKey(036e42f11d0653642c19327932688d5df90789cf7ac24f14c56a985fa5d83236be)
|
||||
|
||||
// this is the script that the TxBuilder is going to create a
|
||||
// script signature that validly spends this scriptPubKey
|
||||
val creditingSpk = P2PKHScriptPubKey(pubKey = privKey.publicKey)
|
||||
// creditingSpk: P2PKHScriptPubKey = pkh(8bba141cab8b1bee4e02185667abeeff96ae2af4)
|
||||
val amount = 10000.satoshis
|
||||
// amount: Satoshis = 10000 sats
|
||||
|
||||
// this is the UTXO we are going to be spending
|
||||
val utxo =
|
||||
TransactionOutput(value = amount, scriptPubKey = creditingSpk)
|
||||
// utxo: TransactionOutput = TransactionOutput(10000 sats,pkh(8bba141cab8b1bee4e02185667abeeff96ae2af4))
|
||||
|
||||
// the private key that locks the funds for the script we are spending too
|
||||
val destinationPrivKey = ECPrivateKey.freshPrivateKey
|
||||
// destinationPrivKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||
|
||||
// the amount we are sending -- 5000 satoshis -- to the destinationSPK
|
||||
val destinationAmount = 5000.satoshis
|
||||
// destinationAmount: Satoshis = 5000 sats
|
||||
|
||||
// the script that corresponds to destination private key, this is what is receiving the money
|
||||
val destinationSPK =
|
||||
P2PKHScriptPubKey(pubKey = destinationPrivKey.publicKey)
|
||||
// destinationSPK: P2PKHScriptPubKey = pkh(1d0baa683ea385c5cc7063ac9ffe17d0d6841c5a)
|
||||
|
||||
// this is where we are sending money too
|
||||
// we could add more destinations here if we
|
||||
// wanted to batch transactions
|
||||
val destinations = {
|
||||
val destination0 = TransactionOutput(value = destinationAmount,
|
||||
scriptPubKey = destinationSPK)
|
||||
|
||||
Vector(destination0)
|
||||
}
|
||||
// destinations: Vector[TransactionOutput] = Vector(TransactionOutput(5000 sats,pkh(1d0baa683ea385c5cc7063ac9ffe17d0d6841c5a)))
|
||||
|
||||
// Add the destinations to the tx builder
|
||||
builder ++= destinations
|
||||
// res0: RawTxBuilder = RawTxBuilder()
|
||||
|
||||
// we have to fabricate a transaction that contains the
|
||||
// UTXO we are trying to spend. If this were a real blockchain
|
||||
// we would need to reference the UTXO set
|
||||
val creditingTx = BaseTransaction(version = Int32.one,
|
||||
inputs = Vector.empty,
|
||||
outputs = Vector(utxo),
|
||||
lockTime = UInt32.zero)
|
||||
// creditingTx: BaseTransaction = BaseTransaction(Int32Impl(1),Vector(),Vector(TransactionOutput(10000 sats,pkh(8bba141cab8b1bee4e02185667abeeff96ae2af4))),UInt32Impl(0))
|
||||
|
||||
// this is the information we need from the crediting TX
|
||||
// to properly "link" it in the transaction we are creating
|
||||
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||
// outPoint: TransactionOutPoint = TransactionOutPoint(2fa3cbde8ffe96a06d1b1062322ee737c89e43a14ab6060c0b4c198f3b721891:0)
|
||||
val input = TransactionInput(
|
||||
outPoint,
|
||||
EmptyScriptSignature,
|
||||
sequenceNumber = UInt32.zero)
|
||||
// input: TransactionInput = TransactionInputImpl(TransactionOutPoint(2fa3cbde8ffe96a06d1b1062322ee737c89e43a14ab6060c0b4c198f3b721891:0),EmptyScriptSignature,UInt32Impl(0))
|
||||
|
||||
// Add a new input to our builder
|
||||
builder += input
|
||||
// res1: RawTxBuilder = RawTxBuilder()
|
||||
|
||||
// We can now generate a RawTxBuilderResult ready to be finalized
|
||||
val builderResult = builder.result()
|
||||
// builderResult: RawTxBuilderResult = RawTxBuilderResult(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(2fa3cbde8ffe96a06d1b1062322ee737c89e43a14ab6060c0b4c198f3b721891:0),EmptyScriptSignature,UInt32Impl(0))),Vector(TransactionOutput(5000 sats,pkh(1d0baa683ea385c5cc7063ac9ffe17d0d6841c5a))),UInt32Impl(0))
|
||||
|
||||
// this contains the information needed to analyze our input during finalization
|
||||
val inputInfo = P2PKHInputInfo(outPoint, amount, privKey.publicKey)
|
||||
// inputInfo: P2PKHInputInfo = P2PKHInputInfo(TransactionOutPoint(2fa3cbde8ffe96a06d1b1062322ee737c89e43a14ab6060c0b4c198f3b721891:0),10000 sats,ECPublicKey(036e42f11d0653642c19327932688d5df90789cf7ac24f14c56a985fa5d83236be))
|
||||
|
||||
// this is how much we are going to pay as a fee to the network
|
||||
// for this example, we are going to pay 1 satoshi per byte
|
||||
val feeRate = SatoshisPerByte(1.satoshi)
|
||||
// feeRate: SatoshisPerByte = 1 sats/byte
|
||||
|
||||
val changePrivKey = ECPrivateKey.freshPrivateKey
|
||||
// changePrivKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||
val changeSPK = P2PKHScriptPubKey(pubKey = changePrivKey.publicKey)
|
||||
// changeSPK: P2PKHScriptPubKey = pkh(19372f479ad10bf21a26b0475ffd46d0d1cf5d15)
|
||||
|
||||
// We chose a finalizer that adds a change output to our tx based on a fee rate
|
||||
val finalizer = StandardNonInteractiveFinalizer(
|
||||
Vector(inputInfo),
|
||||
feeRate,
|
||||
changeSPK)
|
||||
// finalizer: StandardNonInteractiveFinalizer = StandardNonInteractiveFinalizer(Vector(P2PKHInputInfo(TransactionOutPoint(2fa3cbde8ffe96a06d1b1062322ee737c89e43a14ab6060c0b4c198f3b721891:0),10000 sats,ECPublicKey(036e42f11d0653642c19327932688d5df90789cf7ac24f14c56a985fa5d83236be))),1 sats/byte,pkh(19372f479ad10bf21a26b0475ffd46d0d1cf5d15))
|
||||
|
||||
// We can now finalize the tx builder result from earlier with this finalizer
|
||||
val unsignedTx: Transaction = finalizer.buildTx(builderResult)
|
||||
// unsignedTx: Transaction = BaseTransaction(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(2fa3cbde8ffe96a06d1b1062322ee737c89e43a14ab6060c0b4c198f3b721891:0),EmptyScriptSignature,UInt32Impl(0))),Vector(TransactionOutput(5000 sats,pkh(1d0baa683ea385c5cc7063ac9ffe17d0d6841c5a)), TransactionOutput(4775 sats,pkh(19372f479ad10bf21a26b0475ffd46d0d1cf5d15))),UInt32Impl(0))
|
||||
|
||||
// We now turn to signing the unsigned transaction
|
||||
// this contains all the information we need to
|
||||
// validly sign the UTXO above
|
||||
val utxoInfo = ScriptSignatureParams(inputInfo = inputInfo,
|
||||
prevTransaction = creditingTx,
|
||||
signers = Vector(privKey),
|
||||
hashType =
|
||||
HashType.sigHashAll)
|
||||
// utxoInfo: ScriptSignatureParams[P2PKHInputInfo] = ScriptSignatureParams(P2PKHInputInfo(TransactionOutPoint(2fa3cbde8ffe96a06d1b1062322ee737c89e43a14ab6060c0b4c198f3b721891:0),10000 sats,ECPublicKey(036e42f11d0653642c19327932688d5df90789cf7ac24f14c56a985fa5d83236be)),BaseTransaction(Int32Impl(1),Vector(),Vector(TransactionOutput(10000 sats,pkh(8bba141cab8b1bee4e02185667abeeff96ae2af4))),UInt32Impl(0)),Vector(Masked(ECPrivateKey)),SIGHASH_ALL(Int32Impl(1)))
|
||||
|
||||
// all of the UTXO spending information, since we only have
|
||||
// one input, this is just one element
|
||||
val utxoInfos: Vector[ScriptSignatureParams[InputInfo]] = Vector(utxoInfo)
|
||||
// utxoInfos: Vector[ScriptSignatureParams[InputInfo]] = Vector(ScriptSignatureParams(P2PKHInputInfo(TransactionOutPoint(2fa3cbde8ffe96a06d1b1062322ee737c89e43a14ab6060c0b4c198f3b721891:0),10000 sats,ECPublicKey(036e42f11d0653642c19327932688d5df90789cf7ac24f14c56a985fa5d83236be)),BaseTransaction(Int32Impl(1),Vector(),Vector(TransactionOutput(10000 sats,pkh(8bba141cab8b1bee4e02185667abeeff96ae2af4))),UInt32Impl(0)),Vector(Masked(ECPrivateKey)),SIGHASH_ALL(Int32Impl(1))))
|
||||
|
||||
// Yay! Now we use the RawTxSigner object to sign the tx.
|
||||
// The 'sign' method is going produce a validly signed transaction
|
||||
// This is going to iterate through each of the UTXOs and use
|
||||
// the corresponding ScriptSignatureParams to produce a validly
|
||||
// signed input. This UTXO has:
|
||||
// 1: one input
|
||||
// 2: outputs (destination and change outputs)
|
||||
// 3: a fee rate of 1 satoshi/byte
|
||||
val signedTx: Transaction =
|
||||
RawTxSigner.sign(
|
||||
utx = unsignedTx,
|
||||
utxoInfos = utxoInfos,
|
||||
expectedFeeRate = feeRate
|
||||
)
|
||||
// signedTx: Transaction = BaseTransaction(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(2fa3cbde8ffe96a06d1b1062322ee737c89e43a14ab6060c0b4c198f3b721891:0),P2PKHScriptSignature(ECPublicKeyBytes(ByteVector(33 bytes, 0x036e42f11d0653642c19327932688d5df90789cf7ac24f14c56a985fa5d83236be)), ECDigitalSignature(304402200dba96395e157d4928ac32fbcdf0e043f124159776d3bb493fdfacb3410bdd0702203bea68ee8eb1300f08f605c7e8ba4bee380b6c41d857d693221e876ad0f8351201)),UInt32Impl(0))),Vector(TransactionOutput(5000 sats,pkh(1d0baa683ea385c5cc7063ac9ffe17d0d6841c5a)), TransactionOutput(4775 sats,pkh(19372f479ad10bf21a26b0475ffd46d0d1cf5d15))),UInt32Impl(0))
|
||||
```
|
||||
|
||||
```scala
|
||||
signedTx.inputs.length
|
||||
// res2: Int = 1
|
||||
|
||||
signedTx.outputs.length
|
||||
// res3: Int = 2
|
||||
|
||||
//remember, you can call .hex on any bitcoin-s data structure to get the hex representation!
|
||||
signedTx.hex
|
||||
// res4: String = 02000000019118723b8f194c0b0c06b64aa1439ec837e72e3262101b6da096fe8fdecba32f000000006a47304402200dba96395e157d4928ac32fbcdf0e043f124159776d3bb493fdfacb3410bdd0702203bea68ee8eb1300f08f605c7e8ba4bee380b6c41d857d693221e876ad0f835120121036e42f11d0653642c19327932688d5df90789cf7ac24f14c56a985fa5d83236be000000000288130000000000001976a9141d0baa683ea385c5cc7063ac9ffe17d0d6841c5a88aca7120000000000001976a91419372f479ad10bf21a26b0475ffd46d0d1cf5d1588ac00000000
|
||||
```
|
65
website/versioned_docs/version-1.7.0/crypto/sign.md
Normal file
65
website/versioned_docs/version-1.7.0/crypto/sign.md
Normal file
@ -0,0 +1,65 @@
|
||||
---
|
||||
id: version-1.7.0-sign
|
||||
title: Sign API
|
||||
original_id: sign
|
||||
---
|
||||
|
||||
### The [`Sign` API](/api/org/bitcoins/crypto/Sign)
|
||||
|
||||
This is the API we define to sign things with. It takes in an arbitrary byte vector and returns a `Future[ECDigitalSignature]`. The reason we incorporate `Future`s here is for extensibility of this API. We would like to provide implementations of this API for hardware devices, which need to be asynchrnous since they may require user input.
|
||||
|
||||
From [Sign.scala](/api/org/bitcoins/crypto/Sign):
|
||||
|
||||
```scala
|
||||
import scodec.bits._
|
||||
import org.bitcoins.crypto._
|
||||
import scala.concurrent._
|
||||
import scala.concurrent.duration._
|
||||
|
||||
trait Sign {
|
||||
def signFunction: ByteVector => Future[ECDigitalSignature]
|
||||
|
||||
def signFuture(bytes: ByteVector): Future[ECDigitalSignature] =
|
||||
signFunction(bytes)
|
||||
|
||||
def sign(bytes: ByteVector): ECDigitalSignature = {
|
||||
Await.result(signFuture(bytes), 30.seconds)
|
||||
}
|
||||
|
||||
def publicKey: ECPublicKey
|
||||
}
|
||||
```
|
||||
|
||||
The `ByteVector` that is input to the `signFunction` should be the hash that is output from [`TransactionSignatureSerializer`](/api/org/bitcoins/core/crypto/TransactionSignatureSerializer)'s `hashForSignature` method. Our in-memory [`BaseECKey`](/api/org/bitcoins/crypto/BaseECKey) types implement the `Sign` API.
|
||||
|
||||
If you wanted to implement a new `Sign` api for a hardware wallet, you can easily pass it into the `TxBuilder`/`Signer` classes to allow for you to use those devices to sign with Bitcoin-S.
|
||||
|
||||
This API is currently used to sign ordinary transactions with our [`Signer`](/api/org/bitcoins/core/wallet/signer/Signer)s. The `Signer` subtypes (i.e. `P2PKHSigner`) implement the specific functionality needed to produce a valid digital signature for their corresponding script type.
|
||||
|
||||
|
||||
### The [`ExtSign`](/api/org/bitcoins/crypto/Sign) API.
|
||||
|
||||
An [ExtKey](/api/org/bitcoins/core/crypto/ExtKey) is a data structure that can be used to generate more keys from a parent key. For more information look at [hd-keys.md](../core/hd-keys.md)
|
||||
|
||||
You can sign with `ExtPrivateKey` the same way you could with a normal `ECPrivateKey`.
|
||||
|
||||
```scala
|
||||
import org.bitcoins.core.hd._
|
||||
import org.bitcoins.core.crypto._
|
||||
|
||||
val extPrivKey = ExtPrivateKey(ExtKeyVersion.SegWitMainNetPriv)
|
||||
// extPrivKey: ExtPrivateKey = Masked(ExtPrivateKeyImpl)
|
||||
|
||||
extPrivKey.sign(DoubleSha256Digest.empty.bytes)
|
||||
// res0: ECDigitalSignature = ECDigitalSignature(304402201e9e132ba14eb6d03672195ec50ae783d8f17112e0fa93a7ddc5cf42c5ebd23d022036a78727ecc5e1fe88256838e57c92af9f993f2d245f97ecb6a5d5548764ca88)
|
||||
|
||||
val path = BIP32Path(Vector(BIP32Node(0,false)))
|
||||
// path: BIP32Path = m/0
|
||||
|
||||
extPrivKey.sign(DoubleSha256Digest.empty.bytes,path)
|
||||
// res1: ECDigitalSignature = ECDigitalSignature(30440220673de4f0250c2aeeb966add7458f31007797c22d3c7b7480d8c7adde7c1091a3022045813e7f920764f1c55ba1fccd8886dfe3dd8b7ed3a0150e0d72aef4b97a9c94)
|
||||
```
|
||||
|
||||
With `ExtSign`, you can use `ExtPrivateKey` to sign transactions inside of `TxBuilder` since `UTXOSpendingInfo` takes in `Sign` as a parameter.
|
||||
|
||||
You can also provide a `path` to use to derive a child `ExtPrivateKey`, and then sign with that child private key
|
193
website/versioned_docs/version-1.7.0/getting-setup.md
Normal file
193
website/versioned_docs/version-1.7.0/getting-setup.md
Normal file
@ -0,0 +1,193 @@
|
||||
---
|
||||
id: version-1.7.0-getting-setup
|
||||
title: Getting Bitcoin-S installed on your machine
|
||||
original_id: getting-setup
|
||||
---
|
||||
|
||||
> This documentation is intended for setting up development of bitcoin-s.
|
||||
> If you want to just install bitcoin-s rather than develop,
|
||||
> see [getting-started](getting-started.md)
|
||||
|
||||
## Getting Setup With Bitcoin-S
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
<!-- END doctoc -->
|
||||
|
||||
- [Step 1: Java and Scala](#step-1-developer-runtimes)
|
||||
- [Step 2: Bitcoin-S Repository](#step-2-bitcoin-s-repository)
|
||||
- [Step 3: Configuration](#step-3-configuration)
|
||||
- [Step 4: Setting Up A Bitcoin-S Node](#step-4-setting-up-a-bitcoin-s-node)
|
||||
- [Step 5: (Optional): Moving To Testnet](#step-5-optional-moving-to-testnet)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
|
||||
## Step 1: Developer runtimes
|
||||
|
||||
### Scala/Java
|
||||
To get started you will need Java, Scala, and some other nice tools installed, luckily the Scala team has an easy setup process!
|
||||
|
||||
Simply follow the instructions in [this short blog](https://www.scala-lang.org/2020/06/29/one-click-install.html) to get started.
|
||||
|
||||
If you don't like `curl`, you can use OS specific package managers to install coursier [here](https://get-coursier.io/docs/2.0.0-RC2/cli-overview.html#installation)
|
||||
|
||||
>bitcoin-s requires java9+ for development environments. If you do not have java9+ installed, you will not be able to build bitcoin-s.
|
||||
[You will run into this error if you are on java8 or lower](https://github.com/bitcoin-s/bitcoin-s/issues/3298)
|
||||
|
||||
If you follow the coursier route, [you can switch to a java11 version by running](https://get-coursier.io/docs/2.0.0-RC6-15/cli-java.html)
|
||||
|
||||
>cs java --jvm adopt:11 --setup
|
||||
|
||||
### Scala.js
|
||||
|
||||
We support publishing of [scala.js](https://www.scala-js.org/) artifacts.
|
||||
This library will compile Scala source code into javascript artifacts.
|
||||
|
||||
To be able to run scala js tests, you need to have the Node.js installed.
|
||||
You can install it from [here](https://nodejs.org/en/)
|
||||
|
||||
## Step 2: Bitcoin-S Repository
|
||||
|
||||
Now, it is time to clone the [Bitcoin-S repository](https://github.com/bitcoin-s/bitcoin-s/) by running
|
||||
|
||||
```bashrc
|
||||
git clone --depth 500 --recursive git@github.com:bitcoin-s/bitcoin-s.git
|
||||
```
|
||||
|
||||
or alternatively, if you do not have ssh setup with github, you can run
|
||||
|
||||
```bashrc
|
||||
git clone --depth 500 --recursive https://github.com/bitcoin-s/bitcoin-s.git
|
||||
```
|
||||
|
||||
|
||||
#### Optional: Running full test suite
|
||||
<details>
|
||||
> WARNING: This should not be done on low resource machines. Running the entire test suite requires at minimum of 4GB
|
||||
> of RAM on the machine you are running this on.
|
||||
|
||||
To run the entire test suite, you need to download all bitcoind instances and eclair instances. This is needed for unit tests
|
||||
or binding bitcoin-s to a bitcoind instance if you do not have locally running instances.
|
||||
|
||||
```bashrc
|
||||
sbt downloadBitcoind
|
||||
sbt downloadEclair
|
||||
```
|
||||
|
||||
If you want to run the entire test suite you can run the following command after you download bitcoind
|
||||
and eclair.
|
||||
|
||||
```bashrc
|
||||
sbt test
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
## Step 3: Configuration
|
||||
|
||||
Now that we have the bitcoin-s repo setup, we want to create our application configurations. This is done by creating a `bitcoin-s.conf` file at `$HOME/.bitcoin-s`. [Here is an example configuration file](config/configuration.md#example-configuration-file). The only thing that you will _need_ to change is the `peers` list to which you will want to add `"localhost:18444"` if you want to run in regtest.
|
||||
|
||||
Once the bitcoin-s configuration is all done, I recommend creating a directory someplace in which to run your `bitcoind` node. Once you have this directory created, add the following `bitcoin.conf` file to it
|
||||
|
||||
```
|
||||
regtest=1
|
||||
server=1
|
||||
rpcuser=[your username here]
|
||||
rpcpassword=[your password here]
|
||||
daemon=1
|
||||
blockfilterindex=1
|
||||
peerblockfilters=1
|
||||
debug=1
|
||||
txindex=1
|
||||
```
|
||||
|
||||
## Step 4: Setting Up A Bitcoin-S Node
|
||||
|
||||
We are finally ready to start running some programs! Follow the [instructions here](applications/server.md#building-the-server) to build the server. Then, follow [these instructions](applications/cli.md) to setup the CLI.
|
||||
|
||||
There are 2 ways to use the bitcoin-s server. It can either be as a neutrino node or use bitcoind as a backend.
|
||||
This can be configured by the configuration option `bitcoin-s.node.mode` choosing either `neutrino` or `bitcoind`.
|
||||
|
||||
### Neutrino Node
|
||||
|
||||
<details>
|
||||
To use a neutrino server you need to be paired with a bitcoin node that can serve compact filters.
|
||||
[Suredbits](https://suredbits.com/) runs a mainnet and testnet node you can connect to them by setting your `peers` config option to:
|
||||
|
||||
Mainnet:
|
||||
|
||||
`bitcoin-s.node.peers = ["neutrino.suredbits.com:8333"]`
|
||||
|
||||
Testnet:
|
||||
|
||||
`bitcoin-s.node.peers = ["neutrino.testnet3.suredbits.com:18333"]`
|
||||
|
||||
If you would like to use your own node you can either use the bitcoind backend option or connect to your own compatible node.
|
||||
There is no released version of bitcoind that is neutrino compatible, so you will either have to compile the latest `master` yourself, or use the experimental version provided by running `sbt downloadBitcoind`.
|
||||
|
||||
After building your bitcoin-s server, properly configuring it to be in `neutrino` mode you can start your server with:
|
||||
|
||||
```bashrc
|
||||
./app/server/target/universal/stage/bin/bitcoin-s-server
|
||||
```
|
||||
|
||||
and once this is done, you should be able to communicate with the server using
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bin/bitcoin-s-cli getnewaddress
|
||||
```
|
||||
</details>
|
||||
|
||||
### Bitcoind Backend
|
||||
|
||||
<details>
|
||||
If you already have a bitcoind node running and would like to connect your bitcoin-s server to it you can set your node's mode to `bitcoind`.
|
||||
|
||||
You will need to configure bitcoin-s to be able to find your bitcoind.
|
||||
If you would only like bitcoin-s to connect to bitcoind and start it itself then you only need to properly set the `rpcuser`, and `rpcpassword` options.
|
||||
If you would like bitcoin-s to launch bitcoind on start up you will need to set the other configuration options.
|
||||
These options should default to use the latest bitcoind downloaded from `sbt downloadBitcoind`.
|
||||
|
||||
```$xslt
|
||||
bitcoin-s {
|
||||
bitcoind-rpc {
|
||||
# bitcoind rpc username
|
||||
rpcuser = user
|
||||
# bitcoind rpc password
|
||||
rpcpassword = password
|
||||
|
||||
# Binary location of bitcoind
|
||||
binary = ${HOME}/.bitcoin-s/binaries/bitcoind/bitcoin-0.20.1/bin/bitcoind
|
||||
# bitcoind datadir
|
||||
datadir = ${HOME}/.bitcoin
|
||||
# bitcoind network binding
|
||||
bind = localhost
|
||||
# bitcoind p2p port
|
||||
port = 8333
|
||||
# bitcoind rpc binding
|
||||
rpcbind = localhost
|
||||
# bitcoind rpc port
|
||||
rpcport = 8332
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Step 5 (Optional): Moving To Testnet
|
||||
|
||||
To run your Bitcoin-S Server on testnet, simply change `network = testnet3` and change
|
||||
your `peers = ["neutrino.testnet3.suredbits.com:18333"] ` in your `.bitcoin-s/bitcoin-s.conf` file.
|
||||
This will allow you to connect to Suredbits' neutrino-enabled `bitcoind` node.
|
||||
Keep in mind then when you restart your server, it will begin initial sync which will take
|
||||
many hours as all block filters for all testnet blocks will be downloaded.
|
||||
If you wish to speed this process up,
|
||||
download [this snapshot](https://s3-us-west-2.amazonaws.com/www.suredbits.com/chaindb-testnet-2021-02-03.zip), unzip it and put the file in your `$HOME/.bitcoin-s/testnet3` directory and then from there, run
|
||||
|
||||
```bashrc
|
||||
$ unzip chaindb-testnet-2021-02-03.zip
|
||||
$ mv chaindb.sqlite ~/.bitcoin-s/testnet/
|
||||
```
|
||||
|
||||
This should take a couple minutes to execute, but once it is done, you will only have a short while left to sync once you start your server.
|
127
website/versioned_docs/version-1.7.0/getting-started.md
Normal file
127
website/versioned_docs/version-1.7.0/getting-started.md
Normal file
@ -0,0 +1,127 @@
|
||||
---
|
||||
id: version-1.7.0-getting-started
|
||||
title: Intro and Getting Started
|
||||
original_id: getting-started
|
||||
---
|
||||
|
||||
## Philosophy
|
||||
|
||||
Bitcoin-S is a loosely coupled set of cryptocurrency libraries for the JVM. They work well together, but also can be used
|
||||
independently. This project's goal is NOT to be a full node implementation, rather a set of scalable cryptocurrency libraries
|
||||
that use industry standard tools (rather than esoteric tech often found in cryptocurrency) where possible to make the lives of professional
|
||||
software engineers, security engineers, devops engineers and accountants easier.
|
||||
We are rapidly iterating on development with the goal of getting to a set of stable APIs that only change when the underlying bitcoin protocol changes.
|
||||
|
||||
If you are a professional working a cryptocurrency business and
|
||||
have feedback on how to make your lives easier, please reach out on [slack](https://join.slack.com/t/suredbits/shared_invite/zt-eavycu0x-WQL7XOakzQo8tAy7jHHZUw),
|
||||
[gitter](https://gitter.im/bitcoin-s-core/) or [twitter](https://twitter.com/Chris_Stewart_5/)!
|
||||
|
||||
## Getting prebuilt artifacts
|
||||
|
||||
### Java binaries
|
||||
|
||||
<details>
|
||||
|
||||
#### Latest release
|
||||
|
||||
Please see the release page on github, you can find it [here](https://github.com/bitcoin-s/bitcoin-s/releases)
|
||||
|
||||
#### Master builds
|
||||
|
||||
We build installers for mac, linux and windows everytime a PR is merged to master.
|
||||
|
||||
You can find the latest builds at this link:
|
||||
|
||||
https://github.com/bitcoin-s/bitcoin-s/actions/workflows/release.yml
|
||||
|
||||
Here is what the installers look like
|
||||
|
||||
![installers](/img/doc-imgs/github-artifacts.png)
|
||||
|
||||
</details>
|
||||
|
||||
### Docker
|
||||
|
||||
<details>
|
||||
We publish docker images to docker hub on every PR merge and tag on github.
|
||||
You can obtain the images for both the app server and oracle server on these
|
||||
docker hub repos
|
||||
|
||||
[bitcoin-s-server docker hub repo](https://hub.docker.com/r/bitcoinscala/bitcoin-s-server/tags?page=1&ordering=last_updated)
|
||||
|
||||
[bitcoin-s-oracle-server docker hub repo](https://hub.docker.com/r/bitcoinscala/bitcoin-s-oracle-server/tags?page=1&ordering=last_updated)
|
||||
</details>
|
||||
|
||||
### Library jars
|
||||
|
||||
<details>
|
||||
Add this to your `build.sbt`:
|
||||
|
||||
```scala
|
||||
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-bitcoind-rpc" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-core" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-chain" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-dlc-oracle" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-eclair-rpc" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-fee-provider" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-key-manager" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-lnd-rpc" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-node" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-oracle-explorer-client" % "0.6.0"
|
||||
|
||||
libraryDependencies +="org.bitcoin-s" % "bitcoin-s-secp256k1jni" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit-core" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-wallet" % "0.6.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-zmq" % "0.6.0"
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Nightly builds
|
||||
|
||||
You can also run on the bleeding edge of Bitcoin-S, by
|
||||
adding a snapshot build to your `build.sbt`. The most
|
||||
recent snapshot published is `1.6.0-196-bc79a24f-SNAPSHOT`.
|
||||
|
||||
|
||||
|
||||
To fetch snapshots, you will need to add the correct
|
||||
resolver in your `build.sbt`:
|
||||
|
||||
```sbt
|
||||
resolvers += Resolver.sonatypeRepo("snapshots")
|
||||
```
|
||||
|
||||
The official maven repo for releases is
|
||||
|
||||
https://repo1.maven.org/maven2/org/bitcoin-s/
|
||||
|
||||
The repo for snapshots, which are published after everytime something is merged to master:
|
||||
|
||||
https://oss.sonatype.org/content/repositories/snapshots/org/bitcoin-s/
|
||||
|
||||
</details>
|
||||
|
||||
## Building JARs yourself
|
||||
|
||||
Please see [our setup docs](getting-setup.md)
|
||||
|
||||
## If you want to setup Bitcoin-S locally for development
|
||||
|
||||
Please see [our setup docs](getting-setup.md)
|
124
website/versioned_docs/version-1.7.0/key-manager/key-manager.md
Normal file
124
website/versioned_docs/version-1.7.0/key-manager/key-manager.md
Normal file
@ -0,0 +1,124 @@
|
||||
---
|
||||
id: version-1.7.0-key-manager
|
||||
title: Key Manager
|
||||
original_id: key-manager
|
||||
---
|
||||
|
||||
|
||||
### Key Manager
|
||||
|
||||
The key manager module's goal is to encapsulate all private key interactions with the [wallet](../wallet/wallet.md) project.
|
||||
|
||||
As of this writing, there is only one type of `KeyManager` - [`BIP39KeyManager`](/api/org/bitcoins/keymanager/bip39/BIP39KeyManager).
|
||||
|
||||
The [`BIP39KeyManager`](/api/org/bitcoins/keymanager/bip39/BIP39KeyManager) stores a [`MnemonicCode`](/api/org/bitcoins/core/crypto/MnemonicCode) on disk which can be decrypted and used as a hot wallet.
|
||||
|
||||
Over the long run, we want to make it so that the wallet project needs to communicate with the key-manager to access private keys.
|
||||
|
||||
This means that ALL SIGNING should be done inside of the key-manager, and private keys should not leave the key manager.
|
||||
|
||||
This makes it easier to reason about the security characteristics of our private keys, and a way to provide a uniform interface for alternative key storage systems (hsm, cloud based key storage, etc) to be plugged into the bitcoin-s library.
|
||||
|
||||
#### Creating a key manager
|
||||
|
||||
The first thing you need create a key manager is some entropy.
|
||||
|
||||
A popular way for bitcoin wallet's to represent entropy is [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) which you [can use in bitcoin-s](/api/org/bitcoins/core/crypto/BIP39Seed)
|
||||
|
||||
You can generate a `MnemonicCode` in bitcoin-s with the following code
|
||||
|
||||
```scala
|
||||
import org.bitcoins.core.crypto._
|
||||
|
||||
//get 256 bits of random entropy
|
||||
val entropy = MnemonicCode.getEntropy256Bits
|
||||
// entropy: scodec.bits.BitVector = BitVector(256 bits, 0x2a27d0b0e87fabb34b964e6182a04924c014a0d02ae3580c9fb301ffe293be2e)
|
||||
|
||||
val mnemonic = MnemonicCode.fromEntropy(entropy)
|
||||
// mnemonic: MnemonicCode = Masked(MnemonicCodeImpl)
|
||||
|
||||
//you can print that mnemonic seed with this
|
||||
println(mnemonic.words)
|
||||
// Vector(clay, direct, club, special, wide, super, comic, six, ghost, bench, banner, end, access, expire, doll, fragile, fix, gossip, under, advance, wreck, endorse, weather, spare)
|
||||
```
|
||||
|
||||
Now that we have a `MnemonicCode` that was securely generated, we need to now create `KeyManagerParams` which tells us how to generate
|
||||
generate specific kinds of addresses for wallets.
|
||||
|
||||
`KeyManagerParams` takes 3 parameters:
|
||||
|
||||
1. `seedPath` there is where we store the `MnemonicCode` on your file system
|
||||
2. [`purpose`](/api/org/bitcoins/core/hd/HDPurpose) which represents what type of utxo this `KeyManager` is associated with. The specification for this is in [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki)
|
||||
3. [`network`](/api/org/bitcoins/core/config/NetworkParameters) what cryptocurrency network this key manager is associated with
|
||||
|
||||
|
||||
This controls how the root key is defined. The combination of `purpose` and `network` determine how the root `ExtKey` is serialized. For more information on how this works please see [hd-keys](../core/hd-keys.md)
|
||||
|
||||
Now we can construct a native segwit key manager for the regtest network!
|
||||
|
||||
```scala
|
||||
//this will create a temp directory with the prefix 'key-manager-example` that will
|
||||
//have a file in it called "encrypted-bitcoin-s-seed.json"
|
||||
val seedPath = Files.createTempDirectory("key-manager-example").resolve(WalletStorage.ENCRYPTED_SEED_FILE_NAME)
|
||||
// seedPath: Path = /tmp/key-manager-example13670997372507832180/encrypted-bitcoin-s-seed.json
|
||||
|
||||
//let's create a native segwit key manager
|
||||
val purpose = HDPurposes.SegWit
|
||||
// purpose: HDPurpose = m/84'
|
||||
|
||||
//let's choose regtest as our network
|
||||
val network = RegTest
|
||||
// network: RegTest.type = RegTest
|
||||
|
||||
val kmParams = KeyManagerParams(seedPath, purpose, network)
|
||||
// kmParams: KeyManagerParams = KeyManagerParams(/tmp/key-manager-example13670997372507832180/encrypted-bitcoin-s-seed.json,m/84',RegTest)
|
||||
|
||||
val aesPasswordOpt = Some(AesPassword.fromString("password"))
|
||||
// aesPasswordOpt: Some[AesPassword] = Some(Masked(AesPassword))
|
||||
|
||||
val km = BIP39KeyManager.initializeWithMnemonic(aesPasswordOpt, mnemonic, None, kmParams)
|
||||
// km: Either[KeyManagerInitializeError, BIP39KeyManager] = Right(org.bitcoins.keymanager.bip39.BIP39KeyManager@3c0fcad9)
|
||||
|
||||
val rootXPub = km.right.get.getRootXPub
|
||||
// rootXPub: ExtPublicKey = vpub5SLqN2bLY4WeaRWAhPxQk2BdTBXf89Vpr6xRd56tq4FYFpt6nQgJzRZMXtVDpahGbqxLmX8neVcgLDbdGjXC3LbzcFna8GnRHnEwvYLMUPK
|
||||
|
||||
println(rootXPub)
|
||||
// vpub5SLqN2bLY4WeaRWAhPxQk2BdTBXf89Vpr6xRd56tq4FYFpt6nQgJzRZMXtVDpahGbqxLmX8neVcgLDbdGjXC3LbzcFna8GnRHnEwvYLMUPK
|
||||
```
|
||||
|
||||
Which should print something that looks like this
|
||||
|
||||
`vpub5SLqN2bLY4WeXxMqwJHJFBEwxSscGB2uDUnsTS3edVjZEwTrQDFDNqoR2xLqARQPabGaXsHSTenTRcqm2EnB9MpuC4vSk3LqSgNmGGZtuq7`
|
||||
|
||||
which is a native segwit `ExtPubKey` for the regtest network!
|
||||
|
||||
You can always change the `network` or `purpose` to support different things. You do _not_ need to initialize the key manager
|
||||
again after initializing it once. You can use the same `mnemonic` for different networks, which you control `KeyManagerParams`.
|
||||
|
||||
```scala
|
||||
//let's create a nested segwit key manager for mainnet
|
||||
val mainnetKmParams = KeyManagerParams(seedPath, HDPurposes.SegWit, MainNet)
|
||||
// mainnetKmParams: KeyManagerParams = KeyManagerParams(/tmp/key-manager-example13670997372507832180/encrypted-bitcoin-s-seed.json,m/84',MainNet)
|
||||
|
||||
//we do not need to all `initializeWithMnemonic()` again as we have saved the seed to dis
|
||||
val mainnetKeyManager = BIP39KeyManager.fromMnemonic(mnemonic, mainnetKmParams, None, Instant.now)
|
||||
// mainnetKeyManager: BIP39KeyManager = org.bitcoins.keymanager.bip39.BIP39KeyManager@6b64a92b
|
||||
|
||||
val mainnetXpub = mainnetKeyManager.getRootXPub
|
||||
// mainnetXpub: ExtPublicKey = zpub6jftahH18ngZycGe2q6uaNZe947StdTpWZ3JkegSM5m4UE91o3LZUgBuciKZpDJxEQRZmRX2V92ssN3t9XBFEHLQ5caGTv4NNgVXUw6Wiyb
|
||||
|
||||
println(mainnetXpub)
|
||||
// zpub6jftahH18ngZycGe2q6uaNZe947StdTpWZ3JkegSM5m4UE91o3LZUgBuciKZpDJxEQRZmRX2V92ssN3t9XBFEHLQ5caGTv4NNgVXUw6Wiyb
|
||||
```
|
||||
|
||||
Which gives us something that looks like this
|
||||
|
||||
`zpub6jftahH18ngZw98KGjRo5XcxeKTQ2eztsvskb1dC9XF5TLimQquTs6Ry7nBBA425D9joXmfgJJCexmJ1u2SELJZJfRi95gcnXadLpZzYb5c`
|
||||
|
||||
which is a p2sh wrapped segwit `ExtPubKey` for the bitcoin main network!
|
||||
|
||||
#### Creating a key manager from existing mnemonic
|
||||
|
||||
To create a `KeyManager` from existing mnemonic you need to specify the `seedPath` and then construct the `KeyManagerParams` that you would like.
|
||||
|
||||
Finally you call `KeyManager.fromParams()` that reads the mnemonic from disk and create's the key manager
|
143
website/versioned_docs/version-1.7.0/node/node.md
Normal file
143
website/versioned_docs/version-1.7.0/node/node.md
Normal file
@ -0,0 +1,143 @@
|
||||
---
|
||||
id: version-1.7.0-node
|
||||
title: Light Client
|
||||
original_id: node
|
||||
---
|
||||
|
||||
Bitcoin-s has node module that allows you to connect to the p2p network.
|
||||
|
||||
### Neutrino Node
|
||||
|
||||
Bitcoin-s has experimental support for neutrino which is a new lite client proposal on the bitcoin p2p network. You can
|
||||
read more about how neutrino works [here](https://suredbits.com/neutrino-what-is-it-and-why-we-need-it/). At this time,
|
||||
bitcoin-s only supports connecting to one trusted peer.
|
||||
|
||||
#### Limitations
|
||||
|
||||
Currently, the node does not have an active mempool.
|
||||
It is only aware of transactions it broadcasts and ones confirmed in blocks.
|
||||
|
||||
#### Callbacks
|
||||
|
||||
Bitcoin-S support call backs for the following events that happen on the bitcoin p2p network:
|
||||
|
||||
1. onTxReceived
|
||||
2. onBlockReceived
|
||||
3. onMerkleBlockReceived
|
||||
4. onCompactFilterReceived
|
||||
|
||||
That means every time one of these events happens on the p2p network, we will call your callback
|
||||
so that you can be notified of the event. These callbacks will be run after the message has been
|
||||
recieved and will execute sequentially. If any of them fail an error log will be output and the remainder of the callbacks will continue.
|
||||
Let's make an easy one
|
||||
|
||||
#### Example
|
||||
|
||||
Here is an example of constructing a neutrino node and registering a callback so you can be notified of an event.
|
||||
|
||||
To run the example, we need a bitcoind binary that has neutrino support.
|
||||
Bitcoin Core only has p2p neutrino support as of version 0.21.0.
|
||||
You will need to use a version of Bitcoin Core at least as old as 0.21.0.
|
||||
For your node to be able to service these filters you will need set
|
||||
`blockfilterindex=1` and `peerblockfilters=1` in your `bitcoin.conf` file.
|
||||
|
||||
|
||||
```scala
|
||||
implicit val system = ActorSystem(s"node-example")
|
||||
implicit val ec = system.dispatcher
|
||||
|
||||
//we also require a bitcoind instance to connect to
|
||||
//so let's start one (make sure you ran 'sbt downloadBitcoind')
|
||||
val instance = BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.Experimental))
|
||||
val p2pPort = instance.p2pPort
|
||||
val bitcoindF = BitcoindRpcTestUtil.startedBitcoindRpcClient(instance, Vector.newBuilder)
|
||||
|
||||
//contains information on how to connect to bitcoin's p2p info
|
||||
val peerF = bitcoindF.map(b => NodeUnitTest.createPeer(b))
|
||||
|
||||
// set a data directory
|
||||
val prefix = s"node-example-${System.currentTimeMillis()}"
|
||||
val datadir = Files.createTempDirectory(prefix)
|
||||
|
||||
val tmpDir = BitcoinSTestAppConfig.tmpDir()
|
||||
// set the current network to regtest
|
||||
val config = ConfigFactory.parseString {
|
||||
s"""
|
||||
| bitcoin-s {
|
||||
| network = regtest
|
||||
| node {
|
||||
| mode = neutrino # neutrino, spv
|
||||
|
|
||||
| peers = ["127.0.0.1:$p2pPort"] # a list of peer addresses in form "hostname:portnumber"
|
||||
| # (e.g. "neutrino.testnet3.suredbits.com:18333")
|
||||
| # Port number is optional, the default value is 8333 for mainnet,
|
||||
| # 18333 for testnet and 18444 for regtest.
|
||||
| }
|
||||
| }
|
||||
|""".stripMargin
|
||||
}
|
||||
|
||||
implicit val appConfig = BitcoinSAppConfig(datadir, config)
|
||||
implicit val chainConfig = appConfig.chainConf
|
||||
implicit val nodeConfig = appConfig.nodeConf
|
||||
|
||||
val initNodeF = nodeConfig.start()
|
||||
|
||||
//the node requires a chainHandler to store block information
|
||||
//use a helper method in our testkit to create the chain project
|
||||
val chainApiF = for {
|
||||
chainHandler <- ChainUnitTest.createChainHandler()
|
||||
} yield chainHandler
|
||||
|
||||
|
||||
//yay! All setup done, let's create a node and then start it!
|
||||
val nodeF = for {
|
||||
chainApi <- chainApiF
|
||||
peer <- peerF
|
||||
} yield {
|
||||
val dataMessageHandler = DataMessageHandler(chainApi)
|
||||
NeutrinoNode(nodePeer = peer,
|
||||
dataMessageHandler = dataMessageHandler,
|
||||
nodeConfig = nodeConfig,
|
||||
chainConfig = chainConfig,
|
||||
actorSystem = system)
|
||||
}
|
||||
|
||||
//let's start it
|
||||
val startedNodeF = nodeF.flatMap(_.start())
|
||||
|
||||
//let's make a simple callback that print's the
|
||||
//blockhash everytime we receive a block on the network
|
||||
val blockReceivedFunc: OnBlockReceived = { block: Block =>
|
||||
Future.successful(
|
||||
println(s"Received blockhash=${block.blockHeader.hashBE}"))
|
||||
}
|
||||
|
||||
// Create callback
|
||||
val nodeCallbacks = NodeCallbacks.onBlockReceived(blockReceivedFunc)
|
||||
|
||||
// Add call to our node's config
|
||||
nodeConfig.addCallbacks(nodeCallbacks)
|
||||
|
||||
//let's test it out by generating a block with bitcoind!
|
||||
|
||||
val genBlockF = for {
|
||||
bitcoind <- bitcoindF
|
||||
addr <- bitcoind.getNewAddress
|
||||
hashes <- bitcoind.generateToAddress(1,addr)
|
||||
} yield hashes
|
||||
|
||||
//you should see our callback print a block hash
|
||||
//when running this code
|
||||
|
||||
//cleanup
|
||||
val cleanupF = for {
|
||||
_ <- genBlockF
|
||||
bitcoind <- bitcoindF
|
||||
node <- startedNodeF
|
||||
x = NeutrinoNodeConnectedWithBitcoind(node.asInstanceOf[NeutrinoNode],bitcoind)
|
||||
_ <- NodeUnitTest.destroyNodeConnectedWithBitcoind(x)
|
||||
} yield ()
|
||||
|
||||
Await.result(cleanupF, 60.seconds)
|
||||
```
|
189
website/versioned_docs/version-1.7.0/oracle/oracle-server.md
Normal file
189
website/versioned_docs/version-1.7.0/oracle/oracle-server.md
Normal file
@ -0,0 +1,189 @@
|
||||
---
|
||||
id: version-1.7.0-oracle-server
|
||||
title: Oracle Server
|
||||
original_id: oracle-server
|
||||
---
|
||||
|
||||
The Oracle Server is a DLC Oracle with functionality for creating events and attesting to them.
|
||||
You can interact with the oracle server with `bitcoin-s-cli` or `curl`
|
||||
|
||||
The following a guide is for interacting with the oracle
|
||||
If you are looking for the documentation on how to build the oracle server,
|
||||
checkout [this page](build-oracle-server.md).
|
||||
|
||||
## Server Endpoints
|
||||
|
||||
- `getpublickey` - Get oracle's public key
|
||||
- `getstakingaddress` - Get oracle's staking address
|
||||
- `listevents` - Lists all event names
|
||||
- `createenumevent` `label` `maturationtime` `outcomes` - Registers an oracle enum event
|
||||
- `label` - Label for this event
|
||||
- `maturationtime` - The earliest expected time an outcome will be signed, given in ISO 8601 format
|
||||
- `outcomes` - Possible outcomes for this event
|
||||
- `createnumericevent` `name` `maturationtime` `minvalue` `maxvalue` `unit` `precision` - Registers an oracle event that uses digit decomposition when signing the number
|
||||
- `name`- Name for this event
|
||||
- `maturationtime` - The earliest expected time an outcome will be signed, given in ISO 8601 format
|
||||
- `minvalue` - Minimum value of this event
|
||||
- `maxvalue` - Maximum value of this event
|
||||
- `unit` - The unit denomination of the outcome value
|
||||
- `precision` - The precision of the outcome representing the base exponent by which to multiply the number represented by the composition of the digits to obtain the actual outcome value.
|
||||
- `createdigitdecompevent` `name` `maturationtime` `base` `numdigits` `unit` `precision` `[signed]` - Registers an oracle event that uses digit decomposition when signing the number
|
||||
- `name`- Name for this event
|
||||
- `maturationtime` - The earliest expected time an outcome will be signed, given in epoch second
|
||||
- `base` - The base in which the outcome value is decomposed
|
||||
- `numdigits` - The max number of digits the outcome can have
|
||||
- `unit` - The unit denomination of the outcome value
|
||||
- `precision` - The precision of the outcome representing the base exponent by which to multiply the number represented by the composition of the digits to obtain the actual outcome value.
|
||||
- `--signed`- Whether the outcomes can be negative
|
||||
- `getevent` `event` - Get an event's details
|
||||
- `eventName` - The event's name
|
||||
- `signevent` `event` `outcome` - Signs an event
|
||||
- `eventName` - The event's name
|
||||
- `outcome`- Outcome to sign for this event
|
||||
- `signdigits` `event` `outcome` - Signs an event
|
||||
- `eventName` - The event's name
|
||||
- `outcome` - Number to sign for this event
|
||||
- `getsignatures` `event` - Get the signatures from a signed event
|
||||
- `eventName` - The event's name
|
||||
- `signmessage` `message` - Signs the SHA256 hash of the given string using the oracle's signing key
|
||||
- `message` - Message to hash and sign
|
||||
|
||||
### Create Event Example
|
||||
|
||||
Bitcoin-S CLI:
|
||||
```bash
|
||||
$ bitcoin-s-cli createenumevent test "2030-01-03T00:30:00.000Z" "outcome1,outcome2,outcome3"
|
||||
fdd824b0ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb905f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374
|
||||
|
||||
$ bitcoin-s-cli getevent test
|
||||
{
|
||||
"nonces": [
|
||||
"80e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f"
|
||||
],
|
||||
"eventName": "test",
|
||||
"signingVersion": "DLCOracleV0SigningVersion",
|
||||
"maturationTime": "2030-01-03T00:30:00.000Z",
|
||||
"announcementSignature": "ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb90",
|
||||
"eventDescriptorTLV": "fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d6533",
|
||||
"eventTLV": "fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374",
|
||||
"announcementTLV": "fdd824b0ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb905f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374",
|
||||
"attestations": null,
|
||||
"signatures": null,
|
||||
"outcomes": [
|
||||
"outcome1",
|
||||
"outcome2",
|
||||
"outcome3"
|
||||
],
|
||||
"signedOutcome": null
|
||||
}
|
||||
|
||||
|
||||
$ bitcoin-s-cli signevent test "outcome1"
|
||||
fdd8687004746573745f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e086f7574636f6d6531
|
||||
|
||||
$ bitcoin-s-cli getsignatures test
|
||||
fdd8687004746573745f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e086f7574636f6d6531
|
||||
```
|
||||
|
||||
CURL:
|
||||
```bash
|
||||
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "createenumevent", "params": ["testEvent", ""2030-01-03T00:30:00.000Z"", ["outcome1", "outcome2", "outcome3"]]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
|
||||
{"result":"fdd824b0ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb905f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374","error":null}
|
||||
|
||||
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getevent", "params": ["testEvent"]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
|
||||
{"result":{"nonces":["80e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f"],"eventName":"test","signingVersion":"DLCOracleV0SigningVersion","maturationTime":"2030-01-03T00:30:00.000Z","announcementSignature":"ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb90","eventDescriptorTLV":"fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d6533","eventTLV":"fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374","announcementTLV":"fdd824b0ba0f08e9becbf77019e246ca8a80c027585634dc1aed4b7f67442ada394b40dcb242d8a8c84893a752b93f30ff07525b0604382255ec7392fcc6f230140feb905f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd8224c000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f657131d1fdd8061d0003086f7574636f6d6531086f7574636f6d6532086f7574636f6d65330474657374","attestations":["33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e"],"signatures":["80e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e"],"outcomes":["outcome1","outcome2","outcome3",],"signedOutcome": null},"error":null}
|
||||
|
||||
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "signevent", "params": ["testEvent", "outcome1"]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
|
||||
{"result":"fdd8687004746573745f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e086f7574636f6d6531","error":null}
|
||||
|
||||
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getsignatures", "params": ["testEvent"]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
|
||||
{"result":["fdd8687004746573745f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115000180e550759cb6275f6db3fad2b616ed51bdcccc204d0d978cd921cafae9fc1d6f33fd84ba8eea0a75f1568149f42e8466e1bc3422ea449532d4eeffad8586d14e086f7574636f6d6531"],"error":null}
|
||||
```
|
||||
|
||||
### Numeric Example
|
||||
|
||||
Bitcoin-S CLI:
|
||||
|
||||
```bash
|
||||
$ bitcoin-s-cli createnumericevent exampleNumeric "2030-01-03T00:30:00.000Z" -1000 1000 "units" 0
|
||||
fdd824fd010bfc52dab25169eef25815c795128f38ef3b89bc7f53d1d788b4a1c544e5bebfbf6799975b62a1888e2d77445b6d002672f52f8626b1ea6cc6cd974a8039d28a9f5f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd822a70004012d73a453bb630fe355830a81727cf2fb10c41ccfee040c529a4dec21ca5071f5aff60ac9ef8425ae438e84a6f067952d60b947e9e44bfc6e8fd89b781492057b1db5da37f1c10bfcaf7a4fb0e9f6dbb8d25dfed7a25241bbec3c0a60a40d2949305ff92f679598a11e7a857beef901903fc83624413831a06513da577cdd66657131d1fdd80a0f000a0105756e6974730000000000030d6578616d706c654465636f6d70
|
||||
|
||||
$ bitcoins-cli getevent exampleNumeric
|
||||
{
|
||||
"nonces": [
|
||||
"012d73a453bb630fe355830a81727cf2fb10c41ccfee040c529a4dec21ca5071",
|
||||
"49305ff92f679598a11e7a857beef901903fc83624413831a06513da577cdd66",
|
||||
"7b1db5da37f1c10bfcaf7a4fb0e9f6dbb8d25dfed7a25241bbec3c0a60a40d29",
|
||||
"f5aff60ac9ef8425ae438e84a6f067952d60b947e9e44bfc6e8fd89b78149205"
|
||||
],
|
||||
"eventName": "exampleNumeric",
|
||||
"signingVersion": "DLCOracleV0SigningVersion",
|
||||
"maturationTime": "2030-01-03T00:30:00.000Z",
|
||||
"announcementSignature": "fc52dab25169eef25815c795128f38ef3b89bc7f53d1d788b4a1c544e5bebfbf6799975b62a1888e2d77445b6d002672f52f8626b1ea6cc6cd974a8039d28a9f",
|
||||
"eventDescriptorTLV": "fdd80a0f000a0105756e697473000000000003",
|
||||
"eventTLV": "fdd822a70004012d73a453bb630fe355830a81727cf2fb10c41ccfee040c529a4dec21ca507149305ff92f679598a11e7a857beef901903fc83624413831a06513da577cdd667b1db5da37f1c10bfcaf7a4fb0e9f6dbb8d25dfed7a25241bbec3c0a60a40d29f5aff60ac9ef8425ae438e84a6f067952d60b947e9e44bfc6e8fd89b78149205657131d1fdd80a0f000a0105756e6974730000000000030d6578616d706c654465636f6d70",
|
||||
"announcementTLV": "fdd824fd010bfc52dab25169eef25815c795128f38ef3b89bc7f53d1d788b4a1c544e5bebfbf6799975b62a1888e2d77445b6d002672f52f8626b1ea6cc6cd974a8039d28a9f5f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd822a70004012d73a453bb630fe355830a81727cf2fb10c41ccfee040c529a4dec21ca507149305ff92f679598a11e7a857beef901903fc83624413831a06513da577cdd667b1db5da37f1c10bfcaf7a4fb0e9f6dbb8d25dfed7a25241bbec3c0a60a40d29f5aff60ac9ef8425ae438e84a6f067952d60b947e9e44bfc6e8fd89b78149205657131d1fdd80a0f000a0105756e6974730000000000030d6578616d706c654465636f6d70",
|
||||
"attestations": null,
|
||||
"signatures": null,
|
||||
"outcomes": [
|
||||
[
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9"
|
||||
],
|
||||
[
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9"
|
||||
],
|
||||
[
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9"
|
||||
],
|
||||
[
|
||||
"+",
|
||||
"-"
|
||||
]
|
||||
],
|
||||
"signedOutcome": null
|
||||
}
|
||||
|
||||
|
||||
$ bitcoin-s-cli signdigits exampleNumeric 123
|
||||
fdd868fd01380d6578616d706c654465636f6d705f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e521150004012d73a453bb630fe355830a81727cf2fb10c41ccfee040c529a4dec21ca5071a853a189b9acffa2488542c4998261866ce392dbf38031509ceff34077431e65f5aff60ac9ef8425ae438e84a6f067952d60b947e9e44bfc6e8fd89b78149205773713008d316640b74d04f180b6c3c09b8de11b29cd7474681a7ad869857cd57b1db5da37f1c10bfcaf7a4fb0e9f6dbb8d25dfed7a25241bbec3c0a60a40d294f2222871b23a823acbfa552478ae3d526377a8918b346d6e206156c3e5a2c8549305ff92f679598a11e7a857beef901903fc83624413831a06513da577cdd66c03ed28ef6f7b0f48f974b61811a571652ea2eafda5fd5b244674420deb294e8012b013101320133
|
||||
```
|
||||
|
||||
CURL:
|
||||
|
||||
```bash
|
||||
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "createnumericevent", "params": ["numericExample", "2030-01-03T00:30:00.000Z", -1000, 1000, "units", 0]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
|
||||
{"result":"fdd824fd0110647c85d333aa6fc0d7808201da9d1010b815710dc25c3d73e9cc7a7f372a7342c99144ba74d70be72920f4515daa6565bce12aedfc5a828ee37b5453454c1b575f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd822ac0004d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf37051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c47446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd4756217139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d2657131d1fdd80a0f000a0105756e697473000000000003126578616d706c6544696769744465636f6d70","error":null}
|
||||
|
||||
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getevent", "params": ["numericExample"]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
|
||||
{"result":{"nonces":["7051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c4","7139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d2","7446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621","d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3"],"eventName":"numericExample","signingVersion":"DLCOracleV0SigningVersion","maturationTime":"2030-01-03T00:30:00.000Z","announcementSignature":"647c85d333aa6fc0d7808201da9d1010b815710dc25c3d73e9cc7a7f372a7342c99144ba74d70be72920f4515daa6565bce12aedfc5a828ee37b5453454c1b57","eventDescriptorTLV":"fdd80a0f000a0105756e697473000000000003","eventTLV":"fdd822ac00047051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c47139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d27446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3657131d1fdd80a0f000a0105756e697473000000000003126578616d706c6544696769744465636f6d70","announcementTLV":"fdd824fd0110647c85d333aa6fc0d7808201da9d1010b815710dc25c3d73e9cc7a7f372a7342c99144ba74d70be72920f4515daa6565bce12aedfc5a828ee37b5453454c1b575f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e52115fdd822ac00047051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c47139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d27446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3657131d1fdd80a0f000a0105756e697473000000000003126578616d706c6544696769744465636f6d70","attestations":null,"signatures":null,"outcomes":[["0","1","2","3","4","5","6","7","8","9"],["0","1","2","3","4","5","6","7","8","9"],["0","1","2","3","4","5","6","7","8","9"],["+","-"]],"signedOutcome": null},"error":null}
|
||||
|
||||
$ curl --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "signdigits", "params": ["numericExample", 123]}' -H "Content-Type: application/json" http://127.0.0.1:9998/
|
||||
{"result":"fdd868fd013d126578616d706c6544696769744465636f6d705f6f49e116de8cb57856bacdd9997d8dfb73877f64a4ec8d45fc0e73a0e521150004d72282a2e9532924dc8cd79685a501202332ad0d118166328cb76138414fccf3d0646c9efd9523274014841ba24bf63219d5650d1682209d7e48af009d58e6d87051e50fd1ab30df4717da8905e400a32c5f4d793a4ac5433ed416165dd286c4c025dfd1e39de77e0418fa7d39abf2e9daf55d7fe34f8e312368cb4d45b4d4b97446ab1d71a550a0d604c3e86c40a3c9b12de8f08a86639068707822cd475621700347c52af088eda9a0245385094518134e73bb997102e11f6de0aeb36af7237139d7cabd19d6b0b9e827cdf84a4fc18c88d1882e4e096d8dfeff58759504d2f9e7a9e183b0836ad58dd646d9ab123132397109e4f51c5842958932a81bacd1012b013101320133","error":null}
|
||||
```
|
133
website/versioned_docs/version-1.7.0/rpc/bitcoind.md
Normal file
133
website/versioned_docs/version-1.7.0/rpc/bitcoind.md
Normal file
@ -0,0 +1,133 @@
|
||||
---
|
||||
id: version-1.7.0-rpc-bitcoind
|
||||
title: bitcoind/Bitcoin Core
|
||||
original_id: rpc-bitcoind
|
||||
---
|
||||
|
||||
## Downloading bitcoind
|
||||
|
||||
The Bitcoin Core RPC client in Bitcoin-S currently supports the Bitcoin Core
|
||||
- 0.16
|
||||
- 0.17
|
||||
- 0.18
|
||||
- 0.19
|
||||
- 0.20
|
||||
- 0.21
|
||||
|
||||
version lines. It can be set up to work with both local and remote Bitcoin Core servers.
|
||||
|
||||
You can fetch them using bitcoin-s by running the following sbt command. If you already have bitcoind installed on your machine, you can skip this step.
|
||||
|
||||
|
||||
```bash
|
||||
sbt downloadBitcoind
|
||||
```
|
||||
|
||||
The binaries will be stored in `~/.bitcoin-s/binaries/bitcoind/`
|
||||
|
||||
|
||||
## Connecting to a local `bitcoind` instance
|
||||
|
||||
### Getting started quickly, with default options:
|
||||
|
||||
```scala
|
||||
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
|
||||
```
|
||||
|
||||
## Multi-wallet `bitcoind` instances
|
||||
|
||||
When using the `bitcoind` with multiple wallets you will need to specify the wallet's name.
|
||||
To do so the wallet rpc functions have an optional `walletName` parameter.
|
||||
|
||||
```scala
|
||||
implicit val ec: ExecutionContext = ExecutionContext.global
|
||||
|
||||
val client = BitcoindRpcClient.fromDatadir(binary=new File("/path/to/bitcoind"), datadir=new File("/path/to/bitcoind-datadir"))
|
||||
|
||||
for {
|
||||
_ <- client.start()
|
||||
_ <- client.walletPassphrase("mypassword", 10000, Some("walletName"))
|
||||
balance <- client.getBalance("walletName")
|
||||
} yield balance
|
||||
```
|
||||
|
||||
## Connecting to a remote `bitcoind`
|
||||
|
||||
First, we create a secure connection to our `bitcoind` instance by setting
|
||||
up a SSH tunnel:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```scala
|
||||
implicit val ec: ExecutionContext = ExecutionContext.global
|
||||
|
||||
val username = "FILL_ME_IN" //this username comes from 'rpcuser' in your bitcoin.conf file //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 //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
|
||||
)
|
||||
}
|
||||
|
||||
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`](https://github.com/bitcoin-s/bitcoin-s/blob/master/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/BitcoindException.scala).
|
||||
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:
|
||||
|
||||
```scala
|
||||
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 = BitcoinAddress("bc1qm8kec4xvucdgtzppzvvr2n6wp4m4w0k8akhf98")
|
||||
|
||||
val txid: Future[DoubleSha256DigestBE] =
|
||||
cli.sendToAddress(address, 3.bitcoins).recoverWith {
|
||||
case BitcoindWalletException.UnlockNeeded(_) =>
|
||||
cli.walletPassphrase("my_passphrase", 60).flatMap { _ =>
|
||||
cli.sendToAddress(address, 3.bitcoins)
|
||||
}
|
||||
}
|
||||
```
|
60
website/versioned_docs/version-1.7.0/rpc/lnd.md
Normal file
60
website/versioned_docs/version-1.7.0/rpc/lnd.md
Normal file
@ -0,0 +1,60 @@
|
||||
---
|
||||
id: version-1.7.0-lnd-rpc
|
||||
title: LND
|
||||
original_id: lnd-rpc
|
||||
---
|
||||
|
||||
This is an RPC client for [LND](https://github.com/LightningNetwork/lnd). It assumes that a bitcoind instance is running.
|
||||
|
||||
Currently, this RPC client is written for [v0.13.0](https://github.com/lightningnetwork/lnd/releases/tag/v0.13.0-beta) version of LND.
|
||||
|
||||
## Configuration of LND
|
||||
|
||||
Please see the [sample configuration for LND](https://github.com/lightningnetwork/lnd/blob/v0.13.0-beta/sample-lnd.conf).
|
||||
|
||||
You can find the configuration we use for our testing infrastructure for lnd [here](https://github.com/bitcoin-s/bitcoin-s/blob/656e0928bf1bf4f511f60dec625699b454f29a1f/testkit/src/main/scala/org/bitcoins/testkit/lnd/LndRpcTestUtil.scala#L90).
|
||||
|
||||
## Starting LND
|
||||
|
||||
You need to download the binaries from the [LND's github](https://github.com/lightningnetwork/lnd/releases/tag/v0.13.0-beta).
|
||||
|
||||
To run lnd by unzipping the `lnd-linux-amd64-v0.13.0-beta.tar.gz` (or whichever platform you are on) and then running
|
||||
|
||||
```bash
|
||||
$ ./lnd-linux-amd64-v0.13.0-beta/lnd
|
||||
```
|
||||
|
||||
If you wish to start lnd from the RPC client, you can construct a [`LndRpcClient.binary`](https://github.com/bitcoin-s/bitcoin-s/blob/656e0928bf1bf4f511f60dec625699b454f29a1f/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/LndRpcClient.scala#L35) field set
|
||||
|
||||
We will default to using the `binary` field first when trying to start the jar, and the fallback to the default datadir (`~/.lnd`).
|
||||
|
||||
Here is an example of how to start lnd:
|
||||
|
||||
|
||||
```scala
|
||||
implicit val system = ActorSystem(s"lnd-rpc-${System.currentTimeMillis}")
|
||||
implicit val ec = system.dispatcher
|
||||
|
||||
val datadirPath = Paths.get("path", "to", "datadir")
|
||||
val binaryPath = Paths.get("path", "to", "lnd-linux-amd64-v0.13.0-beta", "lnd")
|
||||
val instance = LndInstance.fromDataDir(datadirPath.toFile)
|
||||
val client = new LndRpcClient(instance, Some(binaryPath.toFile))
|
||||
|
||||
val startedF = client.start()
|
||||
|
||||
for {
|
||||
lnd <- startedF
|
||||
info <- lnd.getInfo
|
||||
} yield {
|
||||
println(s"Lnd info: $info")
|
||||
}
|
||||
```
|
||||
|
||||
### Updating to a new LND version
|
||||
|
||||
The lnd rpc module uses lnd's gRPC. This means when updating to the latest version, the `.proto` files will need to be updated.
|
||||
Bitcoin-S stores them in [lnd-rpc/src/main/protobuf](https://github.com/bitcoin-s/bitcoin-s/tree/master/lnd-rpc/src/main/protobuf).
|
||||
You can find the files to copy from LND [here](https://github.com/lightningnetwork/lnd/tree/master/lnrpc).
|
||||
|
||||
After updating the `proto` files you can run `sbt compile` and this will generate the corresponding class files, this should then give
|
||||
compile warnings for changed rpc functions.
|
92
website/versioned_docs/version-1.7.0/secp256k1/secp256k1.md
Normal file
92
website/versioned_docs/version-1.7.0/secp256k1/secp256k1.md
Normal file
@ -0,0 +1,92 @@
|
||||
---
|
||||
id: version-1.7.0-secp256k1
|
||||
title: Secp256k1
|
||||
original_id: secp256k1
|
||||
---
|
||||
|
||||
[Libsecp256k1](https://github.com/bitcoin-core/secp256k1) is used to preform cryptographic operations on the secp256k1 curve.
|
||||
This is the curve that bitcoin uses. There is a _signficant_ speedup when using this library compared to java crypto libraries
|
||||
like bouncy castle.
|
||||
|
||||
In bitcoin-s, we support native binaries for libsecp256k1
|
||||
|
||||
1. [linux 32 bit](../../secp256k1jni/natives/linux_32)
|
||||
2. [linux 64 bit](../../secp256k1jni/natives/linux_64)
|
||||
3. [mac osx 64 bit](../../secp256k1jni/natives/osx_64)
|
||||
4. [windows 64 bit](../../secp256k1jni/natives/windows_64)
|
||||
|
||||
Bitcoin-s uses a zero dependency library called [`native-lib-loader`](https://github.com/scijava/native-lib-loader).
|
||||
That does the appropriate loading of the library onto your classpath to be accessed.
|
||||
|
||||
### Using libsecp256k1
|
||||
|
||||
To tell if you have access to libsecp256k1 you can do the following
|
||||
|
||||
|
||||
```scala
|
||||
val isEnabled = org.bitcoin.Secp256k1Context.isEnabled()
|
||||
|
||||
println(s"Secp256k1Context.isEnabled=${isEnabled}")
|
||||
```
|
||||
|
||||
If libsecp256k1 is enabled, you can use [NativeSecp256k1](/api/org/bitcoin/NativeSecp256k1)
|
||||
with static method defined in the class.
|
||||
|
||||
|
||||
```scala
|
||||
val privKey = ECPrivateKey.freshPrivateKey
|
||||
val pubKey = privKey.publicKey
|
||||
val dataToSign = DoubleSha256Digest.empty
|
||||
|
||||
val signature = NativeSecp256k1.sign(dataToSign.bytes.toArray, privKey.bytes.toArray)
|
||||
|
||||
val verify = NativeSecp256k1.verify(dataToSign.bytes.toArray, signature, pubKey.bytes.toArray)
|
||||
|
||||
println(s"Verified with NativeSecp256k1 signature=${verify}")
|
||||
|
||||
//you can also just directly sign with the ECKey interface:
|
||||
val signature2 = privKey.sign(dataToSign)
|
||||
|
||||
val verified2 = pubKey.verify(dataToSign, signature2)
|
||||
|
||||
println(s"Verified with NativeSecp256k1 again=${verified2}")
|
||||
```
|
||||
|
||||
### When libsecp256k1 isn't available, or you want to turn it off
|
||||
|
||||
There are two reasons you wouldn't want to use libsecp256k1
|
||||
|
||||
1. You don't trust the pre-compiled binaries we are using
|
||||
2. Your OS/arch is not supported
|
||||
|
||||
There are two ways you can circumvent libsecp256k1
|
||||
|
||||
1. Set `DISABLE_SECP256K1=true` in your environment variables. This will force `CryptoContext.default` to return false which will make Bitcoin-S act like `Secp256k1Context.isEnabled()` has returned false.
|
||||
2. Call Bouncy castle methods in `ECKey`.
|
||||
|
||||
Here is an example of calling bouncy castle methods in `ECKey`
|
||||
|
||||
```scala
|
||||
val privKey = ECPrivateKey.freshPrivateKey
|
||||
// privKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||
// calls bouncy castle indirectly via CryptoContext
|
||||
val publicKey = privKey.publicKey
|
||||
// publicKey: ECPublicKey = ECPublicKey(03f93041b489939ff360d5b639c099900413fc28b016b4f2904530e67238a3349f)
|
||||
val dataToSign = DoubleSha256Digest.empty
|
||||
// dataToSign: DoubleSha256Digest = DoubleSha256Digest(0000000000000000000000000000000000000000000000000000000000000000)
|
||||
|
||||
// calls bouncy castle indirectly via CryptoContext
|
||||
val signature = privKey.sign(dataToSign.bytes)
|
||||
// signature: ECDigitalSignature = ECDigitalSignature(3045022100a170c11306dd2e0a8791f30aaffa839cb50697f4fbb36f498b3372f4ee1b90d10220152ac19d50bb6f92ed24bae6d00cfd1fcb8d4e50531a1d811ba70b1a114d293c)
|
||||
|
||||
// calls bouncy castle indirectly via CryptoContext
|
||||
val verified = publicKey.verify(dataToSign.bytes, signature)
|
||||
// verified: Boolean = true
|
||||
|
||||
println(s"Verified with bouncy castle=${verified}")
|
||||
// Verified with bouncy castle=true
|
||||
```
|
||||
|
||||
### Building libsecp256k1
|
||||
|
||||
[See instructions here](add-to-jni.md#adding-to-bitcoin-s)
|
173
website/versioned_docs/version-1.7.0/testkit/testkit.md
Normal file
173
website/versioned_docs/version-1.7.0/testkit/testkit.md
Normal file
@ -0,0 +1,173 @@
|
||||
---
|
||||
id: version-1.7.0-testkit
|
||||
title: Testkit
|
||||
original_id: testkit
|
||||
---
|
||||
|
||||
## Philosophy of Testkit
|
||||
|
||||
The high level of of the bitcoin-s testkit is to mimic and provide functionality to test 3rd party applications.
|
||||
|
||||
There are other examples of these in the Scala ecosystem like the `akka-testkit` and `slick-testkit`.
|
||||
|
||||
We use this testkit to test bitcoin-s it self.
|
||||
|
||||
|
||||
### Testkit for bitcoind
|
||||
|
||||
This gives the ability to create and destroy `bitcoind` on the underlying operating system to test against.
|
||||
|
||||
Make sure you have run `sbt downloadBitcoind` before running this example, as you need access to the bitcoind binaries.
|
||||
|
||||
Our [BitcoindRpcClient](/api/org/bitcoins/rpc/client/common/BitcoindRpcClient) is tested with the functionality provided in the testkit.
|
||||
A quick example of a useful utility method is [BitcoindRpcTestUtil.startedBitcoindRpcClient()](/api/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil).
|
||||
This spins up a bitcoind regtest instance on machine and generates 101 blocks on that node.
|
||||
|
||||
This gives you the ability to start spending money immediately with that bitcoind node.
|
||||
|
||||
```scala
|
||||
implicit val system = ActorSystem("bitcoind-testkit-example")
|
||||
implicit val ec = system.dispatcher
|
||||
|
||||
//pick our bitcoind version we want to spin up
|
||||
//you can pick older versions if you want
|
||||
//we support versions 16-19
|
||||
val bitcoindV = BitcoindVersion.V19
|
||||
|
||||
//create an instance
|
||||
val instance = BitcoindRpcTestUtil.instance(versionOpt = Some(bitcoindV))
|
||||
|
||||
//now let's create an rpc client off of that instance
|
||||
val bitcoindRpcClientF = BitcoindRpcTestUtil.startedBitcoindRpcClient(instance, Vector.newBuilder)
|
||||
|
||||
//yay! it's started. Now you can run tests against this.
|
||||
//let's just grab the block count for an example
|
||||
val blockCountF = for {
|
||||
bitcoind <- bitcoindRpcClientF
|
||||
count <- bitcoind.getBlockCount
|
||||
} yield {
|
||||
//run a test against the block count
|
||||
assert(count > 0, s"Block count was not more than zero!")
|
||||
}
|
||||
|
||||
//when you are done, don't forget to destroy it! Otherwise it will keep running on the underlying os
|
||||
val stoppedF = for {
|
||||
rpc <- bitcoindRpcClientF
|
||||
_ <- blockCountF
|
||||
stopped <- BitcoindRpcTestUtil.stopServers(Vector(rpc))
|
||||
} yield stopped
|
||||
```
|
||||
|
||||
For more information on how the bitcoind rpc client works, see our [bitcoind rpc docs](../rpc/bitcoind.md)
|
||||
|
||||
#### Caching bitcoind in test cases
|
||||
|
||||
When doing integration tests with bitcoind, you likely do not want to spin up a
|
||||
new bitcoind for _every_ test that is run.
|
||||
|
||||
Not to fear, when using `testkit` you can use our bitcoind fixtures for your unit tests!
|
||||
These will only spin up on bitcoind per test suite, rather than one bitcoind per test.
|
||||
|
||||
We currently have two types of fixtures available to users of this dependency
|
||||
|
||||
1. [Connected pairs of bitcoind nodes](https://github.com/bitcoin-s/bitcoin-s/blob/eaac9c154c25f3bd76615ea2151092f06df6bdb4/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala#L282)
|
||||
2. [Bitcoind nodes with funded wallets](https://github.com/bitcoin-s/bitcoin-s/blob/eaac9c154c25f3bd76615ea2151092f06df6bdb4/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala#L161)
|
||||
|
||||
If you mixin either of those traits for your test, you will now have access to the corresponding fixture.
|
||||
|
||||
You can find an examples of how to use these two test fixtures
|
||||
|
||||
1. [Example of using a connected pair of nodes in test suite](https://github.com/bitcoin-s/bitcoin-s/blob/32a6db930bdf849a94d92cd1de160b87845ab168/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala#L37)
|
||||
2. [Example of using a bitcoind with funded wallet in test suite](https://github.com/bitcoin-s/bitcoin-s/blob/eaac9c154c25f3bd76615ea2151092f06df6bdb4/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala#L161)
|
||||
|
||||
|
||||
### Testkit for eclair
|
||||
|
||||
We have similar utility methods for eclair. Eclair's testkit requires a bitcoind running (which we can spin up thanks to our bitcoind testkit).
|
||||
|
||||
Here is an example of spinning up an eclair lightning node, that is connected to a bitcoind and testing your lightning application.
|
||||
|
||||
Make sure to run `sbt downloadBitcoind downloadEclair` before running this so you have access to the underlying eclair binares
|
||||
|
||||
```scala
|
||||
//Steps:
|
||||
//1. Open and confirm channel on the underlying blockchain (regtest)
|
||||
//2. pay an invoice
|
||||
//3. Await until the payment is processed
|
||||
//4. assert the node has received the payment
|
||||
//5. cleanup
|
||||
|
||||
implicit val system = ActorSystem("eclair-testkit-example")
|
||||
implicit val ec = system.dispatcher
|
||||
|
||||
//we need a bitcoind to connect eclair nodes to
|
||||
lazy val bitcoindRpcClientF: Future[BitcoindRpcClient] = {
|
||||
for {
|
||||
cli <- EclairRpcTestUtil.startedBitcoindRpcClient()
|
||||
// make sure we have enough money to open channels
|
||||
address <- cli.getNewAddress
|
||||
_ <- cli.generateToAddress(200, address)
|
||||
} yield cli
|
||||
}
|
||||
|
||||
//let's create two eclair nodes now
|
||||
val clientF = for {
|
||||
bitcoind <- bitcoindRpcClientF
|
||||
e <- EclairRpcTestUtil.randomEclairClient(Some(bitcoind))
|
||||
} yield e
|
||||
|
||||
val otherClientF = for {
|
||||
bitcoind <- bitcoindRpcClientF
|
||||
e <- EclairRpcTestUtil.randomEclairClient(Some(bitcoind))
|
||||
} yield e
|
||||
|
||||
//great, setup done! Let's run the test
|
||||
//to verify we can send a payment over the channel
|
||||
for {
|
||||
client <- clientF
|
||||
otherClient <- otherClientF
|
||||
_ <- EclairRpcTestUtil.openAndConfirmChannel(clientF, otherClientF)
|
||||
invoice <- otherClient.createInvoice("abc", 50.msats)
|
||||
info <- otherClient.getInfo
|
||||
_ = assert(info.nodeId == invoice.nodeId)
|
||||
infos <- client.getSentInfo(invoice.lnTags.paymentHash.hash)
|
||||
_ = assert(infos.isEmpty)
|
||||
paymentId <- client.payInvoice(invoice)
|
||||
_ <- EclairRpcTestUtil.awaitUntilPaymentSucceeded(client, paymentId)
|
||||
sentInfo <- client.getSentInfo(invoice.lnTags.paymentHash.hash)
|
||||
} yield {
|
||||
assert(sentInfo.head.amount == 50.msats)
|
||||
}
|
||||
|
||||
//don't forget to shutdown everything!
|
||||
val stop1F = clientF.map(c => EclairRpcTestUtil.shutdown(c))
|
||||
|
||||
val stop2F = otherClientF.map(o => EclairRpcTestUtil.shutdown(o))
|
||||
|
||||
val stoppedBitcoindF = for {
|
||||
bitcoind <- bitcoindRpcClientF
|
||||
_ <- BitcoindRpcTestUtil.stopServers(Vector(bitcoind))
|
||||
} yield ()
|
||||
|
||||
|
||||
val resultF = for {
|
||||
_ <- stop1F
|
||||
_ <- stop2F
|
||||
_ <- stoppedBitcoindF
|
||||
_ <- system.terminate()
|
||||
} yield ()
|
||||
|
||||
Await.result(resultF, 180.seconds)
|
||||
```
|
||||
|
||||
### Other modules
|
||||
|
||||
You may find useful testkit functionality for other modules here
|
||||
|
||||
1. [Chain](/api/org/bitcoins/testkit/chain/ChainUnitTest)
|
||||
2. [Key Manager](/api/org/bitcoins/testkit/keymanager/KeyManagerApiUnitTest)
|
||||
3. [Wallet](/api/org/bitcoins/testkit/wallet/BitcoinSWalletTest)
|
||||
4. [Node](/api/org/bitcoins/testkit/node/NodeUnitTest)
|
||||
|
||||
In general, you will find constructors and destructors of fixtures that can be useful when testing your applications
|
||||
if you are using any of those modules.
|
48
website/versioned_docs/version-1.7.0/wallet/backups.md
Normal file
48
website/versioned_docs/version-1.7.0/wallet/backups.md
Normal file
@ -0,0 +1,48 @@
|
||||
---
|
||||
id: version-1.7.0-backups
|
||||
title: Wallet Backups
|
||||
original_id: backups
|
||||
---
|
||||
|
||||
Currently, the primary to back up the Bitcoin-S wallet now is through creating a `zip`
|
||||
archive of the `.bitcoin-s` data folder. This is chosen because to have a complete backup
|
||||
for open DLCs you need to restore all the data given from your counter-party as well as some
|
||||
generated by your own wallet. Zipping the folder is the easiest way to back up and restore
|
||||
this data as it is not something that can be written down on a piece of paper.
|
||||
|
||||
## Backing up from the GUI
|
||||
|
||||
To create a backup from the GUI simply click the `File` menu, then select `Save Backup`.
|
||||
This will bring up a dialog to choose the save location for where to save the file to.
|
||||
|
||||
![backup gui](/img/doc-imgs/backup-gui.png)
|
||||
|
||||
This file with be a `zip` archive of your `.bitcoin-s` data folder, it will contain all
|
||||
of your wallet seeds, DLC data, oracle data, wallet history, and configuration.
|
||||
|
||||
## Backing up from the CLI
|
||||
|
||||
To create a backup from the cli simply use the `zipdatadir` cli command.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
bitcoin-s-cli zipdatadir "/path/to/save/zip/drive"
|
||||
```
|
||||
|
||||
This will create a `zip` archive at the given path that can be later used to restore from
|
||||
|
||||
## Restoring from a backup
|
||||
|
||||
To restore from a backup you simply to place the contents of the `zip` archive in your `.bitcoin-s` folder.
|
||||
|
||||
The default for different operating systems is:
|
||||
|
||||
Linux & MacOs: `~/.bitcoin-s`
|
||||
|
||||
Windows: `C:/Users/{Your Username}/.bitcoin-s`
|
||||
|
||||
After replacing the files, simply restart Bitcoin-S and will re-sync from where you
|
||||
last left off.
|
||||
|
||||
* If neutrino syncing was previously being used, it will need to download them all again.
|
179
website/versioned_docs/version-1.7.0/wallet/dlc.md
Normal file
179
website/versioned_docs/version-1.7.0/wallet/dlc.md
Normal file
@ -0,0 +1,179 @@
|
||||
---
|
||||
id: version-1.7.0-dlc
|
||||
title: Executing A DLC with Bitcoin-S
|
||||
original_id: dlc
|
||||
---
|
||||
|
||||
## Executing A Discreet Log Contract (DLC)
|
||||
|
||||
## Step 1: Get Bitcoin-S Setup
|
||||
|
||||
See the [setup document](../getting-setup.md).
|
||||
|
||||
### Using the GUI
|
||||
|
||||
To first start up the GUI you first need to start your bitcoin-s server and gui with
|
||||
|
||||
```bashrc
|
||||
sbt bundle/run
|
||||
```
|
||||
|
||||
or if your bitcoin-s server is already running, you can run the standalone gui with
|
||||
|
||||
```bashrc
|
||||
sbt gui/run
|
||||
```
|
||||
|
||||
or by following the instructions for building and running the GUI [here](../getting-setup.md#step-5-setting-up-a-bitcoin-s-server)
|
||||
|
||||
## Step 2: Agree On Contract Terms
|
||||
|
||||
Both parties must agree on all fields from the table below:
|
||||
|
||||
| Field Name | Description |
|
||||
| :------------: | :------------------------------------------------------: |
|
||||
| contractInfo | Information about payouts and which oracles to use |
|
||||
| collateral | Number of sats the initiator is putting up |
|
||||
| locktime | Locktime of the CETs |
|
||||
| refundlocktime | Locktime of the Refund Transaction |
|
||||
| feerate | Fee rate in sats/vbyte |
|
||||
|
||||
> Note: if you wish to set up your own oracle for testing, you can do so by checking out our [oracle rpc server](../oracle/oracle-server.md) or [Krystal Bull](https://github.com/benthecarman/krystal-bull)
|
||||
|
||||
## Step 3: Set up The DLC
|
||||
|
||||
### Using the GUI
|
||||
|
||||
If you're a visual learner there is a [video demo](https://www.youtube.com/watch?v=zy1sL2ndcDg) that explains this process in detail.
|
||||
But do note that this demonstrates the old non-adaptor version of DLCs so that the Offer, Accept, Sign protocol is the same, but the contents will be different.
|
||||
|
||||
If using a numeric contract and/or multiple oracles, messages can get very large and sometimes even too large to for the application.
|
||||
To solve this there is an `Export to file` button located under the text box for the messages your wallet will construct.
|
||||
This can be used to export a DLC message to a file and then the file can be sent to your counter party.
|
||||
If you receive a file from a counter-party, there is an `Import file` button on every dialog you input a DLC message.
|
||||
This can be used to import the file of the DLC message from your counter-party.
|
||||
|
||||
#### Creating The Offer
|
||||
|
||||
Once the terms are agreed to, either party can use the `Offer` button and enter each of the fields from the table above.
|
||||
|
||||
#### Accepting The Offer
|
||||
|
||||
Upon receiving a DLC Offer from your counter-party, you can use the `Accept` button and paste in the DLC Offer.
|
||||
|
||||
#### Signing The DLC
|
||||
|
||||
Upon receiving a DLC Accept message from your counter-party, you can use the `Sign` button and paste in the DLC Accept.
|
||||
|
||||
#### Adding DLC Signatures To Your Database
|
||||
|
||||
Upon receiving a DLC Sign message from your counter-party, add their signatures to your database using the `Add Sigs` button and paste in the message.
|
||||
After doing so you can get the fully signed funding transaction using the `Get Funding Tx` button. This will return the fully signed serialized transaction.
|
||||
|
||||
### Using the CLI
|
||||
|
||||
If using a numeric contract and/or multiple oracles, messages can get very large and sometimes even too large to for the application.
|
||||
To solve this there are RPC calls where you can give a file instead of the entire DLC message.
|
||||
To output a file you simply just need to pipe the output of a command into a file.
|
||||
|
||||
For example:
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli acceptdlcoffer [offer] > myDLCAccept.txt
|
||||
```
|
||||
|
||||
#### Creating The Offer
|
||||
|
||||
Once these terms are agreed to, either party can call on `createdlcoffer` with flags for each of the fields in the table above. For example:
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli createdlcoffer [contractInfo] [collateral] [feerate] [locktime] [refundlocktime]
|
||||
```
|
||||
|
||||
#### Accepting The Offer
|
||||
|
||||
Upon receiving a DLC Offer from your counter-party, the following command will create the serialized accept message:
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli acceptdlcoffer [offer]
|
||||
```
|
||||
|
||||
or from file:
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli acceptdlcofferfromfile [filepath]
|
||||
```
|
||||
|
||||
#### Signing The DLC
|
||||
|
||||
Upon receiving a DLC Accept message from your counter-party, the following command will generate all of your signatures for this DLC:
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli signdlc [accept]
|
||||
```
|
||||
|
||||
or from file:
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli signdlcfromfile [filepath]
|
||||
```
|
||||
|
||||
|
||||
#### Adding DLC Signatures To Your Database
|
||||
|
||||
Upon receiving a DLC Sign message from your counter-party, add their signatures to your database by:
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli adddlcsigs [sign]
|
||||
```
|
||||
|
||||
or from file:
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli adddlcsigsfromfile [filepath]
|
||||
```
|
||||
|
||||
#### Getting Funding Transaction
|
||||
|
||||
You are now fully setup and can generate the fully signed funding transaction for broadcast using
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli getdlcfundingtx [contractId]
|
||||
```
|
||||
|
||||
where the `contractId` is in all but the messages other than the DLC Offer message, and is also returned by the `adddlcsigs` command.
|
||||
|
||||
Alternatively, you can use the `getdlcs` command to list all of your current DLCs saved in your wallet.
|
||||
|
||||
## Step 4: Executing the DLC
|
||||
|
||||
### Using the GUI
|
||||
|
||||
#### Execute
|
||||
|
||||
You can execute the DLC unilaterally with the `Execute` button which will require the oracle signature.
|
||||
This will return a fully signed Contract Execution Transaction for the event signed by the oracle.
|
||||
|
||||
#### Refund
|
||||
|
||||
If the `refundlocktime` for the DLC has been reached, you can get the fully-signed refund transaction with the `Refund` button and entering the `contractId`.
|
||||
|
||||
### Using the CLI
|
||||
|
||||
#### Execute
|
||||
|
||||
Upon receiving an oracle signature, you can execute the DLC unilaterally with
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli executedlc [contractId] [signatureTLVs]
|
||||
```
|
||||
|
||||
which will return fully signed Contract Execution Transaction for the event signed by the oracle.
|
||||
|
||||
#### Refund
|
||||
|
||||
If the `refundlocktime` for the DLC has been reached, you can get the fully-signed refund transaction with
|
||||
|
||||
```bashrc
|
||||
./app/cli/target/universal/stage/bitcoin-s-cli executedlcrefund [contractId]
|
||||
```
|
||||
|
50
website/versioned_docs/version-1.7.0/wallet/wallet-rpc.md
Normal file
50
website/versioned_docs/version-1.7.0/wallet/wallet-rpc.md
Normal file
@ -0,0 +1,50 @@
|
||||
---
|
||||
title: Wallet RPC Examples
|
||||
id: version-1.7.0-wallet-rpc
|
||||
original_id: wallet-rpc
|
||||
---
|
||||
|
||||
### `listreservedutxos`
|
||||
|
||||
Lists all reserved utxos in the wallet.
|
||||
These utxos will not be unreserved unless you manually
|
||||
unreserve them with `lockunspent` or they are spent in the blockchain
|
||||
|
||||
```bash
|
||||
bitcoin-s-cli listreservedutxos
|
||||
[
|
||||
{
|
||||
"outpoint": {
|
||||
"txid": "1c22634fa282e71866a8b8c6732ec89eb5c46d30f9773486b0ae32770e8109e1",
|
||||
"vout": 1,
|
||||
},
|
||||
"value": 2000
|
||||
},
|
||||
{
|
||||
"outpoint": {
|
||||
"txid": "2b12634fa282e71866a8b8c6732ec89eb5c46d30f9773486b0ae32770e810901",
|
||||
"vout": 0,
|
||||
},
|
||||
"value": 1000
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
|
||||
### `lockunspent`
|
||||
|
||||
Locks all utxos in the wallet
|
||||
```bash
|
||||
bitcoin-s-cli lockunspent false
|
||||
```
|
||||
|
||||
Unlocks utxo `1c22634fa282e71866a8b8c6732ec89eb5c46d30f9773486b0ae32770e8109e1:1`
|
||||
```bash
|
||||
bitcoin-s-cli lockunspent true '{"txid" : "1c22634fa282e71866a8b8c6732ec89eb5c46d30f9773486b0ae32770e8109e1","vout" : 1}'
|
||||
```
|
||||
|
||||
Locks utxos `1c22634fa282e71866a8b8c6732ec89eb5c46d30f9773486b0ae32770e8109e1:1` and `4c63268a688d103caeb26137cecd4053566bd3626504e079055581c104c4de5b:0`
|
||||
```bash
|
||||
bitcoin-s-cli lockunspent false '[{"txid" : "1c22634fa282e71866a8b8c6732ec89eb5c46d30f9773486b0ae32770e8109e1","vout" : 1}, {"txid" : "4c63268a688d103caeb26137cecd4053566bd3626504e079055581c104c4de5b","vout" : 0}]'
|
||||
```
|
93
website/versioned_sidebars/version-1.7.0-sidebars.json
Normal file
93
website/versioned_sidebars/version-1.7.0-sidebars.json
Normal file
@ -0,0 +1,93 @@
|
||||
{
|
||||
"version-1.7.0-docs": {
|
||||
"Getting Started": [
|
||||
"version-1.7.0-getting-started",
|
||||
"version-1.7.0-bips"
|
||||
],
|
||||
"Getting Setup": [
|
||||
"version-1.7.0-getting-setup"
|
||||
],
|
||||
"Applications": [
|
||||
"version-1.7.0-applications/cli",
|
||||
"version-1.7.0-applications/server",
|
||||
"version-1.7.0-applications/gui",
|
||||
"version-1.7.0-applications/server-systemd"
|
||||
],
|
||||
"Chain": [
|
||||
"version-1.7.0-chain/chain",
|
||||
"version-1.7.0-chain/filter-sync",
|
||||
"version-1.7.0-chain/chain-query-api"
|
||||
],
|
||||
"Configuration": [
|
||||
"version-1.7.0-config/configuration"
|
||||
],
|
||||
"Core Module": [
|
||||
"version-1.7.0-core/core-intro",
|
||||
"version-1.7.0-core/addresses",
|
||||
"version-1.7.0-core/hd-keys",
|
||||
"version-1.7.0-core/adding-spks",
|
||||
"version-1.7.0-core/spending-info",
|
||||
"version-1.7.0-core/psbts",
|
||||
"version-1.7.0-core/dlc",
|
||||
"version-1.7.0-core/txbuilder",
|
||||
"version-1.7.0-core/lightning-network"
|
||||
],
|
||||
"Crypto Module": [
|
||||
"version-1.7.0-crypto/crypto-intro",
|
||||
"version-1.7.0-crypto/sign",
|
||||
"version-1.7.0-crypto/adaptor-signatures"
|
||||
],
|
||||
"Fee Provider": [
|
||||
"version-1.7.0-fee-provider/fee-provider"
|
||||
],
|
||||
"Key Manager": [
|
||||
"version-1.7.0-key-manager/server-key-manager",
|
||||
"version-1.7.0-key-manager/key-manager"
|
||||
],
|
||||
"Node": [
|
||||
"version-1.7.0-node/node",
|
||||
"version-1.7.0-node/node-api"
|
||||
],
|
||||
"Wallet": [
|
||||
"version-1.7.0-wallet/wallet",
|
||||
"version-1.7.0-wallet/wallet-callbacks",
|
||||
"version-1.7.0-wallet/wallet-get-address",
|
||||
"version-1.7.0-wallet/address-tagging",
|
||||
"version-1.7.0-wallet/dlc",
|
||||
"version-1.7.0-wallet/wallet-rescan",
|
||||
"version-1.7.0-wallet/wallet-sync",
|
||||
"version-1.7.0-wallet/wallet-rpc",
|
||||
"version-1.7.0-wallet/backups"
|
||||
],
|
||||
"RPC Clients": [
|
||||
"version-1.7.0-rpc/rpc-clients-intro",
|
||||
"version-1.7.0-rpc/rpc-eclair",
|
||||
"version-1.7.0-rpc/rpc-bitcoind",
|
||||
"version-1.7.0-rpc/lnd-rpc"
|
||||
],
|
||||
"Secp256k1": [
|
||||
"version-1.7.0-secp256k1/secp256k1",
|
||||
"version-1.7.0-secp256k1/jni-modify"
|
||||
],
|
||||
"Testkit": [
|
||||
"version-1.7.0-testkit/testkit",
|
||||
"version-1.7.0-testkit/testkit-core"
|
||||
],
|
||||
"DLC Oracle": [
|
||||
"version-1.7.0-oracle/build-oracle-server",
|
||||
"version-1.7.0-oracle/oracle-server",
|
||||
"version-1.7.0-oracle/oracle-election-example",
|
||||
"version-1.7.0-oracle/oracle-price-example"
|
||||
],
|
||||
"Oracle Explorer Client": [
|
||||
"version-1.7.0-oracle-explorer-client/oracle-explorer-client"
|
||||
],
|
||||
"Contributing": [
|
||||
"version-1.7.0-contributing",
|
||||
"version-1.7.0-contributing-website"
|
||||
],
|
||||
"Security": [
|
||||
"version-1.7.0-security"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user