mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 21:34:39 +01:00
Add website version for 0.1.0
This commit is contained in:
parent
0ffee0097e
commit
b0bb5adf22
86
website/versioned_docs/version-0.1.0/contributing-website.md
Normal file
86
website/versioned_docs/version-0.1.0/contributing-website.md
Normal file
@ -0,0 +1,86 @@
|
||||
---
|
||||
id: version-0.1.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
|
||||
$ sbt
|
||||
> doc/mdoc --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.
|
175
website/versioned_docs/version-0.1.0/contributing.md
Normal file
175
website/versioned_docs/version-0.1.0/contributing.md
Normal file
@ -0,0 +1,175 @@
|
||||
---
|
||||
id: version-0.1.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
|
||||
|
||||
## Developer productivity
|
||||
|
||||
### 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).
|
68
website/versioned_docs/version-0.1.0/core/addresses.md
Normal file
68
website/versioned_docs/version-0.1.0/core/addresses.md
Normal file
@ -0,0 +1,68 @@
|
||||
---
|
||||
id: version-0.1.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(9a56486eeeef146555ee6dcde9039d205649d896155855b44c8296c0464dfdb0,true)
|
||||
val pubkey = privkey.publicKey
|
||||
// pubkey: crypto.ECPublicKey = ECPublicKey(0367b1156e1c11d69de16ff76b2c4b249396f9bb86cf5933837e147638cdae9485)
|
||||
|
||||
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(tb1qde6457araspjqa4hjkqfsm8z3jax97exte40h9)
|
||||
```
|
||||
|
||||
## 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 = mqb1D1swAkQEAsXbznjis6CWcKp7241cM8
|
||||
```
|
||||
|
192
website/versioned_docs/version-0.1.0/core/core-intro.md
Normal file
192
website/versioned_docs/version-0.1.0/core/core-intro.md
Normal file
@ -0,0 +1,192 @@
|
||||
---
|
||||
id: version-0.1.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
|
||||
2. [`crypto`](/api/org/bitcoins/core/crypto) - cryptograhic functionality used in Bitcoin and Lightning
|
||||
3. [`script`](/api/org/bitcoins/core/script) - an implementation of [Script](https://en.bitcoin.it/wiki/Script) - the programming language in Bitcoin
|
||||
4. [`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.
|
||||
5. [`config`](/api/org/bitcoins/core/config) - Contains information about a chain's genesis block and DNS seeds
|
||||
6. [`number`](/api/org/bitcoins/core/number) - Implements number types that are native in C, i.e. `UInt8`, `UInt32`, `UInt64`, etc.
|
||||
7. [`currency`](/api/org/bitcoins/core/currency) - Implements currency units in the Bitcoin protocol
|
||||
8. [`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)
|
||||
9. [`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 = "0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f8$9c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1$a02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e$90c865c2f6f7a9710a474154ab1423abb5b9288ac00000000"
|
||||
// hexTx: String = "0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f8$9c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1$a02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e$90c865c2f6f7a9710a474154ab1423abb5b9288ac00000000"
|
||||
```
|
||||
|
||||
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`
|
||||
|
||||
BIP39 mnemonic phrases are the most common way of creating backups of wallets.
|
||||
They are between 12 and 24 words the user writes down, and can later be used to restore
|
||||
their bitcoins. From the mnemonic phrase we generate a wallet seed, and that seed
|
||||
can be used to generate what's called an extended private key
|
||||
([`ExtPrivateKey`](/api/org/bitcoins/core/crypto/ExtPrivateKey) in Bitcoin-S).
|
||||
|
||||
Here's an example:
|
||||
|
||||
```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, 0x574d20e6ea2087645573fba9f81e8ce37978145d099093e973e19dc5bbec4a28)
|
||||
|
||||
val mnemonicCode = MnemonicCode.fromEntropy(entropy)
|
||||
// mnemonicCode: MnemonicCode = MnemonicCodeImpl(Vector(firm, harbor, defy, stairs, anchor, rate, fiction, legal, prepare, science, permit, shoulder, nurse, any, injury, craft, negative, entire, wear, describe, forum, wage, chunk, buyer))
|
||||
|
||||
mnemonicCode.words // the phrase the user should write down
|
||||
// res0: Vector[String] = Vector(firm, harbor, defy, stairs, anchor, rate, fiction, legal, prepare, science, permit, shoulder, nurse, any, injury, craft, negative, entire, wear, describe, forum, wage, chunk, buyer) // 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, 0x736cda24cdaa9d037276191a07f0bd067c0bf75366241f35830f7d99741428ec2d03fd7ff896e7f30f4776bba8bfa5fb4fc9692443f20d23c840d0a59a774541))
|
||||
|
||||
val xpriv = ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.SegWitMainNetPriv,
|
||||
bip39Seed)
|
||||
// xpriv: ExtPrivateKey = zprvAWgYBBk7JR8GjK4toR1D3nBk7hzpR4Ub6teUFG29phdrKk9f1ERymniBTYR4586pZiTwC6FyCgrnG9SEeRNRqBehteqSsydiezHJfJTDPZL
|
||||
val xpub = xpriv.extPublicKey
|
||||
// xpub: ExtPublicKey = zpub6jftahH18ngZwo9MuSYDQv8UfjqJpXCSU7a53eRmP3AqCYUoYmkEKb2fJpPXe2QLTDunZhBE8j8Bg5twZ3SVvpSb2suuSbmp3zEW5XTV6vM
|
||||
|
||||
// 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
|
||||
```
|
||||
|
||||
### 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 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
|
||||
```
|
||||
|
142
website/versioned_docs/version-0.1.0/core/hd-keys.md
Normal file
142
website/versioned_docs/version-0.1.0/core/hd-keys.md
Normal file
@ -0,0 +1,142 @@
|
||||
---
|
||||
id: version-0.1.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, 0x36b8317570cf6a0dd2838b07cb02be971c82b996d44b987530c506f2c8fef6fd)
|
||||
|
||||
val mnemonicCode = MnemonicCode.fromEntropy(entropy)
|
||||
// mnemonicCode: MnemonicCode = MnemonicCodeImpl(Vector(cute, screen, front, thunder, wall, alone, energy, imitate, amazing, fix, quick, comfort, sight, fresh, forget, maximum, observe, praise, course, assume, clutch, legal, swim, pink))
|
||||
|
||||
mnemonicCode.words // the phrase the user should write down
|
||||
// res0: Vector[String] = Vector(cute, screen, front, thunder, wall, alone, energy, imitate, amazing, fix, quick, comfort, sight, fresh, forget, maximum, observe, praise, course, assume, clutch, legal, swim, pink) // 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, 0xf6bc20ecba293c86f6c5672ebda54b5eed4f718333ea89de7a782385d61b42b39b15751adbe3247f5baebdcaf57e60ca3eb8b1845cd61166d6b37b21cf7ad8cb))
|
||||
|
||||
val xpriv = ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.SegWitMainNetPriv,
|
||||
bip39Seed)
|
||||
// xpriv: ExtPrivateKey = zprvAWgYBBk7JR8GjdnxjoVfK12jRpQxjXM2hA6wkDwq624VkBcGsgprix1DtgtDMwtmahSBmfypGafJNFxLvjpMkKmH2nVq1cM4ddoFYkuRmhA
|
||||
val xpub = xpriv.extPublicKey
|
||||
// xpub: ExtPublicKey = zpub6jftahH18ngZx7sRqq2fg8yTyrFT8z4t4P2YYcMSeMbUcywRRE97GkKhjzA4s36tsp3ijNCSchMfUcrFTGWbCPzteku1CjmHmDqET8FeGSa
|
||||
|
||||
// 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 = zpub6rkV5qiypfYUAmMWAvq6vGDnQCDRRnMPyGCG24YJKhAtCW87eicxGEoVu62CC8ZRkEsFYTZr4cSNDnoD7z7nuW2i8yGTTFsZTZB3ePRJHR8
|
||||
|
||||
// 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(tb1q5stv7ruhmnn58q2kwlrjscdld3pwwtd8d4prw6)
|
||||
|
||||
// tada! We just generated an address you can send money to,
|
||||
// without having access to the private key!
|
||||
firstAccountAddress.value
|
||||
// res2: String = tb1q5stv7ruhmnn58q2kwlrjscdld3pwwtd8d4prw6
|
||||
|
||||
// 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
|
||||
```
|
||||
|
137
website/versioned_docs/version-0.1.0/core/txbuilder.md
Normal file
137
website/versioned_docs/version-0.1.0/core/txbuilder.md
Normal file
@ -0,0 +1,137 @@
|
||||
---
|
||||
id: version-0.1.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(currencyUnit = 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(currencyUnit = 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)
|
||||
|
||||
// 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 = "02000000011246e1e161b239715655cd320f01dbf182614c85a788bb61c8d393b740c355da000000006a47304402202221bf73ec3ee6d0e10b1804eb6926313a1ca927f266bb46122780df519881c502207d121507813ec4e6c5ee9c6d782252829e05e77418a41ae3c7aa74f45e41426401210282d386db7421d36dcd8a130725429789bf7f817a595a99aaad502e9e49c8d281000000000288130000000000001976a9145093de131f5ca169aed2c3f2c85eb77074920bea88aca6120000000000001976a9149e2f2ba93f21679d7676aa643489d7eca2362cb588ac00000000"
|
||||
```
|
||||
|
70
website/versioned_docs/version-0.1.0/getting-started.md
Normal file
70
website/versioned_docs/version-0.1.0/getting-started.md
Normal file
@ -0,0 +1,70 @@
|
||||
---
|
||||
id: version-0.1.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"
|
||||
```
|
||||
|
||||
## Build tools
|
||||
|
||||
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.1.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-core" % "0.1.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-bitcoind-rpc" % "0.1.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-eclair-rpc" % "0.1.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit" % "0.1.0"
|
||||
|
||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-zmq" % "0.1.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.1.0+45-91633375+20190620-1322-SNAPSHOT`.
|
||||
|
||||
To fetch snapshots, you will need to add the correct
|
||||
resolver in your `build.sbt`:
|
||||
|
||||
```sbt
|
||||
resolvers += Resolver.sonatypeRepo("snapshots")
|
||||
```
|
||||
|
||||
|
||||
### Mill
|
||||
|
||||
TODO
|
109
website/versioned_docs/version-0.1.0/rpc/bitcoind.md
Normal file
109
website/versioned_docs/version-0.1.0/rpc/bitcoind.md
Normal file
@ -0,0 +1,109 @@
|
||||
---
|
||||
id: version-0.1.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 akka.actor.ActorSystem
|
||||
|
||||
import org.bitcoins.{rpc, core}
|
||||
import core.currency.Bitcoins
|
||||
import rpc.client.common._
|
||||
|
||||
implicit val system = ActorSystem.create()
|
||||
implicit val ec: ExecutionContext = system.dispatcher
|
||||
|
||||
// this reads authentication credentials and
|
||||
// connection details from the default data
|
||||
// directory on your platform
|
||||
val client = BitcoindRpcClient.fromDatadir()
|
||||
|
||||
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 akka.actor.ActorSystem
|
||||
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 system: ActorSystem = ActorSystem.create()
|
||||
implicit val ec: ExecutionContext = system.dispatcher
|
||||
|
||||
val rpcCli = new BitcoindRpcClient(bitcoindInstance)
|
||||
|
||||
rpcCli.getBalance.onComplete { case balance =>
|
||||
println(s"Wallet balance=${balance}")
|
||||
system.terminate()
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
To test the Bitcoin-S RPC project you need both version 0.16 and 0.17 of Bitcoin Core. A list of current and previous releases can be found [here](https://bitcoincore.org/en/releases/).
|
||||
|
||||
You then need to set environment variables to indicate where Bitcoin-S can find the different versions:
|
||||
|
||||
```bash
|
||||
$ export BITCOIND_V16_PATH=/path/to/v16/bitcoind
|
||||
$ export BITCOIND_V17_PATH=/path/to/v17/bitcoind
|
||||
```
|
||||
|
||||
If you just run tests testing common functionality it's enough to have either version 0.16 or 0.17 on your `PATH`.
|
||||
|
||||
To run all RPC related tests:
|
||||
|
||||
```bash
|
||||
$ bash sbt bitcoindRpcTest/test
|
||||
```
|
||||
|
28
website/versioned_docs/version-0.1.0/rpc/eclair.md
Normal file
28
website/versioned_docs/version-0.1.0/rpc/eclair.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
id: version-0.1.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 &
|
||||
```
|
||||
|
||||
Alternatively you can set the `ECLAIR_PATH` env variable and then you can start Eclair with the `start` method on `EclairRpcClient`.
|
||||
|
||||
**YOU NEED TO SET `ECLAIR_PATH` CORRECTLY TO BE ABLE TO RUN THE UNIT TESTS**
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
id: version-0.1.0-rpc-clients-intro
|
||||
title: Introduction
|
||||
original_id: rpc-clients-intro
|
||||
---
|
||||
|
||||
Bitcoin-S contains RPC clients for interacting with both Bitcoin Core and Eclair.
|
73
website/versioned_docs/version-0.1.0/security.md
Normal file
73
website/versioned_docs/version-0.1.0/security.md
Normal file
@ -0,0 +1,73 @@
|
||||
---
|
||||
id: version-0.1.0-security
|
||||
title: Security
|
||||
original_id: security
|
||||
---
|
||||
|
||||
The Bitcoin-S developers take security very seriously. This library has
|
||||
very few dependencies (at least in the `core` module), which is for
|
||||
security reasons.
|
||||
|
||||
## Disclosure
|
||||
|
||||
If you have any security disclosures related to Bitcoin-S, please send an
|
||||
email to either [stewart.chris1234@gmail.com](mailto:stewart.chris1234@gmail.com?subject=Bitcoin-S%20Security%20Disclosure)
|
||||
or [torkel@rogstad.io](mailto:torkel@rogstad.io?subject=Bitcoin-S%20Security%20Disclosure).
|
||||
|
||||
If you want to encrypt said email (which you should), Torkel's key is available on [Keybase](https://keybase.io/torkelrogstad/pgp_keys.asc?fingerprint=c5dc349be6daa834ad9d59d712beee5312accec4), and Chris' is posted here:
|
||||
|
||||
```
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1
|
||||
|
||||
mQINBFku8rYBEACub6cz6nAy/MHK2TlTztkSJbNpc2B3tZoVCKRz987yLX578JiO
|
||||
EDYosAsD4b4nIjY1O6kD5FUjoJttQO+7IR8RwkmBFRsPqXaryrGr69FqaPlGSMLi
|
||||
uNVlawe0qMY79DPNw03Pu2tdgiq94sWplmOnuyQqcg2lkoK1+8/DXX3801s164wq
|
||||
4ZCCmkAAxJDhoLTyXB6LNI586vJhQ5+SVh8z/kAtp6NVXU5v2LcnkrqlX4oaakbt
|
||||
nY2FYpAZgEI8T+Fg+btGbt3muajhM9ooq0LBtaIMwgcTC4JPyFg6acWaluMGCOtW
|
||||
k1j8eu2/J4ly27YGCtWoDwrDen5qzHF6mm1HI4ko9fG2L4SxxXkl7DpGgtR71D1R
|
||||
mSA9yot8oPwWW1NRncIct188uRuhy4CJIylNU88iqgpUZfYRqwaDl2KCrEbetGMT
|
||||
yZSBVyilXdNjzFUJFtOPAxKmYPztUcEL1hEyGOu03YFt3FQr7QHhNR8+v688DdH4
|
||||
QHpwcrXkB0x/wq18tCO6gNTbnt94VR4PJUvz3BjP7XrHGn3ljKt5PPHO7cmPkDH5
|
||||
/iP928VC1U5FjAJh6dpsGgFb7k51CKx9bUJRDmL3GUMxFvmo+4YZpTKS5G+Ighs3
|
||||
vLIzO1X0aV5b4mltn4Fz4o/Cp+CSVqK//YnetezkmrvwQ2u/iOGeqRKhXwARAQAB
|
||||
tCtDaHJpcyBTdGV3YXJ0IDxzdGV3YXJ0LmNocmlzMTIzNEBnbWFpbC5jb20+iQI+
|
||||
BBMBAgAoAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCWxW1AAUJBakpQwAK
|
||||
CRCYRuzvvweIvijkD/0RQzQAWcJY5XJ503vj0CidzKym4ueykxhgISiZ+hmjr+u5
|
||||
/Poceo5z3nXj1zI8/yMIb//7WRiX61+JGFKwN/OsM07KHa/J8Rf3NCASO2hYCGjq
|
||||
ev0UOWUeSqHwN8zr4kAY9hKZJVR7byKmYV/iqmuAFTB4Nrs8567CzqKaPezB1mKv
|
||||
JMTxx4XiL4M6cFiBSbCBi0qGYS6M0zBETJvFAmSh3H3PtUUdGz0kAyE2Ju11qhPh
|
||||
yZVCjILnzHbsguqPSPsj3Cba6+WcbGzm7HIBPdZDjIvcnuw3Mq8kjtcpOWTMoGP1
|
||||
q9xHioP97Gh+E+z7iFo8g2NszZ1wEzL4k3TnO0keknOmfOVn5zSINp6M8CHCTbzr
|
||||
ls+qqHjcbAfs5BbNRMXxapO78kvSQSDenRjpC7JCl3FIwWqoMMi7T3PIYVFQfMG+
|
||||
EyC3UMVOGmIDavw6yDCCdILcGeMdafEuzZmmV3Qvtt3LsqQjjm+TyBhWazRR+9sJ
|
||||
kRgSdvBkF8XgqyOpaLffWPoKxnaQtJwylQnYuUM8kLP52aH2C9ctKxLChu1BDmZm
|
||||
aWZNpm8h9jySeybQSBlMeDd8TrscuGJ8qBEOfREuv7fqYxsIi+G74+9h5kjiOe+y
|
||||
hkIkSI440mAHRIoCyAkBx4EFZN5lRdYShRGRQrCWD/RrFssABmXhBik707V0nLkC
|
||||
DQRZLvK2ARAA1gn4P9fm9KJpYuwYfxwrl0VfDPMNct5dDY6zbdQGV3djBTcuyeVU
|
||||
EL6w4rRfF1aPFFEXGhT2zn2tPY410fswTNANLKuP/sFEiGEfaMjmYu0DucCMyznK
|
||||
KMbE5FGD/ue0SHAN2K+A13OkPVv6kabu7XiK2QzYBrw1Lk7kGhSqMb8t3hVs0A9B
|
||||
iAqWFhSIBfmnd5SKyJKNksv7DuBcgK9Xjszlbr2gV0v1kc0aMHGdZH4omB5qmq8I
|
||||
aFkgZcY3MbA1zmetd1YauwzhZCFyTFcebm9trTn4D5htHGgXSehP3DMc4y9HVaLL
|
||||
rANAi0Ykk7Bi+BmYHkjsvt7FZj2/V/KWkwgiPjEBvnKX3iWpbJdqU2os9VZM3ctB
|
||||
WaE4pwsXt1kpiEgc/qUJ2xQL3po0dTO8q5heE6iZUNlD+xBLwpUxGjS8rN+V0LCt
|
||||
muqtZ8N8lSZD5U1XVVEpEdfe8lPKQ0wvjZZUTjix1j18mhiwE+cC66JNyM3mlMUx
|
||||
GKHg6M8nnXxTSbv2ogj7wXmqPF5dq5uGzCeDhdnR5tRmNQCpW/QUq8AJzV7VXRJl
|
||||
+qZXar7DgbGUeRBY4M3LJptYUYqJ3LdxYPAO0AeKdlO0e843BaeG1ASGlhCZRGOn
|
||||
Z0xYL7wBiVgwtx57y7D1zpQE1a9Mh7+jnUnH4tplYv70TsQ9wF5yuRsAEQEAAYkC
|
||||
JQQYAQIADwIbDAUCWxW0LAUJBakobgAKCRCYRuzvvweIvhSvD/0RlNWzls+OlLqc
|
||||
6NT/ZGGpECntrfTpQqA0MakuuIkf6/RgBU4OfHqqcBrG8onV1vuu0hH0KnYvv658
|
||||
01PHRthIZN1K/+jcaIdNkOLbl9k9rWaDxKkHzH+IcIF61b6oCW86ffZ1yzZE2nxY
|
||||
zjO0MVM4IlUxtHbrItVj5Itfj7QxPf1YdmLxO/xH2NRbmVwwTSKe4/xK3v1LSxlH
|
||||
R5vknUWIT69VJoINB7jye/aSpBYpJgxXXiGbdYyt6fLyLxds7HXLJ6v6SfBKLuvm
|
||||
qXsDWX5Jyv7EWzzHgl7iCIkCe9tr8ic9IyyWiRn5bjoo5vVFVMYWU/ZtGpYerAh/
|
||||
sp8M09q7OeJbtbYkh9Nqz78ALt7ldT+PeAmqBVqb188F3tG8yG9lQNy43bk90Q8N
|
||||
o7ZpjxlpKFYoSq/Ow7TZgMCdMPkGbcCaSkGDv/McGsaOa7IYf+7n/yE0xMSb0x5A
|
||||
wyaXSLZjScTPiKGAP4fAf6hb0H1Je/69DOJynaODONAYfmlM+9WQjuVlQ3J0rlcK
|
||||
Cgvon6XyxrZ4q1tKheAxOmyM0OSuPYyeXSqCYu5bt7MzNEDUChydZM3v1QvEB9iG
|
||||
6eLX7fq2ipGGDoVl8y1yVRe4BWa3cJfCPC7jT+9VtD/qdlpHSwotYTWj5metYgqB
|
||||
LTIbdd7r9XCGoKIxMJRqNFXc8kylUg==
|
||||
=J0NH
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
```
|
||||
|
23
website/versioned_sidebars/version-0.1.0-sidebars.json
Normal file
23
website/versioned_sidebars/version-0.1.0-sidebars.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"version-0.1.0-docs": {
|
||||
"Getting started": [
|
||||
"version-0.1.0-getting-started"
|
||||
],
|
||||
"Core module": [
|
||||
"version-0.1.0-core/core-intro",
|
||||
"version-0.1.0-core/txbuilder"
|
||||
],
|
||||
"RPC clients": [
|
||||
"version-0.1.0-rpc/rpc-clients-intro",
|
||||
"version-0.1.0-rpc/rpc-eclair",
|
||||
"version-0.1.0-rpc/rpc-bitcoind"
|
||||
],
|
||||
"Contributing": [
|
||||
"version-0.1.0-contributing",
|
||||
"version-0.1.0-contributing-website"
|
||||
],
|
||||
"Security": [
|
||||
"version-0.1.0-security"
|
||||
]
|
||||
}
|
||||
}
|
3
website/versions.json
Normal file
3
website/versions.json
Normal file
@ -0,0 +1,3 @@
|
||||
[
|
||||
"0.1.0"
|
||||
]
|
Loading…
Reference in New Issue
Block a user