Add version 0.2.0 of the website (#948)

This commit is contained in:
Chris Stewart 2019-12-16 05:57:14 -06:00 committed by GitHub
parent ead511a1ec
commit d9dcacf2da
23 changed files with 1594 additions and 4 deletions

View File

@ -1,5 +1,5 @@
![Bitcoin-S logo](website/static/img/bitcoin-s-dark-logo.png)
[![Build Status](https://travis-ci.org/bitcoin-s/bitcoin-s.svg?branch=master)](https://travis-ci.org/bitcoin-s/bitcoin-s) [![Coverage Status](https://coveralls.io/repos/github/bitcoin-s/bitcoin-s/badge.svg?branch=master)](https://coveralls.io/github/bitcoin-s/bitcoin-s?branch=master) [![Maven Central](https://img.shields.io/badge/Maven%20Central-0.1.0-brightgreen.svg)](https://mvnrepository.com/artifact/org.bitcoin-s) [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/bitcoin-s-core)
[![Build Status](https://travis-ci.org/bitcoin-s/bitcoin-s.svg?branch=master)](https://travis-ci.org/bitcoin-s/bitcoin-s) [![Coverage Status](https://coveralls.io/repos/github/bitcoin-s/bitcoin-s/badge.svg?branch=master)](https://coveralls.io/github/bitcoin-s/bitcoin-s?branch=master) [![Maven Central](https://img.shields.io/badge/Maven%20Central-0.2.0-brightgreen.svg)](https://mvnrepository.com/artifact/org.bitcoin-s) [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/bitcoin-s-core)
Feature rich toolkit for making Bitcoin and Lightning applications
on the JVM.

View File

@ -365,10 +365,14 @@ lazy val docs = project
.settings(CommonSettings.testSettings: _*)
.dependsOn(
bitcoindRpc,
chain,
cli,
core,
eclairRpc,
keyManager,
secp256k1jni,
testkit,
wallet,
zmq
)

View File

@ -94,6 +94,57 @@
},
"version-0.1.0/version-0.1.0-security": {
"title": "Security"
},
"version-0.2.0/applications/version-0.2.0-chain": {
"title": "Blockchain Verification"
},
"version-0.2.0/applications/version-0.2.0-cli": {
"title": "bitcoin-s cli"
},
"version-0.2.0/applications/version-0.2.0-configuration": {
"title": "Application configuration"
},
"version-0.2.0/applications/version-0.2.0-key-manager": {
"title": "Key Manager"
},
"version-0.2.0/applications/version-0.2.0-node": {
"title": "Light client"
},
"version-0.2.0/applications/version-0.2.0-wallet": {
"title": "Wallet"
},
"version-0.2.0/version-0.2.0-contributing-website": {
"title": "Contributing to the website"
},
"version-0.2.0/version-0.2.0-contributing": {
"title": "Contributing"
},
"version-0.2.0/core/version-0.2.0-addresses": {
"title": "Generating addresses"
},
"version-0.2.0/core/version-0.2.0-core-intro": {
"title": "Core module"
},
"version-0.2.0/core/version-0.2.0-hd-keys": {
"title": "HD key generation"
},
"version-0.2.0/core/version-0.2.0-txbuilder": {
"title": "TxBuilder example"
},
"version-0.2.0/version-0.2.0-getting-started": {
"title": "Add Bitcoin-S to your project"
},
"version-0.2.0/rpc/version-0.2.0-rpc-bitcoind": {
"title": "bitcoind/Bitcoin Core"
},
"version-0.2.0/rpc/version-0.2.0-rpc-eclair": {
"title": "Eclair"
},
"version-0.2.0/rpc/version-0.2.0-rpc-clients-intro": {
"title": "Introduction"
},
"version-0.2.0/version-0.2.0-windows-users": {
"title": "windows-users"
}
},
"links": {

View File

@ -13,10 +13,13 @@
"rpc/rpc-bitcoind"
],
"Applications": [
"applications/node",
"applications/wallet",
"applications/chain",
"applications/configuration"
"applications/cli",
"applications/configuration",
"applications/key-manager",
"applications/node",
"applications/server",
"applications/wallet"
],
"Contributing": ["contributing", "contributing-website"],
"Security": ["security"]

View File

@ -0,0 +1,91 @@
---
title: Blockchain Verification
id: version-0.2.0-chain
original_id: chain
---
Bitcoin-S comes bundled with a rudimentary blockchain verification
module. This module is currently only released as a library, and not as a binary.
This is because it (nor the documentation) is not deemed production
ready. Use at your own risk, and without too much money depending on it.
## Syncing and verifying block headers
Using the `chain` module of Bitcoin-S it's possible to
sync and verify block headers from the Bitcoin blockchain. In this document
we demonstrate how to do this, while persisting it to disk. We should be
able to read this chain on subsequent runs, assuming we are connected
to the same `bitcoind` instance.
```scala
import org.bitcoins.chain.blockchain._
import org.bitcoins.chain.blockchain.sync._
import org.bitcoins.chain.models._
import org.bitcoins.rpc.client.common._
import org.bitcoins.testkit.chain._
import scala.concurrent._
implicit val ec = ExecutionContext.global
// We are assuming that a `bitcoind` regtest node is running the background.
// You can see our `bitcoind` guides to see how to connect
// to a local or remote `bitcoind` node.
import org.bitcoins.rpc.config.BitcoindInstance
import org.bitcoins.rpc.client.common.BitcoindRpcClient
val bitcoindInstance = BitcoindInstance.fromDatadir()
val rpcCli = BitcoindRpcClient(bitcoindInstance)
// Next, we need to create a way to monitor the chain:
val getBestBlockHash = ChainTestUtil.bestBlockHashFnRpc(Future.successful(rpcCli))
val getBlockHeader = ChainTestUtil.getBlockHeaderFnRpc(Future.successful(rpcCli))
// set a data directory
import java.nio.file.Files
val datadir = Files.createTempDirectory("bitcoin-s-test")
// set the currenet network to regtest
import com.typesafe.config.ConfigFactory
val config = ConfigFactory.parseString {
"""
| bitcoin-s {
| network = regtest
| }
|""".stripMargin
}
import org.bitcoins.chain.config.ChainAppConfig
implicit val chainConfig = ChainAppConfig(datadir, config)
// Initialize the needed database tables if they don't exist:
val chainProjectInitF = chainConfig.initialize()
val blockHeaderDAO = BlockHeaderDAO()
val compactFilterHeaderDAO = CompactFilterHeaderDAO()
val compactFilterDAO = CompactFilterDAO()
// Now, do the actual syncing:
val chainHandlerF = ChainHandler.fromDatabase(blockHeaderDAO, compactFilterHeaderDAO, compactFilterDAO)
val syncedChainApiF = for {
_ <- chainProjectInitF
handler <- chainHandlerF
synced <- ChainSync.sync(handler, getBlockHeader, getBestBlockHash)
} yield synced
val syncResultF = syncedChainApiF.flatMap { chainApi =>
chainApi.getBlockCount.map(count => println(s"chain api blockcount=${count}"))
rpcCli.getBlockCount.map(count => println(s"bitcoind blockcount=${count}"))
}
syncResultF.onComplete { case result =>
println(s"Sync result=${result}")
}
```

View File

@ -0,0 +1,64 @@
---
id: version-0.2.0-cli
title: bitcoin-s cli
original_id: cli
---
## Bitcoin-s command line interface
The [cli](../../app/cli/) project is meant to be a bitcoin-s command line interface (cli). It uses [graalvm native image](https://www.graalvm.org/docs/reference-manual/native-image/) to
create a native executable that circumvents the jvm for fast start up time.
### Building the command line interface
#### Installing graalvm native image
First to build the command line interface you need to have the graal jdk installed. This can be installed on [graalvm's github](https://github.com/graalvm/graalvm-ce-builds/releases/).
Make sure you install the [prerequisites](https://www.graalvm.org/docs/reference-manual/native-image/#prerequisites) for installing the `native-image` executable.
If you do not have the `native-image` executable installed, you need to install it with
```bashrc
./graalvm-ce-java8-19.3.0/bin/gu install native-image
```
Once you have the graalvm installed you should be able to verify you have the `native-image` exeuctable installed by running
```bashrc
$ native-image --help
```
If your command did not work, make sure you can find the `native-image` executable on your `PATH`.
#### Building the native image
Now that you have graalvm native image installed, you should be able to build the cli with. It is important to note that
this only works with Scala `2.12.x`. I'm unsure of why the native image build fails with Scala `2.13.x`
```bashrc
$ sbt ++2.12.10 cli/graalvm-native-image:packageBin
```
After running that command you should find the executable here:
```bash
bitcoin-s/app/cli/target/graalvm-native-image
```
#### Executing commands
You can ask the client for help with
```bash
./app/cli/target/graalvm-native-image/bitcoin-s-cli --help
Usage: bitcoin-s-cli [options] [<cmd>]
-n, --network <value> Select the active network.
--debug Print debugging information
-h, --help Display this help message and exit
<cmd> The command and arguments to be executed. Try bitcoin-s-cli help for a list of all commands
```
Now you are are ready to start the server that the cli sends commands to. Take a look at our [server](server.md) documentation on how to build and start the server.

View File

@ -0,0 +1,51 @@
---
id: version-0.2.0-configuration
title: Application 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`](../../db-commons/src/main/scala/org/bitcoins/db/AppConfig.scala).
`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
// 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.
## Internal configuration
Database connections are also configured by using HOCON. This is done in
[`db.conf`](../../db-commons/src/main/resources/db.conf). The options
exposed here are **not** intended to
be used by users of Bitcoin-S, and are internal only.

View File

@ -0,0 +1,16 @@
---
id: version-0.2.0-key-manager
title: Key Manager
original_id: key-manager
---
#### Key Manager
The key manager module's goal is to encapusulate all private key interactions with the [wallet](wallet.md) project.
As of this writing, the wallet just delegates storage of the encrypted mnemonic seed to the key manager project. Over the log 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.

View File

@ -0,0 +1,14 @@
---
title: Light client
id: version-0.2.0-node
original_id: node
---
Bitcoin-S comes bundled with a light client Bitcoin node. this client
is capable of doing verification of some parts of the blockchain,
and can act as a starting point for building Bitcoin applications
that need to connect to the P2P network.
This node is currently only released as a library, and not as a binary.
This is because it (nor the documentation) is not deemed production
ready. Use at your own risk, and without too much money depending on it.

View File

@ -0,0 +1,136 @@
---
title: Wallet
id: version-0.2.0-wallet
original_id: wallet
---
Bitcoin-S comes bundled with a rudimentary Bitcoin wallet. This wallet
is capable of managing private keys, generating addresses, constructing
and signing transactions, among other things. It is BIP32/BIP44/BIP49/BIP84
compatible.
This wallet is currently only released as a library, and not as a binary.
This is because it (nor the documentation) is not deemed production
ready. Use at your own risk, and without too much money depending on it.
## Creating a wallet
This guide shows how to create a Bitcoin-S wallet and then
peer it with a `bitcoind` instance that relays
information about what is happening on the blockchain
through the P2P network.
This is useful if you want more flexible signing procedures in
the JVM ecosystem and more granular control over your
UTXOs with popular database like Postgres, SQLite, etc.
This code snippet you have a running `bitcoind` instance, locally
on regtest.
```scala
implicit val ec = scala.concurrent.ExecutionContext.global
import com.typesafe.config.ConfigFactory
val config = ConfigFactory.parseString {
"""
| bitcoin-s {
| network = regtest
| }
""".stripMargin
}
import java.nio.file.Files
val datadir = Files.createTempDirectory("bitcoin-s-wallet")
import org.bitcoins.wallet.config.WalletAppConfig
implicit val walletConfig = WalletAppConfig(datadir, config)
// we also need to store chain state for syncing purposes
import org.bitcoins.chain.config.ChainAppConfig
implicit val chainConfig = ChainAppConfig(datadir, config)
// when this future completes, we have
// created the necessary directories and
// databases for managing both chain state
// and wallet state
import scala.concurrent._
val configF: Future[Unit] = for {
_ <- walletConfig.initialize()
_ <- chainConfig.initialize()
} yield ()
import org.bitcoins.rpc.config.BitcoindInstance
val bitcoindInstance = BitcoindInstance.fromDatadir()
import org.bitcoins.rpc.client.common.BitcoindRpcClient
val bitcoind = BitcoindRpcClient(bitcoindInstance)
// when this future completes, we have
// synced our chain handler to our bitcoind
// peer
import org.bitcoins.chain.api.ChainApi
val syncF: Future[ChainApi] = configF.flatMap { _ =>
val getBestBlockHashFunc = { () =>
bitcoind.getBestBlockHash
}
import org.bitcoins.core.crypto.DoubleSha256DigestBE
val getBlockHeaderFunc = { hash: DoubleSha256DigestBE =>
bitcoind.getBlockHeader(hash).map(_.blockHeader)
}
import org.bitcoins.chain.models._
import org.bitcoins.chain.blockchain.ChainHandler
val blockHeaderDAO = BlockHeaderDAO()
val compactFilterHeaderDAO = CompactFilterHeaderDAO()
val compactFilterDAO = CompactFilterDAO()
val chainHandler = ChainHandler(
blockHeaderDAO,
compactFilterHeaderDAO,
compactFilterDAO,
blockchains = Vector.empty,
blockFilterCheckpoints = Map.empty)
import org.bitcoins.chain.blockchain.sync.ChainSync
ChainSync.sync(chainHandler, getBlockHeaderFunc, getBestBlockHashFunc)
}
// once this future completes, we have a initialized
// wallet
import org.bitcoins.wallet.api.LockedWalletApi
import org.bitcoins.wallet.api.InitializeWalletSuccess
import org.bitcoins.wallet.Wallet
import org.bitcoins.core.api._
val walletF: Future[LockedWalletApi] = configF.flatMap { _ =>
Wallet.initialize(NodeApi.NoOp, ChainQueryApi.NoOp).collect {
case InitializeWalletSuccess(wallet) => wallet
}
}
// when this future completes, ww have sent a transaction
// from bitcoind to the Bitcoin-S wallet
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.currency._
val transactionF: Future[Transaction] = for {
wallet <- walletF
address <- wallet.getNewAddress()
txid <- bitcoind.sendToAddress(address, 3.bitcoin)
transaction <- bitcoind.getRawTransaction(txid)
} yield transaction.hex
// when this future completes, we have processed
// the transaction from bitcoind, and we have
// queried our balance for the current balance
val balanceF: Future[CurrencyUnit] = for {
wallet <- walletF
tx <- transactionF
_ <- wallet.processTransaction(tx, confirmations = 0)
balance <- wallet.getBalance
} yield balance
balanceF.foreach { balance =>
println(s"Bitcoin-S wallet balance: $balance")
}
```

View File

@ -0,0 +1,91 @@
---
id: version-0.2.0-contributing-website
title: Contributing to the website
original_id: contributing-website
---
This website is built using [Docusaurus](https://docusaurus.io/).
For simple changes to the documentation, click on the `Edit` button at the top
of each page and submit those changes directly on GitHub.
## Scaladoc
One of the goals of Bitcoin-S is having useful and well-formatted Scaladoc comments on classes,
objects and functions. Here are some useful resources on how to properly format your Scaladoc comments:
- [Scaladoc for library authors](https://docs.scala-lang.org/overviews/scaladoc/for-library-authors.html)
- [Guidelines](https://docs.scala-lang.org/style/scaladoc.html) used by the official Scala language Scaladoc
- [Alvin Alexander guide](https://alvinalexander.com/scala/how-to-generate-scala-documentation-scaladoc-command-examples) on writing Scaladoc
To generate Scaladocs:
```bash
$ sbt
> unidoc
```
This gets placed in `website/static/api`. When viewing the Docusaurus site the generated Scaladocs
appear under the API tab in the header bar,
or in the "API reference" link in the footer.
## Running the site locally
For running the website locally, you'll need:
- `yarn` (https://yarnpkg.com/lang/en/docs/install-ci/)
- `sbt` (https://www.scala-sbt.org/1.0/docs/Setup.html)
> In case you want to contribute substantial structural changes to the website,
> we suggest to read
> [Docusaurus' documentation](https://docusaurus.io/docs/en/installation.html)
> first.
You can now build and launch the website using
these commands:
```sh
cd website
yarn install # only the first time, to install the dependencies
yarn start
```
In a separate shell:
```bash
$ bloop run docs -- --watch
```
The above commands compiles our Mdoc Markdown files every time you change
them, and puts them in the correct directory for Docusaurus to find them.
Now visit http://localhost:3000/ and you should see a local version of
the website.
## Adding a new page
Whenever you add a new markdown page to the documentation, you'll have to
manually include it in the side menu.
You can do this by editing the `website/sidebars.json` file. The name to use is
the `id` specified in the page metadata (see the existing pages for an example).
## Publishing the site
```bash
$ sbt
> docs/publishWebsite
```
This command first generates Scaladocs, then invokes
`docs/docusaurusPublishGhPages`, which in turn compile our mdoc
files, build the site and push them to GH pages.
Before running those commands, you might have to change a few constants in
`siteConfig.js`. These are specifed in the comments of that file.
### CI
Bitcoin-S uses Travis to run tests and deploy library and website builds. Generally
speaking CI has to pass for a PR to get merged. If you make documentation/website only
changes, you can start your PR title with `Docs:`. This skips running tests on CI.

View File

@ -0,0 +1,255 @@
---
id: version-0.2.0-contributing
title: Contributing
original_id: contributing
---
Bitcoin-S is an open source project where anyone is welcome to contribute. All contributions are encouraged and appreciated, whether that is code, testing, documentation or something else entirely.
## Communication Channels
It's possible to communicate with other developers through a variety of communication channels:
- [Suredbits Slack](https://join.slack.com/t/suredbits/shared_invite/enQtNDEyMjY3MTg1MTg3LTYyYjkwOGUzMDQ4NDAwZjE1M2I3MmQyNWNlZjNlYjg4OGRjYTRjNWUwNjRjNjg4Y2NjZjAxYjU1N2JjMTU1YWM) - Suredbits is a company monetizing APIs through the Lightning Network. Suredbits doesn't own Bitcoin-S, but the Suredbits CEO Chris Stewart is the maintainer of this library. There's a separate Bitcoin-S channel on their Slack, this is probably the easiest way of getting in touch with someone working on this project.
- [Bitcoin-S Gitter](https://gitter.im/bitcoin-s-core/)
- [#bitcoin-scala](https://webchat.freenode.net/?channels=bitcoin-scala) on IRC Freenode
## Working on Bitcoin-S applications
Bitcoin-S includes a couple of applications that can be run as standalone executables.
This includes the node, wallet and (partial) blockchain verification modules, as well
as the server that bundles these three together and the CLI used to communicate with
the server. These applications are configured with HOCON files. The file
[`reference.conf`](../testkit/src/main/resources/reference.conf)
is the basis configuration file, and every option read by Bitcoin-S should be present in
this file. This means that you can copy sections from this file and edit them, to tune
how the application runs on your machine.
One example of things you can tune is logging levels. Lets say you wanted general logging
to happen at the `WARN` level, but the P2P message handling to be logged at `DEBUG`. Your
configuration file would then look like:
```conf
bitcoins-s {
logging {
level = warn
p2p = debug
}
}
```
### Running the applications
When running the applications configuration placed in `bitcoin-s.conf` in the current
data directory gets picked up. For linux this is by default `$HOME/.bitcoin-s/`, so the
file you should edit would be `$HOME/.bitcoin-s/bitcoin-s.conf`.
### Running tests for the applications
You can place a `logback-test.xml` file in the `src/test/resources/` directory in the same project that tests are being run in.
If the test suite depends on `testkit`, you can modify [`reference.conf`](../testkit/src/main/resources/reference.conf)
that is built into the testkit to control logging.
## Logging when working on Bitcoin-S tests
When working on various parts of Bitcoin-S the need to log what's going on arises
pretty quickly. There's two way of doing this:
1. Using the way described in the section above, "Working on Bitcoin-S applications".
You could either use traits (like `HTTPLogger` or `P2PLogger`) that exposes a
field `logger`, or acquire the logger directly through the traits companion
object.
2. Use the standard `BitcoinSLogger`, which is also available as both a trait and
a companion object with a field you can access (`BitcoinSLogger.logger`). Note
that by default all logging from this logger is turned off in tests, to make
output less noisy. You can tune this by changing the level found in
`core-test/src/test/resources/logback-test.xml`.
### Akka logging
The test logging for akka is controlled by the [`reference.conf`](../testkit/src/main/resources/reference.conf) file inside of testkit.
This allows you to debug what is happening in our actors inside of bitcoin-s easier. For examples of what you can enable for akka to log, please look at their [logging documentation](https://doc.akka.io/docs/akka/current/logging.html#auxiliary-logging-options)
The easiest thing to do to enable akka logging is to adjust the `loglevel` and `stdout-loglevel` from `OFF` to `DEBUG`.
If you want to enable this when you are running a bitcoin-s application, you will need to modify the [`reference.conf`](../app/server/src/main/resources/reference.conf) file
## Developer productivity
### sbt
The default scala build tool is [sbt](https://www.scala-sbt.org/).
For the basics of how sbt works see the [sbt guide](https://www.scala-sbt.org/1.x/docs/Getting-Started.html)
One helpful configuration is the env variable `SBT_OPTS` which allows you to pass jvm arguments for sbt.
### Bloop
If you're tired of waiting around for sbt all day, there's a new,
cool kid on the block. It is called [Bloop](https://scalacenter.github.io/bloop/),
and it makes compilations in general faster, and in particular
incremental, small compilation units (which greatly help editor
performance). Bloop is a server that runs in the background of
your computer, and keeps several "hot" JVMs running at all
times. These JVMs serve compilation requests. Because the JVMs
are running in the background you avoid the startup lag, and you
also get code that's already [JIT compiled](https://en.wikipedia.org/wiki/Just-in-time_compilation)
for you.
The documentation on Bloops [site](https://scalacenter.github.io/bloop/) is good, but here is the highlights:
1. Install Bloop by doing step 1 & 2 in the [official guide](https://scalacenter.github.io/bloop/setup#universal)
2. Enable the Bloop background daemon
1. macOS:
```bash
$ brew services start bloop
```
2. Ubuntu:
```bash
$ systemctl --user enable $HOME/.bloop/systemd/bloop.service
$ systemctl --user daemon-reload
$ systemctl --user start bloop
```
3. Enable shell completion for the Bloop CLI
1. Bash:
```bash
$ echo '. $HOME/.bloop/bash/bloop' >> $HOME/.bash_profile
```
2. Zsh:
```bash
$ echo 'autoload -U compinit' >> $HOME/.zshrc
$ echo 'fpath=($HOME/.bloop/zsh $fpath)' >> $HOME/.bashrc
$ echo 'compinit' >> $HOME/.bashrc
```
3. Fish:
```bash
$ ln -s $HOME/.bloop/fish/bloop.fish ~/.config/fish/completions/bloop.fish
```
4. Generate configuration files
```bash
$ sbt bloopInstall
```
5. Import Bitcoin-S into IntelliJ again, as a bsp (Build Server Protocol) project (instead of a sbt project). Make sure you're running on the most recent IntelliJ and Scala plugin. See [official docs](https://scalacenter.github.io/bloop/docs/ides/intellij) for details.
6. _(Bonus step):_ Lightning fast recompilations on file save:
```bash
$ bloop compile --project <name of module your're working on> --watch
```
Your editor should now be much faster and require less resources :tada:
## Testing
### Property based testing
This library aims to achieve high level of correctness via property based
testing. At the simplest level, you can think of property based testing as
specifying a invariant that must always hold true.
[Here](https://github.com/bitcoin-s/bitcoin-s-core/blob/89fbf35d78046b7ed21fd93fec05bb57cba023bb/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionSpec.scala#L13-L17)
is an example of a property in the bitcoin-s-core test suite
```scala
property("Serialization symmetry") =
Prop.forAll(TransactionGenerators.transactions) { tx =>
Transaction(tx.hex) == tx
}
```
What this property says is that for every transaction we can generate with
[`TransactionGenerators.transactions`](/api/org/bitcoins/core/gen/TransactionGenerators)
we _must_ be able to serialize it to hex format, then deserialize it back
to a transaction and get the original `tx` back.
A more complex example of property based testing is checking that a
multisignature transaction was signed correctly (see
[`TransactionSignatureCreatorSpec`](core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala)
line 29-34). First we generate a _supposedly_ validly signed multisig
transaction with [`TransactionGenerators.signedMultiSigTransaction`](/api/org/bitcoins/testkit/core/gen/TransactionGenerators)
(line 102-108). These transactions have varying `m` of `n` requirements.
An interesting corner case if when you have 0 of `n` signatures, which
means no signature is required. Property based testing is really good at
fleshing out these corner cases. We check to see if this transaction is
valid by running it through our [`ScriptInterpreter`](/api/org/bitcoins/core/script/interpreter/ScriptInterpreter).
If we have built our functionality correctly the `ScriptInterpreter` should
always return [`ScriptOk`](/api/org/bitcoins/core/script/result/ScriptResult)
indicating the script was valid.
```scala
property("generate valid signatures for a multisignature transaction") =
Prop.forAllNoShrink(TransactionGenerators.signedMultiSigTransaction) {
case (txSignatureComponent: TxSigComponent, _) =>
//run it through the interpreter
val program = ScriptProgram(txSignatureComponent)
val result = ScriptInterpreter.run(program)
result == ScriptOk
}
```
### Running tests
To run the entire test suite all you need to do is run the following command:
> This takes a long time, and runs a lot of tests that require IO. It may hog your computer at times.
```scala
$ sbt test
[info] Elapsed time: 4 min 36.760 sec
[info] ScalaCheck
[info] Passed: Total 149, Failed 0, Errors 0, Passed 149
[info] ScalaTest
[info] Run completed in 4 minutes, 55 seconds.
[info] Total number of tests run: 744
[info] Suites: completed 97, aborted 0
[info] Tests: succeeded 744, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[info] Passed: Total 909, Failed 0, Errors 0, Passed 909
[success] Total time: 297 s, completed Jul 20, 2017 10:34:16 AM
```
To run a specific suite of tests you can specify the suite name in the following way
```scala
$ sbt testOnly *ScriptInterpreterTest*
[info] ScriptInterpreterTest:
[info] ScriptInterpreter
[info] - must evaluate all the scripts from the bitcoin core script_tests.json
[info] Run completed in 8 seconds, 208 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
```
The command `sbt testQuick` can also be handy. It runs tests that either:
1. Failed previously
2. Has not been run previously
3. Either the test or one of its dependencies has been recompiled
For more information on `testQuick`, see the offical
[sbt docs](https://www.scala-sbt.org/1.x/docs/Testing.html#testQuick).
### Coverage
To produce a report that quantifies how much of our code is covered by tests:
```bash
sbt
> coverage
> coreTest/test
> core/coverageReport
```
This generates three different reports: Cobertura, XML and HTML formats.
See the output of your sbt shell to find the location of them.
Open up the HTML file in your browser. You'll now see code coverage
of all files in `core` project.
### CI
Bitcoin-S uses Travis to run tests and deploy library and website builds. Generally
speaking CI has to pass for a PR to get merged. If you make documentation/website only
changes, you can start your PR title with `Docs:`. This skips running tests on CI.

View File

@ -0,0 +1,67 @@
---
id: version-0.2.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
import org.bitcoins.core.{crypto, protocol, config}
// if you want to get addresses for mainnet, just import
// config.MainNet here instead
import config.TestNet3
import crypto.ECPrivateKey
// this gets all addresses into scope
import protocol._
// this gets all scriptPubKeys into scope
import protocol.script._
// this generates a random private key
val privkey = ECPrivateKey()
// privkey: ECPrivateKey = ECPrivateKey(7f0fc482719d180ec8281100f977d6ad50ed1971b71d31026d513fb51bb95206,true)
val pubkey = privkey.publicKey
// pubkey: crypto.ECPublicKey = ECPublicKey(03c585c7c1cd4e670683ec5f3a043a800f7f84ddf39d04a9fe4364802d85f1c756)
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 = Bech32Address(tb1q9vyukq9pt9kw0r70e5zpd06mkyk2m6qukd7uc9)
```
## 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
// pay-to-pubkey-hash address
import org.bitcoins.core.protocol.P2PKHAddress
// 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 = mjSX5jLeUuAsmxLqzFEUMyjCKAKNo5WHJw
```

View File

@ -0,0 +1,141 @@
---
id: version-0.2.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 depedencies 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/core/protocol/NetworkElement). `NetworkElement` provides methods to convert the data structure to hex or byte representation. When paired with [`Factory`](/api/org/bitcoins/core/util/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 = BaseTransactionImpl(Int32Impl(1),Vector(TransactionInputImpl(TransactionOutPoint(4d6da9420d472b6b52c36eee132d87448bf160d8839a58afdd2add6f6adfc8d8:0),P2PKHScriptSignature(ECPublicKey(04c54f8ea9507f31a05ae325616e3024bd9878cb0a5dff780444002d731577be4e2e69c663ff2da922902a4454841aa1754c1b6292ad7d317150308d8cce0ad7ab), ECDigitalSignature(3045022100b31557e47191936cb14e013fb421b1860b5e4fd5d2bc5ec1938f4ffb1651dc8902202661c2920771fd29dd91cd4100cefb971269836da4914d970d333861819265ba01)),UInt32Impl(4294967295)), TransactionInputImpl(TransactionOutPoint(b220a19ba645c021f0cf501435fd6c3b4db960325d0834612612a5684ffab32a:0),P2PKHScriptSignature(ECPublicKey(04c6ec27cffce0823c3fecb162dbd576c88dd7cda0b7b32b0961188a392b488c94ca174d833ee6a9b71c0996620ae71e799fc7c77901db147fa7d97732e49c8226), ECDigitalSignature(30450220230110bc99ef311f1f8bda9d0d968bfe5dfa4af171adbef9ef71678d658823bf022100f956d4fcfa0995a578d84e7e913f9bb1cf5b5be1440bcede07bce9cd5b38115d01)),UInt32Impl(4294967295))),Vector(TransactionOutput(39000000 sats,P2PKHScriptPubKeyImpl(Sha256Hash160DigestImpl(a3d89c53bb956f08917b44d113c6b2bcbe0c29b7))), TransactionOutput(155000000 sats,P2PKHScriptPubKeyImpl(Sha256Hash160DigestImpl(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/core/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 [`TxBuilder`](/api/org/bitcoins/core/wallet/builder/TxBuilder) 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 [UTXOs](/api/org/bitcoins/core/wallet/utxo/UTXOSpendingInfo) 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)
### The [`Sign` API](/api/org/bitcoins/core/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 [`core/src/main/scala/org/bitcoins/core/crypto/Sign.scala`](/api/org/bitcoins/core/crypto/Sign):
```scala
import scodec.bits._
import org.bitcoins.core.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 [`ECKey`](/api/org/bitcoins/core/crypto/ECKey) 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.
### 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
import org.bitcoins.core.protocol.script._
import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.script._
import org.bitcoins.core.script.interpreter._
import org.bitcoins.core.policy._
import org.bitcoins.core.number._
import org.bitcoins.core.crypto._
import org.bitcoins.core.currency._
val spendingTx = Transaction.fromHex("0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000")
val scriptPubKey = ScriptPubKey.fromAsmHex("76a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac")
val output = TransactionOutput(CurrencyUnits.zero, scriptPubKey)
val inputIndex = UInt32.zero
val btxsc = BaseTxSigComponent(spendingTx,inputIndex,output,Policy.standardScriptVerifyFlags)
val preExecution = PreExecutionScriptProgram(btxsc)
```
```scala
val result = ScriptInterpreter.run(preExecution)
// result: org.bitcoins.core.script.result.ScriptResult = ScriptOk
```

View File

@ -0,0 +1,141 @@
---
id: version-0.2.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, 0x39f30e63d03882325006e97c5a15e6d471a4c7d35112569d2352b052a091e3cf)
val mnemonicCode = MnemonicCode.fromEntropy(entropy)
// mnemonicCode: MnemonicCode = MnemonicCodeImpl(Vector(delay, observe, ocean, parrot, market, bomb, divorce, tag, labor, spawn, keen, pottery, bottom, glue, essence, car, final, trouble, start, gaze, claw, employ, monkey, type))
mnemonicCode.words // the phrase the user should write down
// res0: Vector[String] = Vector(delay, observe, ocean, parrot, market, bomb, divorce, tag, labor, spawn, keen, pottery, bottom, glue, essence, car, final, trouble, start, gaze, claw, employ, monkey, type) // 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 = BIP39SeedImpl(ByteVector(64 bytes, 0xd45cc7ef7aa2aae1a8cd90c91a4f79b866dd00a10cf8cdaae157a822167a4cc740b7364eb43f1474d8c86473db4faf845e6a9e3fd06ee39eeb493c751a0cdfee))
val xpriv = ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.SegWitMainNetPriv,
bip39Seed)
// xpriv: ExtPrivateKey = zprvAWgYBBk7JR8GjukHugLbrUkjRE3ycvmhRCT4cE2T2qU53j18nUjL4ocaDsXwBWYzU5u88ZFxQ42YWMLAT1S5V2wwcxgogsMrDQtNeLBwr3D
val xpub = xpriv.extPublicKey
// xpub: ExtPublicKey = zpub6jftahH18ngZxPpm1hscDchTyFtU2PVYnRNfQcS4bB13vXLHL23acbw459g4XxYYHfo44rTmYSXzBQzzBEVqT3PfPcqL69fpdrgkxMHuQCy
// 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 = zpub6qUM2b9Nq9v51X1sPsXpXWznJnBhvhHUfhrXvMFntXQT8ZkK2tizi29cMm2HH3vb1Zz8CHb3933J9tvaH97GS4s6XUZQsrTYf7cWGYtmYLA
// 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 = Bech32Address(tb1quqvdsqdzt2nlszkfqsxndu5pg6ahzyjk2e5qmz)
// tada! We just generated an address you can send money to,
// without having access to the private key!
firstAccountAddress.value
// res2: String = tb1quqvdsqdzt2nlszkfqsxndu5pg6ahzyjk2e5qmz
// 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
```

View File

@ -0,0 +1,138 @@
---
id: version-0.2.0-txbuilder
title: TxBuilder example
original_id: txbuilder
---
Bitcoin-S features a transaction buidlder that constructs and signs Bitcoin
transactions. Here's an example of how to use it
```scala
import scala.concurrent._
import scala.concurrent.duration._
import org.bitcoins.core._
import number._
import config._
import currency._
import crypto._
import script.crypto._
import protocol.transaction._
import protocol.script._
import wallet.builder._
import wallet.fee._
import wallet.utxo._
implicit val ec: ExecutionContext = ExecutionContext.Implicits.global
// generate a fresh private key that we are going to use in the scriptpubkey
val privKey = ECPrivateKey.freshPrivateKey
val pubKey = privKey.publicKey
// 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)
val amount = 10000.satoshis
// this is the UTXO we are going to be spending
val utxo =
TransactionOutput(value = amount, scriptPubKey = creditingSpk)
// the private key that locks the funds for the script we are spending too
val destinationPrivKey = ECPrivateKey.freshPrivateKey
// the amount we are sending -- 5000 satoshis -- to the destinationSPK
val destinationAmount = 5000.satoshis
// the script that corresponds to destination private key, this is what is protecting the money
val destinationSPK =
P2PKHScriptPubKey(pubKey = destinationPrivKey.publicKey)
// this is where we are sending money too
// we could add more destinations here if we
// wanted to batch transactions
val destinations = {
val destination1 = TransactionOutput(value = destinationAmount,
scriptPubKey = destinationSPK)
List(destination1)
}
// 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 = List.empty,
outputs = List(utxo),
lockTime = UInt32.zero)
// 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)
// this contains all the information we need to
// validly sign the UTXO above
val utxoSpendingInfo = BitcoinUTXOSpendingInfo(outPoint = outPoint,
output = utxo,
signers = List(privKey),
redeemScriptOpt = None,
scriptWitnessOpt = None,
hashType =
HashType.sigHashAll,
conditionalPath =
ConditionalPath.NoConditionsLeft)
// all of the UTXO spending information, since we are only
//spending one UTXO, this is just one element
val utxos: List[BitcoinUTXOSpendingInfo] = List(utxoSpendingInfo)
// 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)
val changePrivKey = ECPrivateKey.freshPrivateKey
val changeSPK = P2PKHScriptPubKey(pubKey = changePrivKey.publicKey)
// the network we are on, for this example we are using
// the regression test network. This is a network you control
// on your own machine
val networkParams = RegTest
// Yay! Now we have a TxBuilder object that we can use
// to sign the TX.
val txBuilder: BitcoinTxBuilder = {
val builderF = BitcoinTxBuilder(
destinations = destinations,
utxos = utxos,
feeRate = feeRate,
changeSPK = changeSPK,
network = networkParams)
Await.result(builderF, 30.seconds)
}
// Let's finally produce a validly signed 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 UTXOSpendingInfo 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 = {
val signF = txBuilder.sign
Await.result(signF, 30.seconds)
}
```
```scala
signedTx.inputs.length
// res0: Int = 1
signedTx.outputs.length
// res1: Int = 2
//remember, you can call .hex on any bitcoin-s data structure to get the hex representation!
signedTx.hex
// res2: String = "0200000001aaa194af011ead436c86eddd507b9a02fc7b15b190d6975fa68757f5cf6ef640000000006a473044022070862947a8ee417f0873e9edb9484684c3671b109e1f69403135220bf4c9687c02207d2395edb2a88522d42fb3e34c6e86f8b81b333b18759dfb6a78ed978d30a07c01210342b79cc77b59e28a5f569348e9efd5fa9a37982f18c1d29b0818bc8890a1c60b000000000288130000000000001976a9146c9e69cc34268e73bbf02c0819d92db359385cd188aca6120000000000001976a914e5050227c7823cb7c5da0f8d879b1562b4ca581c88ac00000000"
```

View File

@ -0,0 +1,79 @@
---
id: version-0.2.0-getting-started
title: Add Bitcoin-S to your project
original_id: getting-started
---
## REPL
You can try out Bitcoin-S in a REPL in a matter of seconds. Run the provided
["try bitcoin-s"](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/try-bitcoin-s.sh)
script, which has no dependencies other than an installed JDK. The script
downloads and installs [Coursier](https://get-coursier.io/) and uses it to
fetch the [Ammonite](https://ammonite.io) REPL and the latest version of
Bitcoin-S. It then drops you into immediately into a REPL session.
```bash
$ curl -s https://raw.githubusercontent.com/bitcoin-s/bitcoin-s/master/try-bitcoin-s.sh | bash
Loading...
Welcome the Bitcoin-S REPL, powered by Ammonite
Check out our documentation and examples at
https://bitcoin-s.org/docs/getting-started
@ val priv = ECPrivateKey()
@ val pub = priv.publicKey
@ val spk = P2WPKHWitnessSPKV0(pub)
@ val address = Bech32Address(spk, MainNet)
@ address.value # Tada! You've just made a Bech32 address
res4: String = "bc1q7ynsz7tamtnvlmts4snrl7e98jc9d8gqwsjsr5"
```
## Getting prebuilt JARs
If you want to add Bitcoin-S to your project, follow the
instructions for your build tool
### sbt
Add this to your `build.sbt`:
```scala
libraryDependencies +="org.bitcoin-s" % "bitcoin-s-secp256k1jni" % "0.2.0"
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-core" % "0.2.0"
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-bitcoind-rpc" % "0.2.0"
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-eclair-rpc" % "0.2.0"
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit" % "0.2.0"
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-zmq" % "0.2.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 `0.2.0+113-52351447+20191215-2018-SNAPSHOT`.
To fetch snapshots, you will need to add the correct
resolver in your `build.sbt`:
```sbt
resolvers += Resolver.sonatypeRepo("snapshots")
```
### Mill
TODO
## Building JARs yourself
If you want to build Bitcoin-S JARs yourself, you need to use the
[sbt](https://www.scala-sbt.org/) build tool. Once you have sbt
installed, run `sbt publishLocal`. This places the required JAR
files in your `.ivy2/local` folder. On Linux, this is located at
`$HOME/.ivy2/local/` by default.

View File

@ -0,0 +1,123 @@
---
id: version-0.2.0-rpc-bitcoind
title: bitcoind/Bitcoin Core
original_id: rpc-bitcoind
---
> Note: `bitcoin-s-bitcoind-rpc` requires you to have `bitcoind` (Bitcoin Core daemon) installed. Grab this at [bitcoincore.org](https://bitcoincore.org/en/download/)
The Bitcoin Core RPC client in Bitcoin-S currently supports the Bitcoin Core 0.16 and 0.17
version lines. It can be set up to work with both local and remote Bitcoin Core servers.
## Connecting to a local `bitcoind` instance
### Getting started quickly, with default options:
```scala
import scala.concurrent._
import org.bitcoins.{rpc, core}
import core.currency.Bitcoins
import rpc.client.common._
import java.io._
implicit val ec: ExecutionContext = ExecutionContext.global
// this reads authentication credentials and
// connection details from the default data
// directory on your platform
val client = BitcoindRpcClient.fromDatadir(binary=new File("/path/to/bitcoind"), datadir=new File("/path/to/bitcoind-datadir"))
val balance: Future[Bitcoins] = for {
_ <- client.start()
balance <- client.getBalance
} yield balance
```
## Connecting to a remote `bitcoind`
First, we create a secure connection to our `bitcoind` instance by setting
up a SSH tunnel:
```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
import java.net.URI
import scala.concurrent._
import org.bitcoins.core.config._
import org.bitcoins.rpc.config._
import org.bitcoins.rpc.client.common._
val username = "FILL_ME_IN" //this username comes from 'rpcuser' in your bitcoin.conf file //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
)
}
implicit val ec: ExecutionContext = ExecutionContext.global
val rpcCli = BitcoindRpcClient(bitcoindInstance)
rpcCli.getBalance.onComplete { case balance =>
println(s"Wallet balance=${balance}")
}
```
## Error handling
All errors returned by Bitcoin Core are mapped to a corresponding
[`BitcoindException`](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
import org.bitcoins.rpc.client.common._
import org.bitcoins.rpc.BitcoindWalletException
import org.bitcoins.core.crypto._
import org.bitcoins.core.protocol._
import org.bitcoins.core.currency._
import java.io._
import scala.concurrent._
implicit val ec = ExecutionContext.global
// let's assume you have an already running client,
// so there's no need to start this one
val cli = BitcoindRpcClient.fromDatadir(binary=new File("/path/to/bitcoind"), datadir=new File("/path/to/bitcoind-datadir"))
// let's also assume you have a bitcoin address
val address: BitcoinAddress = ???
val txid: Future[DoubleSha256DigestBE] =
cli.sendToAddress(address, 3.bitcoins).recoverWith {
case BitcoindWalletException.UnlockNeeded(_) =>
cli.walletPassphrase("my_passphrase", 60).flatMap { _ =>
cli.sendToAddress(address, 3.bitcoins)
}
}
```

View File

@ -0,0 +1,29 @@
---
id: version-0.2.0-rpc-eclair
title: Eclair
original_id: rpc-eclair
---
This is a RPC client for [Eclair](https://github.com/acinq/eclair). It assumes that a bitcoind instance is running.
Currently this RPC client is written for [v0.2-beta8](https://github.com/ACINQ/eclair/releases/tag/v0.2-beta8) version of Eclair.
## Configuration of Eclair
Please see the configuration secion of the
[Eclair README](https://github.com/acinq/eclair#configuring-eclair).
## Starting the jar
You need to download the jar from the [Eclair GitHub](https://github.com/ACINQ/eclair/releases/tag/v0.2-beta8).
To run Eclair you can use this command:
```bash
$ java -jar eclair-node-0.2-beta8-52821b8.jar &
```
If you wish to start Eclair from the RPC client, you can do one of the following:
1. Construct a `EclairRpcClient` with the `binary` field set
2. Set the `ECLAIR_PATH` environment variable to the directory where the Eclair Jar is located.

View File

@ -0,0 +1,32 @@
---
id: version-0.2.0-rpc-clients-intro
title: Introduction
original_id: rpc-clients-intro
---
When working with Bitcoin applications, a common task to
accomplish is connecting to a service like Bitcoin Core,
and use that for tasks like generating addresses,
verifying payments and
monitoring the blockchain. This typically happens through
tools like `bitcoin-cli`, or the Bitcoin Core HTTP RPC
server interface. One big drawback to this, is that you
lose all type-safety in your application. Even if you
have a custom type that represents a Bitcoin transaction,
how do you get that to play nicely with the result that
Bitcoin Core gives you after signing a transaction? A
random hexadecimal string in a HTTP response could be
anything from a public key, a transaction or a block
header.
We've done all the mundane work of wiring requests and
responses from Bitcoin Core to the powerful and safe types
found in Bitcoin-S. We've also written a bunch of tests,
that verify that all of this actually work.
You'll know for sure that you're sending
a valid public key to `importmulti`, and you when doing
RPC calls like `getblockheader` we'll even parse the
hexadecimal string into a complete header that you can
interact with without goofing around with bits and bytes.
We currently have RPC clients for Bitcoin Core and Eclair.

View File

@ -0,0 +1,29 @@
---
id: version-0.2.0-windows-users
title: windows-users
original_id: windows-users
---
This will be a guide directed to Windows Users hoping to contribute to Bitcoin-s and its development.
## Bloop
Reference the `contributing.md` document for a more descriptive guide on what bloop is and how to use it.
When following the installation guide to bloop on their website you will use `scoop` to install `bloop`. After installation
there will more than likely be issues with `bloop` looking for `.jar` files in a folder like `C:\root\.ivy2\`. The true installation
location of the `.ivy2` folder is likely in `C:\users\{your_username}\.ivy2\`. Once we have located our `.ivy2` folder
we will want to direct `bloop` on how to find the files in the new location. I found it was quite simple to use Windows
symbolic link (Note: if you are a running a Linux Subsystem this will also influence where your Linux bloop looks for this directory and thus will break as subsystems will have to use the `mnt` folder to access `C` drive).
To create the symbolic link we run
```mklink /D C:\root\.ivy2\ C:\users\{your_username}\.ivy2\```
the `/D` option specifies that it is a directory. You will need to run this command in `cmd.exe` instead of `Windows Powershell` as it is not a standalone executable.
## Running a Bitcoind node
Currently there are written changes in code to make it so you are run a node on Windows. Path specs are based on out of box installation. In the case you receive an error like `Could not locate bitcoind on user PATH`
then you will need to do some tweaking of either the code or moving your folder into the correct location. Currently this is specified by the `DEFAULT_DATADIR` in `BitcoindConfig` within `Bitcoind-rpc`. When you install bitcoin out of box there are 2 folders
created, 1 which is contained in the location on the wiki and that contains data generated after syncing. The current directory `DEFAULT_DATADIR` is pointing at which contains the `bitcoind.exe` file.
That file is what is necessary to start up a bitcoind node.
## Running Linux on a Windows Machine
If you are looking to develop in a Linux environment on a Windows Machine I have had success with [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
If you are interested in working on both Linux and Windows for development reasons I would also recommend [Windows Terminal](https://github.com/microsoft/terminal) as a way to hold many different terminals all in one window including your
Linux distro if you set up a WSL. With that being said the most important thing to consider when running Linux on a Windows Machine while also developing on Windows, there will be differences in setting up directories and pathing especially for `bloop`. I will update if I find a functional workaround.
Currently trying to get bloop working on a WSL that already has linked folders to have bloop work on Windows. Linux cannot recognize the file paths for directories as they are in Windows format, trying to find a workaround.

View File

@ -0,0 +1,34 @@
{
"version-0.2.0-docs": {
"Getting started": [
"version-0.2.0-getting-started"
],
"Core module": [
"version-0.2.0-core/core-intro",
"version-0.2.0-core/addresses",
"version-0.2.0-core/hd-keys",
"version-0.2.0-core/txbuilder"
],
"RPC clients": [
"version-0.2.0-rpc/rpc-clients-intro",
"version-0.2.0-rpc/rpc-eclair",
"version-0.2.0-rpc/rpc-bitcoind"
],
"Applications": [
"version-0.2.0-applications/chain",
"version-0.2.0-applications/cli",
"version-0.2.0-applications/configuration",
"version-0.2.0-applications/key-manager",
"version-0.2.0-applications/node",
"version-0.2.0-applications/server",
"version-0.2.0-applications/wallet"
],
"Contributing": [
"version-0.2.0-contributing",
"version-0.2.0-contributing-website"
],
"Security": [
"version-0.2.0-security"
]
}
}

View File

@ -1,3 +1,4 @@
[
"0.2.0",
"0.1.0"
]