mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 18:47:38 +01:00
Add 1.9.4 website, add 1.9.4 release notes (#4726)
* Add 1.9.4 website, add 1.9.4 release notes * Add versioned sidebars * Bump more versions to 1.9.4 * update release notes
This commit is contained in:
parent
2d83210ba3
commit
0cfad33fae
16 changed files with 1502 additions and 27 deletions
49
README.md
49
README.md
|
@ -1,6 +1,5 @@
|
||||||

|

|
||||||
[](https://github.com/bitcoin-s/bitcoin-s/actions) [](https://coveralls.io/github/bitcoin-s/bitcoin-s?branch=master) [](https://github.com/bitcoin-s/bitcoin-s/actions) [](https://coveralls.io/github/bitcoin-s/bitcoin-s?branch=master) [](https://mvnrepository.com/artifact/org.bitcoin-s) [](https://gitter.im/bitcoin-s-core)
|
||||||
-brightgreen.svg)](https://mvnrepository.com/artifact/org.bitcoin-s) [](https://gitter.im/bitcoin-s-core)
|
|
||||||
|
|
||||||
Feature-rich toolkit for making Bitcoin and Lightning applications on the JVM.
|
Feature-rich toolkit for making Bitcoin and Lightning applications on the JVM.
|
||||||
|
|
||||||
|
@ -44,52 +43,52 @@ This link is intended for setting up development of bitcoin-s. If you want to ju
|
||||||
|
|
||||||
### Adding bitcoin-s to your library
|
### Adding bitcoin-s to your library
|
||||||
|
|
||||||
The latest release of bitcoin-s is `1.9.3`, here is how you can use the dependencies in your projects:
|
The latest release of bitcoin-s is `1.9.4`, here is how you can use the dependencies in your projects:
|
||||||
|
|
||||||
```
|
```
|
||||||
libraryDependencies += "org.bitcoin-s" % "bitcoin-s-secp256k1jni" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" % "bitcoin-s-secp256k1jni" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-core" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-core" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-crypto" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-crypto" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-chain" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-chain" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-dlc-oracle" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-dlc-oracle" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-oracle-explorer-client" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-oracle-explorer-client" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-app-commons" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-app-commons" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-db-commons" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-db-commons" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-fee-provider" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-fee-provider" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-bitcoind-rpc" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-bitcoind-rpc" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-eclair-rpc" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-eclair-rpc" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-lnd-rpc" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-lnd-rpc" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-key-manager" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-key-manager" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-node" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-node" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-dlc-node" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-dlc-node" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-wallet" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-wallet" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-dlc-wallet" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-dlc-wallet" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit-core" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit-core" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-zmq" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-zmq" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-tor" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-tor" % "1.9.4"
|
||||||
|
|
||||||
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-cli" % "1.9.3"
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-cli" % "1.9.4"
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
package org.bitcoins.node.constant
|
package org.bitcoins.node.constant
|
||||||
|
|
||||||
case object NodeConstants {
|
case object NodeConstants {
|
||||||
val userAgent = "/bitcoin-s:1.9.3/"
|
val userAgent = "/bitcoin-s:1.9.4/"
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import scala.util.Properties
|
||||||
|
|
||||||
object CommonSettings {
|
object CommonSettings {
|
||||||
|
|
||||||
val previousStableVersion: String = "1.9.3"
|
val previousStableVersion: String = "1.9.4"
|
||||||
|
|
||||||
private def isCI = {
|
private def isCI = {
|
||||||
Properties
|
Properties
|
||||||
|
|
174
release-notes/release-notes-1.9.4.md
Normal file
174
release-notes/release-notes-1.9.4.md
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
# 1.9.4
|
||||||
|
|
||||||
|
This release is backwards compatible with the 1.9.x series of bitcoin-s
|
||||||
|
|
||||||
|
See the individual module sections for more information on lower level updates to the codebase.
|
||||||
|
|
||||||
|
Want to get started quickly? See our `docker-compose.yml` file. [See instructions here](https://github.com/bitcoin-s/bitcoin-s/#docker)
|
||||||
|
|
||||||
|
If you are a typescript developer, [you can access the backend via our typescript library](https://github.com/bitcoin-s/bitcoin-s-ts)
|
||||||
|
|
||||||
|
# Executive Summary
|
||||||
|
|
||||||
|
This is a bug fix release. In our 1.9.3 release we did not successfully publish all jars for the libraries.
|
||||||
|
For more information see: https://github.com/bitcoin-s/bitcoin-s/issues/4725
|
||||||
|
|
||||||
|
This release drops support for Scala 2.12.x, which fixes this bug. It also updates some dependencies.
|
||||||
|
|
||||||
|
## Running bitcoin-s
|
||||||
|
|
||||||
|
If you want to run the standalone server binary, after verifying gpg signatures, you
|
||||||
|
can `unzip bitcoin-s-server-1.9.4.zip` and then run it with `chmod +x ./bin/bitcoin-s-server && ./bin/bitcoin-s-server` to start the node. You will need to
|
||||||
|
configure the node properly first, you can find example
|
||||||
|
configurations [here](https://bitcoin-s.org/docs/config/configuration#example-configuration-file).
|
||||||
|
|
||||||
|
You can then unzip the `bitcoin-s-cli-1.9.4.zip` folder and start using the `bitcoin-s-cli` like this:
|
||||||
|
|
||||||
|
```bashrc
|
||||||
|
./bin/bitcoin-s-cli --help
|
||||||
|
Usage: bitcoin-s-cli [options] [<cmd>]
|
||||||
|
|
||||||
|
-n, --network <value> Select the active network.
|
||||||
|
--debug Print debugging information
|
||||||
|
--rpcport <value> The port to send our rpc request to on the server
|
||||||
|
-h, --help Display this help message and exit
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information on what commands `bitcoin-s-cli` supports check the documentation, here is where to
|
||||||
|
start: https://bitcoin-s.org/docs/next/applications/server#server-endpoints
|
||||||
|
|
||||||
|
## Verifying signatures
|
||||||
|
|
||||||
|
This release is signed with [Chris's signing key](https://bitcoin-s.org/docs/next/security#disclosure) with
|
||||||
|
fingerprint `9234F4D6AF47C71B741A390F8976CA0AF71A7A2A`
|
||||||
|
|
||||||
|
To do the verification, first hash the executable using `sha256sum`. You should check that the result is listed in
|
||||||
|
the `SHA256SUMS.asc` file next to its file name. After doing that you can use `gpg --verify` to authenticate the
|
||||||
|
signature.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gpg -d SHA256SUMS.asc > SHA256SUMS.stripped
|
||||||
|
gpg: Signature made Mon 18 Apr 2022 02:19:54 PM CDT
|
||||||
|
gpg: using RSA key 9234F4D6AF47C71B741A390F8976CA0AF71A7A2A
|
||||||
|
gpg: Good signature from "Chris Stewart <stewart.chris1234@gmail.com>" [ultimate]
|
||||||
|
|
||||||
|
$ sha256sum -c SHA256SUMS.stripped
|
||||||
|
bitcoin-s_1.9.3-1_amd64.deb: OK
|
||||||
|
bitcoin-s-1.9.3.dmg: OK
|
||||||
|
bitcoin-s-bundle.msi: OK
|
||||||
|
bitcoin-s-cli-x86_64-apple-darwin: OK
|
||||||
|
bitcoin-s-cli-x86_64-pc-linux: OK
|
||||||
|
bitcoin-s-server-1.9.3.zip: OK
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Website
|
||||||
|
|
||||||
|
https://bitcoin-s.org/
|
||||||
|
|
||||||
|
### Releases
|
||||||
|
|
||||||
|
https://repo1.maven.org/maven2/org/bitcoin-s/
|
||||||
|
|
||||||
|
### Snapshot releases
|
||||||
|
|
||||||
|
https://oss.sonatype.org/content/repositories/snapshots/org/bitcoin-s/
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
# Modules
|
||||||
|
|
||||||
|
## app commons
|
||||||
|
|
||||||
|
2cfd6f3591 Allow for custom config file name (#4709)
|
||||||
|
|
||||||
|
## App server
|
||||||
|
|
||||||
|
7b7847885e Attempt to reduce redundant work on startup to speed up start up time (#4764)
|
||||||
|
7460dcd255 Parallelize running of individual migrations (#4761)
|
||||||
|
6b432ea509 Emit 2000th header received during IBD (#4719)
|
||||||
|
a36e55c892 Fix patterns I missed when updating logback (#4713)
|
||||||
|
|
||||||
|
## bitcoind rpc
|
||||||
|
|
||||||
|
0c05edd633 mask bitcoind password (#4763)
|
||||||
|
61d4882efd Implement retry of fetching bitcoind version when calling `clientF` (#4760)
|
||||||
|
|
||||||
|
## bundle
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
7d9d0c577f Run scalafmt (#4757)
|
||||||
|
7fe9bdbe35 re-add Compile / fork in server.sbt so we can run appServer from sbt console (#4730)
|
||||||
|
06844bcd13 Make docker publish use java 18 to avoid slick 3.4.0 issues (#4718)
|
||||||
|
d2fb3fc150 Revert "Make electron build use bitcoin-s-ts latest tag (#4701)" (#4711)
|
||||||
|
38725f0155 Make electron build use bitcoin-s-ts latest tag (#4701)
|
||||||
|
3ad43a8f86 ignore jakarta dependnecy in logback (#4707)
|
||||||
|
328e1653a9 Drop support for scalac `2.12.x` (#4704)
|
||||||
|
669eb03f93 2022 09 02 issue 4699 (#4700)
|
||||||
|
|
||||||
|
## chain
|
||||||
|
|
||||||
|
## Core
|
||||||
|
|
||||||
|
2f18f622ab Give BitcoinNetworks.knownNetworks proper type (#4766)
|
||||||
|
|
||||||
|
## Crypto
|
||||||
|
|
||||||
|
## db commons
|
||||||
|
|
||||||
|
## DLC node
|
||||||
|
|
||||||
|
16893f999e DLC connection checks and notifications (#4720)
|
||||||
|
|
||||||
|
## DLC wallet
|
||||||
|
|
||||||
|
26595ab3ac Fix bug where no exception was thrown if the acceptor did not have enough money (#4728)
|
||||||
|
|
||||||
|
## gui
|
||||||
|
|
||||||
|
## fee rate
|
||||||
|
|
||||||
|
## keymanager
|
||||||
|
|
||||||
|
## Lnd rpc
|
||||||
|
|
||||||
|
20ed1dcab0 Fix lnd default datadir (#4767)
|
||||||
|
8bbfbc89d7 Add handling so test lnd clients can be reached by docker (#4729)
|
||||||
|
1758197d58 Remove bitcoind as a dep for lnd (#4703)
|
||||||
|
|
||||||
|
## Lnurl
|
||||||
|
|
||||||
|
## node
|
||||||
|
|
||||||
|
fae1a53579 Bump `bitcoin-s.node.query-wait-time=120 seconds` (#4759)
|
||||||
|
|
||||||
|
## Oracle Explorer Client
|
||||||
|
|
||||||
|
## wallet
|
||||||
|
|
||||||
|
81cddc12df Remove checkRootAccount/downloadMissingUtxos (#4762)
|
||||||
|
2bf1c9d1a5 Try to debug what is happening on CI with zmq test (#4708)
|
||||||
|
2448fe13e8 Revert the unique outpoint index DB migration (#4652)
|
||||||
|
|
||||||
|
## testkit-core
|
||||||
|
|
||||||
|
## testkit
|
||||||
|
|
||||||
|
018a6e58ee Add [regtest] section to fixture config (#4717)
|
||||||
|
|
||||||
|
## tor
|
||||||
|
|
||||||
|
1571b85819 Bump tor timeout to 120 seconds (#4723)
|
||||||
|
|
||||||
|
## Website
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
2d83210ba3 Update flyway-core to 9.2.3 (#4744)
|
||||||
|
12326c7f33 Update sqlite-jdbc to 3.39.3.0 (#4755)
|
||||||
|
6bfb669343 Update akka deps (#4724)
|
||||||
|
fd7bef3aa7 Try out slick 3.4.0-RC3 (#4620)
|
||||||
|
3ee4fe1138 Upgrade dependencies (#4705)
|
59
website/versioned_docs/version-1.9.4/core/addresses.md
Normal file
59
website/versioned_docs/version-1.9.4/core/addresses.md
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
id: version-1.9.4-addresses
|
||||||
|
title: Generating Addresses
|
||||||
|
original_id: addresses
|
||||||
|
---
|
||||||
|
|
||||||
|
Almost all Bitcoin applications need to generate addresses
|
||||||
|
for their users somehow. There's a lot going on in getting
|
||||||
|
a correct bitcoin address, but our APIs make it possible to
|
||||||
|
to get started with all types of addresses in a matter of
|
||||||
|
minutes.
|
||||||
|
|
||||||
|
## Generating SegWit (bech32) addresses
|
||||||
|
|
||||||
|
Generating native SegWit addresses in the bech32 format
|
||||||
|
is something that all Bitcoin applications should enable,
|
||||||
|
as it makes the transaction fees less expensive, and also
|
||||||
|
makes the addresses more readable by humans. However, it
|
||||||
|
has seen slower than necessary adoption. With Bitcoin-S
|
||||||
|
you can generate bech32 addresses in four(!) lines of code
|
||||||
|
(not counting comments and imports), so now there's no
|
||||||
|
reason to keep using legacy transaction formats.
|
||||||
|
|
||||||
|
|
||||||
|
```scala
|
||||||
|
// this generates a random private key
|
||||||
|
val privkey = ECPrivateKey()
|
||||||
|
// privkey: ECPrivateKey = Masked(ECPrivateKey)
|
||||||
|
val pubkey = privkey.publicKey
|
||||||
|
// pubkey: org.bitcoins.crypto.ECPublicKey = ECPublicKey(02e34cdcd460cd8299fe9cafd89179c39a9e2983aa6860d95ad785c2ed18a10013)
|
||||||
|
|
||||||
|
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 = tb1qfw3k6p04asktvrm7zakdq3lnh8x9a507snklww
|
||||||
|
|
||||||
|
println(segwitAddress.toString)
|
||||||
|
// tb1qfw3k6p04asktvrm7zakdq3lnh8x9a507snklww
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generating legacy (base58) addresses
|
||||||
|
|
||||||
|
If you need to generate legacy addresses for backwards
|
||||||
|
compatability reasons, that's also a walk in the park.
|
||||||
|
Take a look:
|
||||||
|
|
||||||
|
```scala
|
||||||
|
// we're reusing the same private/public key pair
|
||||||
|
// from before. don't do this in an actual application!
|
||||||
|
val legacyAddress = P2PKHAddress(pubkey, TestNet3)
|
||||||
|
// legacyAddress: P2PKHAddress = mnQtkUDEUKac7cVRiCfcCvBikyUqYzgj2m
|
||||||
|
|
||||||
|
println(legacyAddress.toString)
|
||||||
|
// mnQtkUDEUKac7cVRiCfcCvBikyUqYzgj2m
|
||||||
|
```
|
225
website/versioned_docs/version-1.9.4/core/dlc.md
Normal file
225
website/versioned_docs/version-1.9.4/core/dlc.md
Normal file
File diff suppressed because one or more lines are too long
145
website/versioned_docs/version-1.9.4/core/hd-keys.md
Normal file
145
website/versioned_docs/version-1.9.4/core/hd-keys.md
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
---
|
||||||
|
id: version-1.9.4-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, 0x269608303f30d6d02be81b3f2a059ddb14a61e39aff5d2d112a484b4974d43c5)
|
||||||
|
|
||||||
|
val mnemonicCode = MnemonicCode.fromEntropy(entropy)
|
||||||
|
// mnemonicCode: MnemonicCode = Masked(MnemonicCodeImpl)
|
||||||
|
|
||||||
|
mnemonicCode.words // the phrase the user should write down
|
||||||
|
// res0: Vector[String] = Vector(charge, raccoon, army, lazy, aspect, gym, quick, address, dish, expand, guess, renew, engine, audit, trade, wrong, spot, mass, powder, annual, enact, pluck, audit, peace) // the phrase the user should write down
|
||||||
|
|
||||||
|
// the password argument is an optional, extra security
|
||||||
|
// measure. all MnemonicCode instances will give you a
|
||||||
|
// valid BIP39 seed, but different passwords will give
|
||||||
|
// you different seeds. So you could have as many wallets
|
||||||
|
// from the same seed as you'd like, by simply giving them
|
||||||
|
// different passwords.
|
||||||
|
val bip39Seed = BIP39Seed.fromMnemonic(mnemonicCode,
|
||||||
|
password = "secret password")
|
||||||
|
// bip39Seed: BIP39Seed = Masked(BIP39SeedImpl)
|
||||||
|
|
||||||
|
val xpriv = ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.SegWitMainNetPriv,
|
||||||
|
bip39Seed)
|
||||||
|
// xpriv: ExtPrivateKey = Masked(ExtPrivateKeyImpl)
|
||||||
|
val xpub = xpriv.extPublicKey
|
||||||
|
// xpub: ExtPublicKey = zpub6jftahH18ngZx3FovrPbtTU1x5yryL1S5f42bK9PLq5EMTPdTUFWQGpqMfaqi9kJfosg8XRuXMStaVTB9mtZfqozGYksnKgTUedMcxiTvim
|
||||||
|
|
||||||
|
// 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 = zpub6s5dzUak5UZuGtENZUvtjB89uFuhYqN9E38bB4Lp6yuR454cibJVWcsyvPYQtMyu5xeWadDWMKSPkTSD5Mye8RcU7fY7x43wvp6CrVFFJCT
|
||||||
|
|
||||||
|
// 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 = tb1q3askd35zqpt9vszkvvffxkdsycn3sky2pqz54c
|
||||||
|
|
||||||
|
// tada! We just generated an address you can send money to,
|
||||||
|
// without having access to the private key!
|
||||||
|
firstAccountAddress.value
|
||||||
|
// res2: String = tb1q3askd35zqpt9vszkvvffxkdsycn3sky2pqz54c
|
||||||
|
|
||||||
|
// you can now continue deriving addresses from the same public
|
||||||
|
// key, by imitating what we did above. To get the next
|
||||||
|
// HD path to generate an address at:
|
||||||
|
val nextAddressPath: SegWitHDPath = firstAddressPath.next
|
||||||
|
// nextAddressPath: SegWitHDPath = m/84'/0'/0'/0/1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Signing things with HD keys
|
||||||
|
|
||||||
|
Please see [sign.md](../crypto/sign.md) for information on how to sign things with HD keys.
|
158
website/versioned_docs/version-1.9.4/core/txbuilder.md
Normal file
158
website/versioned_docs/version-1.9.4/core/txbuilder.md
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
---
|
||||||
|
id: version-1.9.4-txbuilder
|
||||||
|
title: TxBuilder Example
|
||||||
|
original_id: txbuilder
|
||||||
|
---
|
||||||
|
|
||||||
|
Bitcoin-S features a transaction building API that allows you to construct and sign Bitcoin transactions. Here's an example of how to use it
|
||||||
|
|
||||||
|
|
||||||
|
```scala
|
||||||
|
implicit val ec: ExecutionContext = ExecutionContext.Implicits.global
|
||||||
|
// ec: ExecutionContext = scala.concurrent.impl.ExecutionContextImpl$$anon$3@6497e290[Running, parallelism = 16, size = 0, active = 0, running = 0, steals = 493, tasks = 0, submissions = 0]
|
||||||
|
|
||||||
|
// Initialize a transaction builder
|
||||||
|
val builder = RawTxBuilder()
|
||||||
|
// builder: RawTxBuilder = RawTxBuilder()
|
||||||
|
|
||||||
|
// generate a fresh private key that we are going to use in the scriptpubkey
|
||||||
|
val privKey = ECPrivateKey.freshPrivateKey
|
||||||
|
// privKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||||
|
val pubKey = privKey.publicKey
|
||||||
|
// pubKey: ECPublicKey = ECPublicKey(038839cc58d1e077d426f550d13c0dc5bff744f749e4ea17f9c186ceb4e11ad130)
|
||||||
|
|
||||||
|
// this is the script that the TxBuilder is going to create a
|
||||||
|
// script signature that validly spends this scriptPubKey
|
||||||
|
val creditingSpk = P2PKHScriptPubKey(pubKey = privKey.publicKey)
|
||||||
|
// creditingSpk: P2PKHScriptPubKey = pkh(0ba1ff18b17397b9487188bf22c6b9f877d7831f)
|
||||||
|
val amount = 10000.satoshis
|
||||||
|
// amount: Satoshis = 10000 sats
|
||||||
|
|
||||||
|
// this is the UTXO we are going to be spending
|
||||||
|
val utxo =
|
||||||
|
TransactionOutput(value = amount, scriptPubKey = creditingSpk)
|
||||||
|
// utxo: TransactionOutput = TransactionOutput(10000 sats,pkh(0ba1ff18b17397b9487188bf22c6b9f877d7831f))
|
||||||
|
|
||||||
|
// the private key that locks the funds for the script we are spending too
|
||||||
|
val destinationPrivKey = ECPrivateKey.freshPrivateKey
|
||||||
|
// destinationPrivKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||||
|
|
||||||
|
// the amount we are sending -- 5000 satoshis -- to the destinationSPK
|
||||||
|
val destinationAmount = 5000.satoshis
|
||||||
|
// destinationAmount: Satoshis = 5000 sats
|
||||||
|
|
||||||
|
// the script that corresponds to destination private key, this is what is receiving the money
|
||||||
|
val destinationSPK =
|
||||||
|
P2PKHScriptPubKey(pubKey = destinationPrivKey.publicKey)
|
||||||
|
// destinationSPK: P2PKHScriptPubKey = pkh(18bb8fe332dbabfad38ead5e200802da2470eb73)
|
||||||
|
|
||||||
|
// this is where we are sending money too
|
||||||
|
// we could add more destinations here if we
|
||||||
|
// wanted to batch transactions
|
||||||
|
val destinations = {
|
||||||
|
val destination0 = TransactionOutput(value = destinationAmount,
|
||||||
|
scriptPubKey = destinationSPK)
|
||||||
|
|
||||||
|
Vector(destination0)
|
||||||
|
}
|
||||||
|
// destinations: Vector[TransactionOutput] = Vector(TransactionOutput(5000 sats,pkh(18bb8fe332dbabfad38ead5e200802da2470eb73)))
|
||||||
|
|
||||||
|
// Add the destinations to the tx builder
|
||||||
|
builder ++= destinations
|
||||||
|
// res0: RawTxBuilder = RawTxBuilder()
|
||||||
|
|
||||||
|
// we have to fabricate a transaction that contains the
|
||||||
|
// UTXO we are trying to spend. If this were a real blockchain
|
||||||
|
// we would need to reference the UTXO set
|
||||||
|
val creditingTx = BaseTransaction(version = Int32.one,
|
||||||
|
inputs = Vector.empty,
|
||||||
|
outputs = Vector(utxo),
|
||||||
|
lockTime = UInt32.zero)
|
||||||
|
// creditingTx: BaseTransaction = BaseTransaction(Int32Impl(1),Vector(),Vector(TransactionOutput(10000 sats,pkh(0ba1ff18b17397b9487188bf22c6b9f877d7831f))),UInt32Impl(0))
|
||||||
|
|
||||||
|
// this is the information we need from the crediting TX
|
||||||
|
// to properly "link" it in the transaction we are creating
|
||||||
|
val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero)
|
||||||
|
// outPoint: TransactionOutPoint = TransactionOutPoint(c644c58525144e921e4f78e59363f19f3f5a11a376ec00cd5d5dac14dbc88908:0)
|
||||||
|
val input = TransactionInput(
|
||||||
|
outPoint,
|
||||||
|
EmptyScriptSignature,
|
||||||
|
sequenceNumber = UInt32.zero)
|
||||||
|
// input: TransactionInput = TransactionInputImpl(TransactionOutPoint(c644c58525144e921e4f78e59363f19f3f5a11a376ec00cd5d5dac14dbc88908:0),EmptyScriptSignature,UInt32Impl(0))
|
||||||
|
|
||||||
|
// Add a new input to our builder
|
||||||
|
builder += input
|
||||||
|
// res1: RawTxBuilder = RawTxBuilder()
|
||||||
|
|
||||||
|
// We can now generate a RawTxBuilderResult ready to be finalized
|
||||||
|
val builderResult = builder.result()
|
||||||
|
// builderResult: RawTxBuilderResult = RawTxBuilderResult(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(c644c58525144e921e4f78e59363f19f3f5a11a376ec00cd5d5dac14dbc88908:0),EmptyScriptSignature,UInt32Impl(0))),Vector(TransactionOutput(5000 sats,pkh(18bb8fe332dbabfad38ead5e200802da2470eb73))),UInt32Impl(0))
|
||||||
|
|
||||||
|
// this contains the information needed to analyze our input during finalization
|
||||||
|
val inputInfo = P2PKHInputInfo(outPoint, amount, privKey.publicKey)
|
||||||
|
// inputInfo: P2PKHInputInfo = P2PKHInputInfo(TransactionOutPoint(c644c58525144e921e4f78e59363f19f3f5a11a376ec00cd5d5dac14dbc88908:0),10000 sats,ECPublicKey(038839cc58d1e077d426f550d13c0dc5bff744f749e4ea17f9c186ceb4e11ad130))
|
||||||
|
|
||||||
|
// this is how much we are going to pay as a fee to the network
|
||||||
|
// for this example, we are going to pay 1 satoshi per byte
|
||||||
|
val feeRate = SatoshisPerByte(1.satoshi)
|
||||||
|
// feeRate: SatoshisPerByte = 1 sats/byte
|
||||||
|
|
||||||
|
val changePrivKey = ECPrivateKey.freshPrivateKey
|
||||||
|
// changePrivKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||||
|
val changeSPK = P2PKHScriptPubKey(pubKey = changePrivKey.publicKey)
|
||||||
|
// changeSPK: P2PKHScriptPubKey = pkh(43d5d39a854760e7e5382b326ca80d0bae46a7c5)
|
||||||
|
|
||||||
|
// We chose a finalizer that adds a change output to our tx based on a fee rate
|
||||||
|
val finalizer = StandardNonInteractiveFinalizer(
|
||||||
|
Vector(inputInfo),
|
||||||
|
feeRate,
|
||||||
|
changeSPK)
|
||||||
|
// finalizer: StandardNonInteractiveFinalizer = StandardNonInteractiveFinalizer(Vector(P2PKHInputInfo(TransactionOutPoint(c644c58525144e921e4f78e59363f19f3f5a11a376ec00cd5d5dac14dbc88908:0),10000 sats,ECPublicKey(038839cc58d1e077d426f550d13c0dc5bff744f749e4ea17f9c186ceb4e11ad130))),1 sats/byte,pkh(43d5d39a854760e7e5382b326ca80d0bae46a7c5))
|
||||||
|
|
||||||
|
// We can now finalize the tx builder result from earlier with this finalizer
|
||||||
|
val unsignedTx: Transaction = finalizer.buildTx(builderResult)
|
||||||
|
// unsignedTx: Transaction = BaseTransaction(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(c644c58525144e921e4f78e59363f19f3f5a11a376ec00cd5d5dac14dbc88908:0),EmptyScriptSignature,UInt32Impl(0))),Vector(TransactionOutput(5000 sats,pkh(18bb8fe332dbabfad38ead5e200802da2470eb73)), TransactionOutput(4775 sats,pkh(43d5d39a854760e7e5382b326ca80d0bae46a7c5))),UInt32Impl(0))
|
||||||
|
|
||||||
|
// We now turn to signing the unsigned transaction
|
||||||
|
// this contains all the information we need to
|
||||||
|
// validly sign the UTXO above
|
||||||
|
val utxoInfo = ScriptSignatureParams(inputInfo = inputInfo,
|
||||||
|
prevTransaction = creditingTx,
|
||||||
|
signers = Vector(privKey),
|
||||||
|
hashType =
|
||||||
|
HashType.sigHashAll)
|
||||||
|
// utxoInfo: ScriptSignatureParams[P2PKHInputInfo] = ScriptSignatureParams(P2PKHInputInfo(TransactionOutPoint(c644c58525144e921e4f78e59363f19f3f5a11a376ec00cd5d5dac14dbc88908:0),10000 sats,ECPublicKey(038839cc58d1e077d426f550d13c0dc5bff744f749e4ea17f9c186ceb4e11ad130)),BaseTransaction(Int32Impl(1),Vector(),Vector(TransactionOutput(10000 sats,pkh(0ba1ff18b17397b9487188bf22c6b9f877d7831f))),UInt32Impl(0)),Vector(Masked(ECPrivateKey)),SIGHASH_ALL(1))
|
||||||
|
|
||||||
|
// all of the UTXO spending information, since we only have
|
||||||
|
// one input, this is just one element
|
||||||
|
val utxoInfos: Vector[ScriptSignatureParams[InputInfo]] = Vector(utxoInfo)
|
||||||
|
// utxoInfos: Vector[ScriptSignatureParams[InputInfo]] = Vector(ScriptSignatureParams(P2PKHInputInfo(TransactionOutPoint(c644c58525144e921e4f78e59363f19f3f5a11a376ec00cd5d5dac14dbc88908:0),10000 sats,ECPublicKey(038839cc58d1e077d426f550d13c0dc5bff744f749e4ea17f9c186ceb4e11ad130)),BaseTransaction(Int32Impl(1),Vector(),Vector(TransactionOutput(10000 sats,pkh(0ba1ff18b17397b9487188bf22c6b9f877d7831f))),UInt32Impl(0)),Vector(Masked(ECPrivateKey)),SIGHASH_ALL(1)))
|
||||||
|
|
||||||
|
// Yay! Now we use the RawTxSigner object to sign the tx.
|
||||||
|
// The 'sign' method is going produce a validly signed transaction
|
||||||
|
// This is going to iterate through each of the UTXOs and use
|
||||||
|
// the corresponding ScriptSignatureParams to produce a validly
|
||||||
|
// signed input. This UTXO has:
|
||||||
|
// 1: one input
|
||||||
|
// 2: outputs (destination and change outputs)
|
||||||
|
// 3: a fee rate of 1 satoshi/byte
|
||||||
|
val signedTx: Transaction =
|
||||||
|
RawTxSigner.sign(
|
||||||
|
utx = unsignedTx,
|
||||||
|
utxoInfos = utxoInfos,
|
||||||
|
expectedFeeRate = feeRate
|
||||||
|
)
|
||||||
|
// signedTx: Transaction = BaseTransaction(Int32Impl(2),Vector(TransactionInputImpl(TransactionOutPoint(c644c58525144e921e4f78e59363f19f3f5a11a376ec00cd5d5dac14dbc88908:0),P2PKHScriptSignature(ECPublicKeyBytes(ByteVector(33 bytes, 0x038839cc58d1e077d426f550d13c0dc5bff744f749e4ea17f9c186ceb4e11ad130)), ECDigitalSignature(3044022040d3d0be3e208b68ab7ff12f151bb2eb4b6baf277afd7be69bb3d0b6e72e6e4d02203eb558668039a92cb8d5001cff6ec2fca0a8d7f67811311b230afa5d80351d2801)),UInt32Impl(0))),Vector(TransactionOutput(5000 sats,pkh(18bb8fe332dbabfad38ead5e200802da2470eb73)), TransactionOutput(4775 sats,pkh(43d5d39a854760e7e5382b326ca80d0bae46a7c5))),UInt32Impl(0))
|
||||||
|
```
|
||||||
|
|
||||||
|
```scala
|
||||||
|
signedTx.inputs.length
|
||||||
|
// res2: Int = 1
|
||||||
|
|
||||||
|
signedTx.outputs.length
|
||||||
|
// res3: Int = 2
|
||||||
|
|
||||||
|
//remember, you can call .hex on any bitcoin-s data structure to get the hex representation!
|
||||||
|
signedTx.hex
|
||||||
|
// res4: String = 02000000010889c8db14ac5d5dcd00ec76a3115a3f9ff16393e5784f1e924e142585c544c6000000006a473044022040d3d0be3e208b68ab7ff12f151bb2eb4b6baf277afd7be69bb3d0b6e72e6e4d02203eb558668039a92cb8d5001cff6ec2fca0a8d7f67811311b230afa5d80351d280121038839cc58d1e077d426f550d13c0dc5bff744f749e4ea17f9c186ceb4e11ad130000000000288130000000000001976a91418bb8fe332dbabfad38ead5e200802da2470eb7388aca7120000000000001976a91443d5d39a854760e7e5382b326ca80d0bae46a7c588ac00000000
|
||||||
|
```
|
65
website/versioned_docs/version-1.9.4/crypto/sign.md
Normal file
65
website/versioned_docs/version-1.9.4/crypto/sign.md
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
---
|
||||||
|
id: version-1.9.4-sign
|
||||||
|
title: Sign API
|
||||||
|
original_id: sign
|
||||||
|
---
|
||||||
|
|
||||||
|
### The [`Sign` API](/api/org/bitcoins/crypto/Sign)
|
||||||
|
|
||||||
|
This is the API we define to sign things with. It takes in an arbitrary byte vector and returns a `Future[ECDigitalSignature]`. The reason we incorporate `Future`s here is for extensibility of this API. We would like to provide implementations of this API for hardware devices, which need to be asynchrnous since they may require user input.
|
||||||
|
|
||||||
|
From [Sign.scala](/api/org/bitcoins/crypto/Sign):
|
||||||
|
|
||||||
|
```scala
|
||||||
|
import scodec.bits._
|
||||||
|
import org.bitcoins.crypto._
|
||||||
|
import scala.concurrent._
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
trait Sign {
|
||||||
|
def signFunction: ByteVector => Future[ECDigitalSignature]
|
||||||
|
|
||||||
|
def signFuture(bytes: ByteVector): Future[ECDigitalSignature] =
|
||||||
|
signFunction(bytes)
|
||||||
|
|
||||||
|
def sign(bytes: ByteVector): ECDigitalSignature = {
|
||||||
|
Await.result(signFuture(bytes), 30.seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
def publicKey: ECPublicKey
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ByteVector` that is input to the `signFunction` should be the hash that is output from [`TransactionSignatureSerializer`](/api/org/bitcoins/core/crypto/TransactionSignatureSerializer)'s `hashForSignature` method. Our in-memory [`BaseECKey`](/api/org/bitcoins/crypto/BaseECKey) types implement the `Sign` API.
|
||||||
|
|
||||||
|
If you wanted to implement a new `Sign` api for a hardware wallet, you can easily pass it into the `TxBuilder`/`Signer` classes to allow for you to use those devices to sign with Bitcoin-S.
|
||||||
|
|
||||||
|
This API is currently used to sign ordinary transactions with our [`Signer`](/api/org/bitcoins/core/wallet/signer/Signer)s. The `Signer` subtypes (i.e. `P2PKHSigner`) implement the specific functionality needed to produce a valid digital signature for their corresponding script type.
|
||||||
|
|
||||||
|
|
||||||
|
### The [`ExtSign`](/api/org/bitcoins/crypto/Sign) API.
|
||||||
|
|
||||||
|
An [ExtKey](/api/org/bitcoins/core/crypto/ExtKey) is a data structure that can be used to generate more keys from a parent key. For more information look at [hd-keys.md](../core/hd-keys.md)
|
||||||
|
|
||||||
|
You can sign with `ExtPrivateKey` the same way you could with a normal `ECPrivateKey`.
|
||||||
|
|
||||||
|
```scala
|
||||||
|
import org.bitcoins.core.hd._
|
||||||
|
import org.bitcoins.core.crypto._
|
||||||
|
|
||||||
|
val extPrivKey = ExtPrivateKey(ExtKeyVersion.SegWitMainNetPriv)
|
||||||
|
// extPrivKey: ExtPrivateKey = Masked(ExtPrivateKeyImpl)
|
||||||
|
|
||||||
|
extPrivKey.sign(DoubleSha256Digest.empty.bytes)
|
||||||
|
// res0: ECDigitalSignature = ECDigitalSignature(3045022100dac821a2bbb1f964ebab10cc19bae172b8a207e8d20c3b0da7c1669dd329343602207eeadeb11dd783e724203ab84b08db9bda441138aec680cbde06c713c7e0d49e)
|
||||||
|
|
||||||
|
val path = BIP32Path(Vector(BIP32Node(0,false)))
|
||||||
|
// path: BIP32Path = m/0
|
||||||
|
|
||||||
|
extPrivKey.sign(DoubleSha256Digest.empty.bytes,path)
|
||||||
|
// res1: ECDigitalSignature = ECDigitalSignature(30440220339e864f5381dc9f643592ca7cba820efe8549184d5ac35ca3d78c87d734d356022078c3778e3e9b672ddcf90ba181d68536b9448f1924bffdd5d3ad01d93c841e9c)
|
||||||
|
```
|
||||||
|
|
||||||
|
With `ExtSign`, you can use `ExtPrivateKey` to sign transactions inside of `TxBuilder` since `UTXOSpendingInfo` takes in `Sign` as a parameter.
|
||||||
|
|
||||||
|
You can also provide a `path` to use to derive a child `ExtPrivateKey`, and then sign with that child private key
|
127
website/versioned_docs/version-1.9.4/getting-started.md
Normal file
127
website/versioned_docs/version-1.9.4/getting-started.md
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
---
|
||||||
|
id: version-1.9.4-getting-started
|
||||||
|
title: Intro and Getting Started
|
||||||
|
original_id: getting-started
|
||||||
|
---
|
||||||
|
|
||||||
|
## Philosophy
|
||||||
|
|
||||||
|
Bitcoin-S is a loosely coupled set of cryptocurrency libraries for the JVM. They work well together, but also can be used
|
||||||
|
independently. This project's goal is NOT to be a full node implementation, rather a set of scalable cryptocurrency libraries
|
||||||
|
that use industry standard tools (rather than esoteric tech often found in cryptocurrency) where possible to make the lives of professional
|
||||||
|
software engineers, security engineers, devops engineers and accountants easier.
|
||||||
|
We are rapidly iterating on development with the goal of getting to a set of stable APIs that only change when the underlying bitcoin protocol changes.
|
||||||
|
|
||||||
|
If you are a professional working a cryptocurrency business and
|
||||||
|
have feedback on how to make your lives easier, please reach out on [slack](https://join.slack.com/t/suredbits/shared_invite/zt-eavycu0x-WQL7XOakzQo8tAy7jHHZUw),
|
||||||
|
[gitter](https://gitter.im/bitcoin-s-core/) or [twitter](https://twitter.com/Chris_Stewart_5/)!
|
||||||
|
|
||||||
|
## Getting prebuilt artifacts
|
||||||
|
|
||||||
|
### Java binaries
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
#### Latest release
|
||||||
|
|
||||||
|
Please see the release page on github, you can find it [here](https://github.com/bitcoin-s/bitcoin-s/releases)
|
||||||
|
|
||||||
|
#### Master builds
|
||||||
|
|
||||||
|
We build installers for mac, linux and windows everytime a PR is merged to master.
|
||||||
|
|
||||||
|
You can find the latest builds at this link:
|
||||||
|
|
||||||
|
https://github.com/bitcoin-s/bitcoin-s/actions/workflows/release.yml
|
||||||
|
|
||||||
|
Here is what the installers look like
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
<details>
|
||||||
|
We publish docker images to docker hub on every PR merge and tag on github.
|
||||||
|
You can obtain the images for both the app server and oracle server on these
|
||||||
|
docker hub repos
|
||||||
|
|
||||||
|
[bitcoin-s-server docker hub repo](https://hub.docker.com/r/bitcoinscala/bitcoin-s-server/tags?page=1&ordering=last_updated)
|
||||||
|
|
||||||
|
[bitcoin-s-oracle-server docker hub repo](https://hub.docker.com/r/bitcoinscala/bitcoin-s-oracle-server/tags?page=1&ordering=last_updated)
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Library jars
|
||||||
|
|
||||||
|
<details>
|
||||||
|
Add this to your `build.sbt`:
|
||||||
|
|
||||||
|
```scala
|
||||||
|
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-bitcoind-rpc" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-core" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-chain" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-dlc-oracle" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-eclair-rpc" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-fee-provider" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-key-manager" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-lnd-rpc" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-node" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-oracle-explorer-client" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" % "bitcoin-s-secp256k1jni" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit-core" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-testkit" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-wallet" % "1.9.2"
|
||||||
|
|
||||||
|
libraryDependencies += "org.bitcoin-s" %% "bitcoin-s-zmq" % "1.9.2"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Nightly builds
|
||||||
|
|
||||||
|
You can also run on the bleeding edge of Bitcoin-S, by
|
||||||
|
adding a snapshot build to your `build.sbt`. The most
|
||||||
|
recent snapshot published is `1.9.2-102-2a791b3f-20220728-1318-SNAPSHOT`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
To fetch snapshots, you will need to add the correct
|
||||||
|
resolver in your `build.sbt`:
|
||||||
|
|
||||||
|
```sbt
|
||||||
|
resolvers += Resolver.sonatypeRepo("snapshots")
|
||||||
|
```
|
||||||
|
|
||||||
|
The official maven repo for releases is
|
||||||
|
|
||||||
|
https://repo1.maven.org/maven2/org/bitcoin-s/
|
||||||
|
|
||||||
|
The repo for snapshots, which are published after everytime something is merged to master:
|
||||||
|
|
||||||
|
https://oss.sonatype.org/content/repositories/snapshots/org/bitcoin-s/
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Building JARs yourself
|
||||||
|
|
||||||
|
Please see [our setup docs](getting-setup.md)
|
||||||
|
|
||||||
|
## If you want to setup Bitcoin-S locally for development
|
||||||
|
|
||||||
|
Please see [our setup docs](getting-setup.md)
|
124
website/versioned_docs/version-1.9.4/key-manager/key-manager.md
Normal file
124
website/versioned_docs/version-1.9.4/key-manager/key-manager.md
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
---
|
||||||
|
id: version-1.9.4-key-manager
|
||||||
|
title: Key Manager
|
||||||
|
original_id: key-manager
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
### Key Manager
|
||||||
|
|
||||||
|
The key manager module's goal is to encapsulate all private key interactions with the [wallet](../wallet/wallet.md) project.
|
||||||
|
|
||||||
|
As of this writing, there is only one type of `KeyManager` - [`BIP39KeyManager`](/api/org/bitcoins/keymanager/bip39/BIP39KeyManager).
|
||||||
|
|
||||||
|
The [`BIP39KeyManager`](/api/org/bitcoins/keymanager/bip39/BIP39KeyManager) stores a [`MnemonicCode`](/api/org/bitcoins/core/crypto/MnemonicCode) on disk which can be decrypted and used as a hot wallet.
|
||||||
|
|
||||||
|
Over the long run, we want to make it so that the wallet project needs to communicate with the key-manager to access private keys.
|
||||||
|
|
||||||
|
This means that ALL SIGNING should be done inside of the key-manager, and private keys should not leave the key manager.
|
||||||
|
|
||||||
|
This makes it easier to reason about the security characteristics of our private keys, and a way to provide a uniform interface for alternative key storage systems (hsm, cloud based key storage, etc) to be plugged into the bitcoin-s library.
|
||||||
|
|
||||||
|
#### Creating a key manager
|
||||||
|
|
||||||
|
The first thing you need create a key manager is some entropy.
|
||||||
|
|
||||||
|
A popular way for bitcoin wallet's to represent entropy is [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) which you [can use in bitcoin-s](/api/org/bitcoins/core/crypto/BIP39Seed)
|
||||||
|
|
||||||
|
You can generate a `MnemonicCode` in bitcoin-s with the following code
|
||||||
|
|
||||||
|
```scala
|
||||||
|
import org.bitcoins.core.crypto._
|
||||||
|
|
||||||
|
//get 256 bits of random entropy
|
||||||
|
val entropy = MnemonicCode.getEntropy256Bits
|
||||||
|
// entropy: scodec.bits.BitVector = BitVector(256 bits, 0x3ac53842f5136fbd1dd63fe6bfef38fb9cb7ed6fc099bac7b58cd93192d3ba04)
|
||||||
|
|
||||||
|
val mnemonic = MnemonicCode.fromEntropy(entropy)
|
||||||
|
// mnemonic: MnemonicCode = Masked(MnemonicCodeImpl)
|
||||||
|
|
||||||
|
//you can print that mnemonic seed with this
|
||||||
|
println(mnemonic.words)
|
||||||
|
// Vector(depart, clap, awful, tuition, dad, teach, jar, side, trade, youth, soda, warm, slice, wall, sample, basket, river, diet, glimpse, raven, bomb, hawk, trend, normal)
|
||||||
|
```
|
||||||
|
|
||||||
|
Now that we have a `MnemonicCode` that was securely generated, we need to now create `KeyManagerParams` which tells us how to generate
|
||||||
|
generate specific kinds of addresses for wallets.
|
||||||
|
|
||||||
|
`KeyManagerParams` takes 3 parameters:
|
||||||
|
|
||||||
|
1. `seedPath` there is where we store the `MnemonicCode` on your file system
|
||||||
|
2. [`purpose`](/api/org/bitcoins/core/hd/HDPurpose) which represents what type of utxo this `KeyManager` is associated with. The specification for this is in [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki)
|
||||||
|
3. [`network`](/api/org/bitcoins/core/config/NetworkParameters) what cryptocurrency network this key manager is associated with
|
||||||
|
|
||||||
|
|
||||||
|
This controls how the root key is defined. The combination of `purpose` and `network` determine how the root `ExtKey` is serialized. For more information on how this works please see [hd-keys](../core/hd-keys.md)
|
||||||
|
|
||||||
|
Now we can construct a native segwit key manager for the regtest network!
|
||||||
|
|
||||||
|
```scala
|
||||||
|
//this will create a temp directory with the prefix 'key-manager-example` that will
|
||||||
|
//have a file in it called "encrypted-bitcoin-s-seed.json"
|
||||||
|
val seedPath = Files.createTempDirectory("key-manager-example").resolve(WalletStorage.ENCRYPTED_SEED_FILE_NAME)
|
||||||
|
// seedPath: Path = /tmp/key-manager-example4979278246283051324/encrypted-bitcoin-s-seed.json
|
||||||
|
|
||||||
|
//let's create a native segwit key manager
|
||||||
|
val purpose = HDPurposes.SegWit
|
||||||
|
// purpose: HDPurpose = m/84'
|
||||||
|
|
||||||
|
//let's choose regtest as our network
|
||||||
|
val network = RegTest
|
||||||
|
// network: RegTest.type = RegTest
|
||||||
|
|
||||||
|
val kmParams = KeyManagerParams(seedPath, purpose, network)
|
||||||
|
// kmParams: KeyManagerParams = KeyManagerParams(/tmp/key-manager-example4979278246283051324/encrypted-bitcoin-s-seed.json,m/84',RegTest)
|
||||||
|
|
||||||
|
val aesPasswordOpt = Some(AesPassword.fromString("password"))
|
||||||
|
// aesPasswordOpt: Some[AesPassword] = Some(Masked(AesPassword))
|
||||||
|
|
||||||
|
val km = BIP39KeyManager.initializeWithMnemonic(aesPasswordOpt, mnemonic, None, kmParams)
|
||||||
|
// km: Either[KeyManagerInitializeError, BIP39KeyManager] = Right(org.bitcoins.keymanager.bip39.BIP39KeyManager@fc07502)
|
||||||
|
|
||||||
|
val rootXPub = km.right.get.getRootXPub
|
||||||
|
// rootXPub: ExtPublicKey = vpub5SLqN2bLY4WeZCQKz3e9Zv1YfBdjhv25U5TqsXSwNSkMDyhZDScDzJsb8biHA6cM9nEfMf2kzqjdhLoBGW6zjqo3PwWJuAD6VPRvbiQ7r8M
|
||||||
|
|
||||||
|
println(rootXPub)
|
||||||
|
// vpub5SLqN2bLY4WeZCQKz3e9Zv1YfBdjhv25U5TqsXSwNSkMDyhZDScDzJsb8biHA6cM9nEfMf2kzqjdhLoBGW6zjqo3PwWJuAD6VPRvbiQ7r8M
|
||||||
|
```
|
||||||
|
|
||||||
|
Which should print something that looks like this
|
||||||
|
|
||||||
|
`vpub5SLqN2bLY4WeXxMqwJHJFBEwxSscGB2uDUnsTS3edVjZEwTrQDFDNqoR2xLqARQPabGaXsHSTenTRcqm2EnB9MpuC4vSk3LqSgNmGGZtuq7`
|
||||||
|
|
||||||
|
which is a native segwit `ExtPubKey` for the regtest network!
|
||||||
|
|
||||||
|
You can always change the `network` or `purpose` to support different things. You do _not_ need to initialize the key manager
|
||||||
|
again after initializing it once. You can use the same `mnemonic` for different networks, which you control `KeyManagerParams`.
|
||||||
|
|
||||||
|
```scala
|
||||||
|
//let's create a nested segwit key manager for mainnet
|
||||||
|
val mainnetKmParams = KeyManagerParams(seedPath, HDPurposes.SegWit, MainNet)
|
||||||
|
// mainnetKmParams: KeyManagerParams = KeyManagerParams(/tmp/key-manager-example4979278246283051324/encrypted-bitcoin-s-seed.json,m/84',MainNet)
|
||||||
|
|
||||||
|
//we do not need to all `initializeWithMnemonic()` again as we have saved the seed to dis
|
||||||
|
val mainnetKeyManager = BIP39KeyManager.fromMnemonic(mnemonic, mainnetKmParams, None, Instant.now, false)
|
||||||
|
// mainnetKeyManager: BIP39KeyManager = org.bitcoins.keymanager.bip39.BIP39KeyManager@a35587b
|
||||||
|
|
||||||
|
val mainnetXpub = mainnetKeyManager.getRootXPub
|
||||||
|
// mainnetXpub: ExtPublicKey = zpub6jftahH18ngZxPAoKUneQGPZM4DXUPz58XYj172UtUFsSNxUE5GUUZW9DRYd9jE2nLhtMZQzqV9qEVFS9Hm3vnXSsJJ1EoV3aHgWA6YLika
|
||||||
|
|
||||||
|
println(mainnetXpub)
|
||||||
|
// zpub6jftahH18ngZxPAoKUneQGPZM4DXUPz58XYj172UtUFsSNxUE5GUUZW9DRYd9jE2nLhtMZQzqV9qEVFS9Hm3vnXSsJJ1EoV3aHgWA6YLika
|
||||||
|
```
|
||||||
|
|
||||||
|
Which gives us something that looks like this
|
||||||
|
|
||||||
|
`zpub6jftahH18ngZw98KGjRo5XcxeKTQ2eztsvskb1dC9XF5TLimQquTs6Ry7nBBA425D9joXmfgJJCexmJ1u2SELJZJfRi95gcnXadLpZzYb5c`
|
||||||
|
|
||||||
|
which is a p2sh wrapped segwit `ExtPubKey` for the bitcoin main network!
|
||||||
|
|
||||||
|
#### Creating a key manager from existing mnemonic
|
||||||
|
|
||||||
|
To create a `KeyManager` from existing mnemonic you need to specify the `seedPath` and then construct the `KeyManagerParams` that you would like.
|
||||||
|
|
||||||
|
Finally you call `KeyManager.fromParams()` that reads the mnemonic from disk and create's the key manager
|
92
website/versioned_docs/version-1.9.4/secp256k1/secp256k1.md
Normal file
92
website/versioned_docs/version-1.9.4/secp256k1/secp256k1.md
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
---
|
||||||
|
id: version-1.9.4-secp256k1
|
||||||
|
title: Secp256k1
|
||||||
|
original_id: secp256k1
|
||||||
|
---
|
||||||
|
|
||||||
|
[Libsecp256k1](https://github.com/bitcoin-core/secp256k1) is used to preform cryptographic operations on the secp256k1 curve.
|
||||||
|
This is the curve that bitcoin uses. There is a _signficant_ speedup when using this library compared to java crypto libraries
|
||||||
|
like bouncy castle.
|
||||||
|
|
||||||
|
In bitcoin-s, we support native binaries for libsecp256k1
|
||||||
|
|
||||||
|
1. [linux 32 bit](../../secp256k1jni/natives/linux_32)
|
||||||
|
2. [linux 64 bit](../../secp256k1jni/natives/linux_64)
|
||||||
|
3. [mac osx 64 bit](../../secp256k1jni/natives/osx_64)
|
||||||
|
4. [windows 64 bit](../../secp256k1jni/natives/windows_64)
|
||||||
|
|
||||||
|
Bitcoin-s uses a zero dependency library called [`native-lib-loader`](https://github.com/scijava/native-lib-loader).
|
||||||
|
That does the appropriate loading of the library onto your classpath to be accessed.
|
||||||
|
|
||||||
|
### Using libsecp256k1
|
||||||
|
|
||||||
|
To tell if you have access to libsecp256k1 you can do the following
|
||||||
|
|
||||||
|
|
||||||
|
```scala
|
||||||
|
val isEnabled = org.bitcoin.Secp256k1Context.isEnabled()
|
||||||
|
|
||||||
|
println(s"Secp256k1Context.isEnabled=${isEnabled}")
|
||||||
|
```
|
||||||
|
|
||||||
|
If libsecp256k1 is enabled, you can use [NativeSecp256k1](/api/org/bitcoin/NativeSecp256k1)
|
||||||
|
with static method defined in the class.
|
||||||
|
|
||||||
|
|
||||||
|
```scala
|
||||||
|
val privKey = ECPrivateKey.freshPrivateKey
|
||||||
|
val pubKey = privKey.publicKey
|
||||||
|
val dataToSign = DoubleSha256Digest.empty
|
||||||
|
|
||||||
|
val signature = NativeSecp256k1.sign(dataToSign.bytes.toArray, privKey.bytes.toArray)
|
||||||
|
|
||||||
|
val verify = NativeSecp256k1.verify(dataToSign.bytes.toArray, signature, pubKey.bytes.toArray)
|
||||||
|
|
||||||
|
println(s"Verified with NativeSecp256k1 signature=${verify}")
|
||||||
|
|
||||||
|
//you can also just directly sign with the ECKey interface:
|
||||||
|
val signature2 = privKey.sign(dataToSign)
|
||||||
|
|
||||||
|
val verified2 = pubKey.verify(dataToSign, signature2)
|
||||||
|
|
||||||
|
println(s"Verified with NativeSecp256k1 again=${verified2}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### When libsecp256k1 isn't available, or you want to turn it off
|
||||||
|
|
||||||
|
There are two reasons you wouldn't want to use libsecp256k1
|
||||||
|
|
||||||
|
1. You don't trust the pre-compiled binaries we are using
|
||||||
|
2. Your OS/arch is not supported
|
||||||
|
|
||||||
|
There are two ways you can circumvent libsecp256k1
|
||||||
|
|
||||||
|
1. Set `DISABLE_SECP256K1=true` in your environment variables. This will force `CryptoContext.default` to return false which will make Bitcoin-S act like `Secp256k1Context.isEnabled()` has returned false.
|
||||||
|
2. Call Bouncy castle methods in `ECKey`.
|
||||||
|
|
||||||
|
Here is an example of calling bouncy castle methods in `ECKey`
|
||||||
|
|
||||||
|
```scala
|
||||||
|
val privKey = ECPrivateKey.freshPrivateKey
|
||||||
|
// privKey: ECPrivateKey = Masked(ECPrivateKey)
|
||||||
|
// calls bouncy castle indirectly via CryptoContext
|
||||||
|
val publicKey = privKey.publicKey
|
||||||
|
// publicKey: ECPublicKey = ECPublicKey(02fa4039b52b752dcaf6606e16889fc162543f717b910a8bd838d89c89f954bd07)
|
||||||
|
val dataToSign = DoubleSha256Digest.empty
|
||||||
|
// dataToSign: DoubleSha256Digest = DoubleSha256Digest(0000000000000000000000000000000000000000000000000000000000000000)
|
||||||
|
|
||||||
|
// calls bouncy castle indirectly via CryptoContext
|
||||||
|
val signature = privKey.sign(dataToSign.bytes)
|
||||||
|
// signature: ECDigitalSignature = ECDigitalSignature(3045022100dcc054efc50702aa10442f974b0bc4a55fcdf10f712e32c10a935272aaeff5610220139fab013ceb9184e9f363ea1d5066c93513f9e89cfac7abd0a449f2821be6a2)
|
||||||
|
|
||||||
|
// calls bouncy castle indirectly via CryptoContext
|
||||||
|
val verified = publicKey.verify(dataToSign.bytes, signature)
|
||||||
|
// verified: Boolean = true
|
||||||
|
|
||||||
|
println(s"Verified with bouncy castle=${verified}")
|
||||||
|
// Verified with bouncy castle=true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building libsecp256k1
|
||||||
|
|
||||||
|
[See instructions here](add-to-jni.md#adding-to-bitcoin-s)
|
103
website/versioned_docs/version-1.9.4/wallet/wallet-sync.md
Normal file
103
website/versioned_docs/version-1.9.4/wallet/wallet-sync.md
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
---
|
||||||
|
title: Wallet Sync
|
||||||
|
id: version-1.9.4-wallet-sync
|
||||||
|
original_id: wallet-sync
|
||||||
|
---
|
||||||
|
|
||||||
|
## High level wallet state
|
||||||
|
|
||||||
|
Our wallet infrastructure has a specific table called `state_descriptors`.
|
||||||
|
This tracks chain state for our wallet.
|
||||||
|
Here is an example of the contents of this table
|
||||||
|
|
||||||
|
>sqlite> select * from state_descriptors;
|
||||||
|
SyncHeight|0000000000000000000134aa9e949ea1d053042b8dfa59bdc73b0322a88f009e 665741
|
||||||
|
|
||||||
|
If you look carefully in the second column, you will see a string encoding indicating
|
||||||
|
what the wallet state is. In this case, the last block hash seen by the wallet is
|
||||||
|
|
||||||
|
>0000000000000000000134aa9e949ea1d053042b8dfa59bdc73b0322a88f009e
|
||||||
|
|
||||||
|
and height
|
||||||
|
|
||||||
|
>665741
|
||||||
|
|
||||||
|
If you have access to a wallet, you can call
|
||||||
|
|
||||||
|
[`wallet.getSyncDescriptorOpt`](https://github.com/bitcoin-s/bitcoin-s/blob/36b5fc142715f8ab3ad053465d53dc29ab319790/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala#L160) to get access to this information
|
||||||
|
|
||||||
|
#### Wallet state from the cli
|
||||||
|
|
||||||
|
Alternatively, you can retrieve this information with `bitcoin-s-cli`
|
||||||
|
|
||||||
|
```
|
||||||
|
./bitcoin-s-cli walletinfo
|
||||||
|
{
|
||||||
|
"wallet": {
|
||||||
|
"keymanager": {
|
||||||
|
"rootXpub": "..."
|
||||||
|
},
|
||||||
|
"xpub": "...",
|
||||||
|
"hdPath": "...",
|
||||||
|
"height": 1906239,
|
||||||
|
"blockHash": "00000000dcf1066b8cd764a6104a9b5e95a55cd31adf9107974b2581ac90fdb9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Syncing a wallet
|
||||||
|
|
||||||
|
Bitcoin-s provides a utility object called [`WalletSync`](https://github.com/bitcoin-s/bitcoin-s/blob/f3e81d027dfdda79e26642d5c29d381874ee72da/wallet/src/main/scala/org/bitcoins/wallet/sync/WalletSync.scala#L10)
|
||||||
|
that provides useful utilities for syncing a bitcoin-s wallet.
|
||||||
|
|
||||||
|
### Syncing wallet for with access to full blocks
|
||||||
|
|
||||||
|
Inside of `WalletSync` we have a method called [`WalletSync.syncFullBlocks`](https://github.com/bitcoin-s/bitcoin-s/blob/f3e81d027dfdda79e26642d5c29d381874ee72da/wallet/src/main/scala/org/bitcoins/wallet/sync/WalletSync.scala#L18)
|
||||||
|
This method takes 4 parameters
|
||||||
|
|
||||||
|
- a [Wallet](https://github.com/bitcoin-s/bitcoin-s/blob/36b5fc142715f8ab3ad053465d53dc29ab319790/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala#L46) to sync
|
||||||
|
- `getBlockHeaderFunc` is a function to retrieve a block header based on a blockHash
|
||||||
|
- `getBestBlockHashFunc` is a function to retrieve the best block hash for our blockchain
|
||||||
|
- `getBlockFunc` is a function to retrieve a full [`Block`](https://github.com/bitcoin-s/bitcoin-s/blob/8a148357d560a40bf21e7c0e3f4074cd276534fe/core/src/main/scala/org/bitcoins/core/protocol/blockchain/Block.scala#L18) that corresponds to a block hash
|
||||||
|
|
||||||
|
Given these for things, we can use [`WalletSync.syncFullBlocks`](https://github.com/bitcoin-s/bitcoin-s/blob/f3e81d027dfdda79e26642d5c29d381874ee72da/wallet/src/main/scala/org/bitcoins/wallet/sync/WalletSync.scala#L18) to sync our entire wallet.
|
||||||
|
|
||||||
|
Here is a code example
|
||||||
|
|
||||||
|
|
||||||
|
```scala
|
||||||
|
implicit val system: ActorSystem = ActorSystem(s"wallet-sync-example")
|
||||||
|
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(binary=new File("/path/to/bitcoind"), datadir=new File("/path/to/bitcoind-datadir"))
|
||||||
|
|
||||||
|
//yay! Now we have a started bitcoind.
|
||||||
|
//We will use this as our datasource for syncing our wallet
|
||||||
|
val bitcoindRpcClientF: Future[BitcoindRpcClient] = client.start()
|
||||||
|
|
||||||
|
|
||||||
|
//wait for bitcoind to get started
|
||||||
|
val bitcoind = Await.result(bitcoindRpcClientF, 10.seconds)
|
||||||
|
|
||||||
|
val getBestBlockHashFunc = () => bitcoind.getBestBlockHash
|
||||||
|
|
||||||
|
val getBlockHeaderFunc = { hash: DoubleSha256DigestBE => bitcoind.getBlockHeaderRaw(hash) }
|
||||||
|
|
||||||
|
val getBlockFunc = {hash: DoubleSha256DigestBE => bitcoind.getBlockRaw(hash) }
|
||||||
|
|
||||||
|
//yay! We are now all setup. Using our 3 functions above and a wallet, we can now sync
|
||||||
|
//a fresh wallet
|
||||||
|
implicit val walletAppConfig = WalletAppConfig.fromDefaultDatadir()
|
||||||
|
|
||||||
|
val feeRateProvider: FeeRateApi = MempoolSpaceProvider.fromBlockTarget(6, proxyParams = None)
|
||||||
|
val wallet = Wallet(bitcoind, bitcoind, feeRateProvider)
|
||||||
|
|
||||||
|
//yay! we have a synced wallet
|
||||||
|
val syncedWalletF = WalletSync.syncFullBlocks(wallet,
|
||||||
|
getBlockHeaderFunc,
|
||||||
|
getBestBlockHashFunc,
|
||||||
|
getBlockFunc)
|
||||||
|
```
|
101
website/versioned_sidebars/version-1.9.2-sidebars.json
Normal file
101
website/versioned_sidebars/version-1.9.2-sidebars.json
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
{
|
||||||
|
"version-1.9.2-docs": {
|
||||||
|
"Getting Started": [
|
||||||
|
"version-1.9.2-getting-started",
|
||||||
|
"version-1.9.2-bips"
|
||||||
|
],
|
||||||
|
"Getting Setup": [
|
||||||
|
"version-1.9.2-getting-setup",
|
||||||
|
"version-1.9.2-ui-setup"
|
||||||
|
],
|
||||||
|
"Applications": [
|
||||||
|
"version-1.9.2-applications/cli",
|
||||||
|
"version-1.9.2-applications/server",
|
||||||
|
"version-1.9.2-applications/gui",
|
||||||
|
"version-1.9.2-applications/server-systemd"
|
||||||
|
],
|
||||||
|
"Chain": [
|
||||||
|
"version-1.9.2-chain/chain",
|
||||||
|
"version-1.9.2-chain/filter-sync",
|
||||||
|
"version-1.9.2-chain/chain-query-api"
|
||||||
|
],
|
||||||
|
"Configuration": [
|
||||||
|
"version-1.9.2-config/configuration"
|
||||||
|
],
|
||||||
|
"Core Module": [
|
||||||
|
"version-1.9.2-core/core-intro",
|
||||||
|
"version-1.9.2-core/addresses",
|
||||||
|
"version-1.9.2-core/hd-keys",
|
||||||
|
"version-1.9.2-core/adding-spks",
|
||||||
|
"version-1.9.2-core/spending-info",
|
||||||
|
"version-1.9.2-core/psbts",
|
||||||
|
"version-1.9.2-core/dlc",
|
||||||
|
"version-1.9.2-core/txbuilder",
|
||||||
|
"version-1.9.2-core/lightning-network"
|
||||||
|
],
|
||||||
|
"Crypto Module": [
|
||||||
|
"version-1.9.2-crypto/crypto-intro",
|
||||||
|
"version-1.9.2-crypto/sign",
|
||||||
|
"version-1.9.2-crypto/adaptor-signatures"
|
||||||
|
],
|
||||||
|
"Fee Provider": [
|
||||||
|
"version-1.9.2-fee-provider/fee-provider"
|
||||||
|
],
|
||||||
|
"Key Manager": [
|
||||||
|
"version-1.9.2-key-manager/server-key-manager",
|
||||||
|
"version-1.9.2-key-manager/key-manager"
|
||||||
|
],
|
||||||
|
"Node": [
|
||||||
|
"version-1.9.2-node/node",
|
||||||
|
"version-1.9.2-node/node-api"
|
||||||
|
],
|
||||||
|
"Wallet": [
|
||||||
|
"version-1.9.2-wallet/wallet",
|
||||||
|
"version-1.9.2-wallet/wallet-callbacks",
|
||||||
|
"version-1.9.2-wallet/wallet-get-address",
|
||||||
|
"version-1.9.2-wallet/address-tagging",
|
||||||
|
"version-1.9.2-wallet/dlc",
|
||||||
|
"version-1.9.2-wallet/wallet-rescan",
|
||||||
|
"version-1.9.2-wallet/wallet-sync",
|
||||||
|
"version-1.9.2-wallet/wallet-rpc",
|
||||||
|
"version-1.9.2-wallet/backups",
|
||||||
|
"version-1.9.2-wallet/wallet-election-example",
|
||||||
|
"version-1.9.2-wallet/wallet-price-example",
|
||||||
|
"version-1.9.2-wallet/wallet-sports-betting-example"
|
||||||
|
],
|
||||||
|
"Tor": [
|
||||||
|
"version-1.9.2-tor/tor"
|
||||||
|
],
|
||||||
|
"RPC Clients": [
|
||||||
|
"version-1.9.2-rpc/rpc-clients-intro",
|
||||||
|
"version-1.9.2-rpc/rpc-eclair",
|
||||||
|
"version-1.9.2-rpc/rpc-bitcoind",
|
||||||
|
"version-1.9.2-rpc/lnd-rpc"
|
||||||
|
],
|
||||||
|
"Secp256k1": [
|
||||||
|
"version-1.9.2-secp256k1/secp256k1",
|
||||||
|
"version-1.9.2-secp256k1/jni-modify"
|
||||||
|
],
|
||||||
|
"Testkit": [
|
||||||
|
"version-1.9.2-testkit/testkit",
|
||||||
|
"version-1.9.2-testkit/testkit-core"
|
||||||
|
],
|
||||||
|
"DLC Oracle": [
|
||||||
|
"version-1.9.2-oracle/build-oracle-server",
|
||||||
|
"version-1.9.2-oracle/oracle-server",
|
||||||
|
"version-1.9.2-oracle/oracle-election-example",
|
||||||
|
"version-1.9.2-oracle/oracle-price-example",
|
||||||
|
"version-1.9.2-oracle/oracle-sports-betting-example"
|
||||||
|
],
|
||||||
|
"Oracle Explorer Client": [
|
||||||
|
"version-1.9.2-oracle-explorer-client/oracle-explorer-client"
|
||||||
|
],
|
||||||
|
"Contributing": [
|
||||||
|
"version-1.9.2-contributing",
|
||||||
|
"version-1.9.2-contributing-website"
|
||||||
|
],
|
||||||
|
"Security": [
|
||||||
|
"version-1.9.2-security"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
102
website/versioned_sidebars/version-1.9.4-sidebars.json
Normal file
102
website/versioned_sidebars/version-1.9.4-sidebars.json
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
{
|
||||||
|
"version-1.9.4-docs": {
|
||||||
|
"Getting Started": [
|
||||||
|
"version-1.9.4-getting-started",
|
||||||
|
"version-1.9.4-bips"
|
||||||
|
],
|
||||||
|
"Getting Setup": [
|
||||||
|
"version-1.9.4-getting-setup",
|
||||||
|
"version-1.9.4-ui-setup"
|
||||||
|
],
|
||||||
|
"Applications": [
|
||||||
|
"version-1.9.4-applications/cli",
|
||||||
|
"version-1.9.4-applications/server",
|
||||||
|
"version-1.9.4-applications/gui",
|
||||||
|
"version-1.9.4-applications/server-systemd"
|
||||||
|
],
|
||||||
|
"Chain": [
|
||||||
|
"version-1.9.4-chain/chain",
|
||||||
|
"version-1.9.4-chain/filter-sync",
|
||||||
|
"version-1.9.4-chain/chain-query-api"
|
||||||
|
],
|
||||||
|
"Configuration": [
|
||||||
|
"version-1.9.4-config/configuration"
|
||||||
|
],
|
||||||
|
"Core Module": [
|
||||||
|
"version-1.9.4-core/core-intro",
|
||||||
|
"version-1.9.4-core/addresses",
|
||||||
|
"version-1.9.4-core/hd-keys",
|
||||||
|
"version-1.9.4-core/adding-spks",
|
||||||
|
"version-1.9.4-core/spending-info",
|
||||||
|
"version-1.9.4-core/psbts",
|
||||||
|
"version-1.9.4-core/dlc",
|
||||||
|
"version-1.9.4-core/txbuilder",
|
||||||
|
"version-1.9.4-core/lightning-network"
|
||||||
|
],
|
||||||
|
"Crypto Module": [
|
||||||
|
"version-1.9.4-crypto/crypto-intro",
|
||||||
|
"version-1.9.4-crypto/sign",
|
||||||
|
"version-1.9.4-crypto/adaptor-signatures",
|
||||||
|
"version-1.9.4-crypto/musig"
|
||||||
|
],
|
||||||
|
"Fee Provider": [
|
||||||
|
"version-1.9.4-fee-provider/fee-provider"
|
||||||
|
],
|
||||||
|
"Key Manager": [
|
||||||
|
"version-1.9.4-key-manager/server-key-manager",
|
||||||
|
"version-1.9.4-key-manager/key-manager"
|
||||||
|
],
|
||||||
|
"Node": [
|
||||||
|
"version-1.9.4-node/node",
|
||||||
|
"version-1.9.4-node/node-api"
|
||||||
|
],
|
||||||
|
"Wallet": [
|
||||||
|
"version-1.9.4-wallet/wallet",
|
||||||
|
"version-1.9.4-wallet/wallet-callbacks",
|
||||||
|
"version-1.9.4-wallet/wallet-get-address",
|
||||||
|
"version-1.9.4-wallet/address-tagging",
|
||||||
|
"version-1.9.4-wallet/dlc",
|
||||||
|
"version-1.9.4-wallet/wallet-rescan",
|
||||||
|
"version-1.9.4-wallet/wallet-sync",
|
||||||
|
"version-1.9.4-wallet/wallet-rpc",
|
||||||
|
"version-1.9.4-wallet/backups",
|
||||||
|
"version-1.9.4-wallet/wallet-election-example",
|
||||||
|
"version-1.9.4-wallet/wallet-price-example",
|
||||||
|
"version-1.9.4-wallet/wallet-sports-betting-example"
|
||||||
|
],
|
||||||
|
"Tor": [
|
||||||
|
"version-1.9.4-tor/tor"
|
||||||
|
],
|
||||||
|
"RPC Clients": [
|
||||||
|
"version-1.9.4-rpc/rpc-clients-intro",
|
||||||
|
"version-1.9.4-rpc/rpc-eclair",
|
||||||
|
"version-1.9.4-rpc/rpc-bitcoind",
|
||||||
|
"version-1.9.4-rpc/lnd-rpc"
|
||||||
|
],
|
||||||
|
"Secp256k1": [
|
||||||
|
"version-1.9.4-secp256k1/secp256k1",
|
||||||
|
"version-1.9.4-secp256k1/jni-modify"
|
||||||
|
],
|
||||||
|
"Testkit": [
|
||||||
|
"version-1.9.4-testkit/testkit",
|
||||||
|
"version-1.9.4-testkit/testkit-core"
|
||||||
|
],
|
||||||
|
"DLC Oracle": [
|
||||||
|
"version-1.9.4-oracle/build-oracle-server",
|
||||||
|
"version-1.9.4-oracle/oracle-server",
|
||||||
|
"version-1.9.4-oracle/oracle-election-example",
|
||||||
|
"version-1.9.4-oracle/oracle-price-example",
|
||||||
|
"version-1.9.4-oracle/oracle-sports-betting-example"
|
||||||
|
],
|
||||||
|
"Oracle Explorer Client": [
|
||||||
|
"version-1.9.4-oracle-explorer-client/oracle-explorer-client"
|
||||||
|
],
|
||||||
|
"Contributing": [
|
||||||
|
"version-1.9.4-contributing",
|
||||||
|
"version-1.9.4-contributing-website"
|
||||||
|
],
|
||||||
|
"Security": [
|
||||||
|
"version-1.9.4-security"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
[
|
[
|
||||||
|
"1.9.4",
|
||||||
"1.9.3",
|
"1.9.3",
|
||||||
"1.9.2",
|
"1.9.2",
|
||||||
"1.9.1",
|
"1.9.1",
|
||||||
|
|
Loading…
Add table
Reference in a new issue