Add secp256k1jni readme, start working main project readme, move old readme to core/README.md (#276)

Add documentation for TxBuilder

Try to fix links on core/README.md

add readme badges for bintray

Nits and formatting of README (#23)

ran scalafmt, fixed format in secp readme
This commit is contained in:
Chris Stewart 2019-01-08 09:29:06 -06:00 committed by GitHub
parent aa65b783cc
commit 268e235b4d
12 changed files with 328 additions and 155 deletions

175
README.md
View file

@ -1,176 +1,53 @@
[![Build Status](https://travis-ci.org/bitcoin-s/bitcoin-s-core.svg?branch=master)](https://travis-ci.org/bitcoin-s/bitcoin-s-core) [![Coverage Status](https://coveralls.io/repos/github/bitcoin-s/bitcoin-s-core/badge.svg?branch=master)](https://coveralls.io/github/bitcoin-s/bitcoin-s-core?branch=master) [![IRC Network](https://img.shields.io/badge/irc-%23bitcoin--scala-blue.svg "IRC Freenode")](https://webchat.freenode.net/?channels=bitcoin-scala)[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/bitcoin-s-core)
# Bitcoin-S-Core
# Bitcoin-S
This is the core functionality of bitcoin-s.
## Design Principles
[Quick Build Guide](BUILD_README.md)
- Immutable data structures everywhere
- [Algebraic Data Types](https://en.wikipedia.org/wiki/Algebraic_data_type) to allow the compiler to check for exhaustiveness on match statements
- Using [property based testing](http://www.scalatest.org/user_guide/property_based_testing) to test robustness of code
- Minimize dependencies to reduce attack surface
This repostitory includes the following functionality:
- Native Scala objects for various protocol types ([transactions](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/protocol/transaction/Transaction.scala), [inputs](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionInput.scala), [outputs](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionOutput.scala), [scripts signatures](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala), [scriptpubkeys](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala))
- [Serializers and deserializers for bitcoin data structures mentioned above](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/serializers)
- [An implementation of Bitcoin's Script programming language](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/script)
- Passes all tests found in Bitcoin Core's regression test suite called [script_test.json](https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_tests.json)
- Passes all tests inside of Bitcoin Core's transaction regression test suite [tx_valid.json](https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json) / [tx_invalid.json](https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json) /
[sighash.json](https://github.com/bitcoin/bitcoin/blob/master/src/test/data/sighash.json)
- [Payment channel support](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/channels/Channel.scala)
- Integration with [bitcoin core's optimized secp256k1](https://github.com/bitcoin-core/secp256k1/) library
- Consensus rule set up to date through segregated witness
- A robust set of [generators](https://github.com/bitcoin-s/bitcoin-s-core/tree/master/core-gen/src/test/scala/org/bitcoins/core/gen), which are used in property based testing
- These are extremely useful for testing bitcoin applications
- Here is an example of a specification for our [ECPrivateKey](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core-test/src/test/scala/org/bitcoins/core/crypto/ECPrivateKeySpec.scala)
- [Number types](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/number/NumberType.scala#L16) to represent C's unsigned numbers ([`UInt8`](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/number/NumberType.scala#L95), [`UInt32`](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/number/NumberType.scala#L106) etc) which are used in the bitcoin protocol
- 90% test coverage throughout the codebase to ensure high quality code.
- Functions documented with Scaladocs for user friendliness
## Projects
# Design Principles
- Immutable data structures everywhere
- Algebraic Data Types to allow the compiler to check for exhaustiveness on match statements
- Using [property based testing](http://www.scalatest.org/user_guide/property_based_testing) to test robustness of code
1. `core` - this is where protocol data structures live, like [Transactions](core/src/main/scala/org/bitcoins/core/protocol/transaction/Transaction.scala), [Blocks](core/src/main/scala/org/bitcoins/core/protocol/blockchain/Block.scala), or [PrivateKeys](core/src/main/scala/org/bitcoins/core/crypto/ECKey.scala). For more info read [`core/README.md`](core/README.md)
# Setting up libsecp256k1
2. `core-test` - this is where all test cases for the `core` project live
libsecp256k1 needs to be built with the java interface enabled. Use the following commands to build secp256k1 with jni enabled. [Here is the official documentation for doing this in secp256k1](https://github.com/bitcoin-core/secp256k1/blob/master/src/java/org/bitcoin/NativeSecp256k1.java#L35)
```
$ cd secp256k1
$ sh autogen.sh && ./configure --enable-jni --enable-experimental --enable-module-ecdh && make
$ sudo make install #optional, this installs the lib on your system
```
3. `rpc` - this is a RPC client implementation for `bitcoind`. For more info read [`rpc/README.md`](rpc/README.md)
By default, `.jvmopts` adds the freshly compiled `secp256k1` to the JVM classpath. It should therefore be sufficient to start `sbt` by simply doing
4. `eclair-rpc` - this is a RPC client implementation for [Eclair](https://en.wikipedia.org/wiki/Algebraic_data_type), which is a Lightning Network implementation. For more information please read [`eclair-rpc/README.md`](eclair-rpc-README.md)
```bash
$ sbt
```
5. `bench` - benchmarks for Bitcoin-S. For more information please read [`bench/README.md`](bench/README.md)
If you run into classpath problems, you can manually specify the JVM classpath like this:
6. `testkit` - This is a useful testkit for testing Bitcoin related applications. You can spin up Bitcoin and Lightning nodes arbitrarily and set them in specific states. For more information please read [`testkit/README.md`](testkit/README.md)
```
$ sbt -Djava.library.path=/your/class/path
```
7. `zmq` - `bitcoind` has a setting that publishes information about the state of the network over ZMQ. This project implements a subscriber that allows you to read and parse that information. For more information see [`zmq/README.md`](zmq/README.md) as well as the official [Bitcoin Core ZMQ documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md)
You can also copy `libsecp256k1.so` to your system library path.
## Artifacts
# TODO
- Simple [`TransactionBuilder`](https://github.com/MetacoSA/NBitcoin/blob/56bfd1cbca535424b160d8a40688a79de4800630/NBitcoin/TransactionBuilder.cs#L172) similar nbitcoin
- Hardware wallet support (trezor, ledger etc)
- Lightning network scriptpubkey types (some work done [here](https://github.com/Christewart/bitcoin-s-core/commits/lightning_contracts))
- sbt respository
- Java support
- Android support
You need to add the Bitcoin-S Bintray to your resolvers to be able to access published artifacts.
# Creating fat jar
Here is how you build a bitcoin-s-core fat jar file. Note this command will run the entire test suite in bitcoin-s-core.
With sbt, this can be done like this:
```scala
$ sbt assembly
[info] ScalaCheck
[info] Passed: Total 149, Failed 0, Errors 0, Passed 149
[info] ScalaTest
[info] Run completed in 5 minutes, 33 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
[info] Checking every *.class/*.jar file's SHA-1.
[info] Merging files...
[warn] Merging 'META-INF/MANIFEST.MF' with strategy 'discard'
[warn] Strategy 'discard' was applied to a file
[info] SHA-1: 6ea465dcc996cefb68fc334778cac60d892bd7f0
[info] Packaging /home/chris/dev/bitcoin-s-core/target/scala-2.11/bitcoin-s-core-assembly-0.0.1.jar ...
[info] Done packaging.
[success] Total time: 337 s, completed Jul 20, 2017 1:53:11 PM
resolvers += Resolver.bintrayRepo("bitcoin-s", "bitcoin-s-core"),
```
# Examples
Every bitcoin protocol data structure (and some other data structures) extends [`NetworkElement`](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/protocol/NetworkElement.scala). NetworkElement provides easier methods to convert the data structure to hex or a byte representation. When paired with our [`Factory`](https://github.com/bitcoin-s/bitcoin-s-core/blob/master/core/src/main/scala/org/bitcoins/core/util/Factory.scala) 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`](https://github.com/bitcoin-s/bitcoin-s-core/blob/1c7a7b9f46679a753248d9f55246c272bb3d63b9/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala#L462) companion object. You can use this companion object to create a SPK from hex or a byte array.
Here is an example scala console session with bitcoins-core
Now you should be able to add Bitcoin-S artifacts like this:
```scala
$ sbt console
[info] Loading global plugins from /home/chris/.sbt/0.13/plugins
[info] Loading project definition from /home/chris/dev/bitcoin-s-core/project
[info] Set current project to bitcoin-s-core (in build file:/home/chris/dev/bitcoin-s-core/)
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_151).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.protocol.transaction._
"org.bitcoins" % "bitcoin-s-secp256k1jni" % "0.0.1"
scala> val hexTx = "0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f8$9c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1$a02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e$90c865c2f6f7a9710a474154ab1423abb5b9288ac00000000"
hexTx: String = 0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1$52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02$45f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c$65c2f6f7a9710a474154ab1423abb5b9288ac00000000
"org.bitcoins" %% "bitcoin-s-core" % "0.0.1" withSources() withJavadoc()
scala> val tx = Transaction(hexTx)
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
tx: org.bitcoins.core.protocol.transaction.Transaction = BaseTransactionImpl(UInt32Impl(1),List(TransactionInputImpl(TransactionOutPointImpl$DoubleSha256DigestImpl(ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3),UInt32Impl(0)),P2PKHScriptSignatureImpl(6b483045022$008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf012102$1d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353),UInt32Impl(4294967295))),List(TransactionOutputImpl(SatoshisImpl(Int64Impl($9994000)),P2PKHScriptPubKeyImpl(1976a914b1d7591b69e9def0feb13254bace942923c7922d88ac)), TransactionOutputImpl(SatoshisImpl(Int64Impl(840)),P$PKHScriptPubKeyImpl(1976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac))),UInt32Impl(0))
"org.bitcoins" %% "bitcoin-s-bitcoind-rpc" % "0.0.1" withSources() withJavadoc()
scala> val hexAgain = tx.hex
hexAgain: String = 0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f88$c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1f$02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e6$0c865c2f6f7a9710a474154ab1423abb5b9288ac00000000
"org.bitcoins" %% "bitcoin-s-eclair-rpc" % "0.0.1" withSources() withJavadoc()
"org.bitcoins" %% "bitcoin-s-testkit" % "0.0.1" withSources() withJavadoc()
"org.bitcoins" %% "bitcoin-s-zmq" % "0.0.1" withSources() withJavadoc()
```
This gives us an example of a bitcoin transaction that is encoded in hex format that is deserialized to a native Scala object called a [`Transaction`](https://github.com/bitcoin-s/bitcoin-s-core/blob/6358eb83067909771f989d615b422759222d060a/src/main/scala/org/bitcoins/core/protocol/transaction/Transaction.scala#L14-L42). 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`](https://github.com/bitcoin-s/bitcoin-s-core/blob/6358eb83067909771f989d615b422759222d060a/src/main/scala/org/bitcoins/core/crypto/ECKey.scala#L23-L67), [`ScriptPubKey`](https://github.com/bitcoin-s/bitcoin-s-core/blob/6358eb83067909771f989d615b422759222d060a/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala#L23), [`ScriptWitness`](https://github.com/bitcoin-s/bitcoin-s-core/blob/6358eb83067909771f989d615b422759222d060a/src/main/scala/org/bitcoins/core/protocol/script/ScriptWitness.scala#L13), and [`Block`](https://github.com/bitcoin-s/bitcoin-s-core/blob/6358eb83067909771f989d615b422759222d060a/src/main/scala/org/bitcoins/core/protocol/blockchain/Block.scala#L17).
Transactions are run through the interpreter to check the validity of the Transaction. 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
chris@chris:~/dev/bitcoins-core$ sbt console
[info] Loading project definition from /home/chris/dev/bitcoins-core/project
[info] Set current project to bitcoins (in build file:/home/chris/dev/bitcoins-core/)
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import org.bitcoins.core.protocol.script._
import org.bitcoins.core.protocol.script._
scala> import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.protocol.transaction._
scala> import org.bitcoins.core.script._
import org.bitcoins.core.script._
scala> import org.bitcoins.core.script.interpreter._
import org.bitcoins.core.script.interpreter._
scala> import org.bitcoins.core.policy._
import org.bitcoins.core.policy._
scala> val spendingTx = Transaction("0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000")
spendingTx: org.bitcoins.core.protocol.transaction.Transaction = TransactionImpl(1,List(TransactionInputImpl(TransactionOutPointImpl(b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc,0),P2PKHScriptSignatureImpl(4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353,List(BytesToPushOntoStackImpl(72), ScriptConstantImpl(30450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01), BytesToPushOntoStackImpl(33), ScriptConstantImpl(0241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353))),4294967295)),List(TransactionOutputImpl(8...
scala> val scriptPubKey = ScriptPubKey("76a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac")
scriptPubKey: org.bitcoins.core.protocol.script.ScriptPubKey = P2PKHScriptPubKeyImpl(76a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac,List(OP_DUP, OP_HASH160, BytesToPushOntoStackImpl(20), ScriptConstantImpl(31a420903c05a0a7de2de40c9f02ebedbacdc172), OP_EQUALVERIFY, OP_CHECKSIG))
scala> val inputIndex = 0
inputIndex: Int = 0
scala> val program = ScriptProgram(spendingTx,scriptPubKey,inputIndex, Policy.standardScriptVerifyFlags)
program: org.bitcoins.core.script.PreExecutionScriptProgram = PreExecutionScriptProgramImpl(TransactionSignatureComponentImpl(TransactionImpl(1,List(TransactionInputImpl(TransactionOutPointImpl(b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc,0),P2PKHScriptSignatureImpl(4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353,List(BytesToPushOntoStackImpl(72), ScriptConstantImpl(30450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01), BytesToPushOntoStackImpl(33), ScriptConstantImpl(0241d746ca08da0a668735c3e01c1fa02045f2f399c5937079...
scala> ScriptInterpreter.run(program)
res0: org.bitcoins.core.script.result.ScriptResult = ScriptOk
```
# Interacting with bitcoind
Please see our other project [`bitcoin-s-rpc-client`](https://github.com/bitcoin-s/bitcoin-s-rpc-client)
# Stand alone SPV Node
Please see our other project [`bitcoin-s-spv-node`](https://github.com/bitcoin-s/bitcoin-s-spv-node)

View file

@ -1,3 +1,5 @@
[ ![Download](https://api.bintray.com/packages/bitcoin-s/bitcoin-s-core/bitcoin-s-bench/images/download.svg) ](https://bintray.com/bitcoin-s/bitcoin-s-core/bitcoin-s-bench/_latestVersion)
# Benchmark suite
This is a WIP. It currently contains one bench mark for de-serializing large blocks

View file

@ -33,6 +33,7 @@ lazy val testCompilerOpts = commonCompilerOpts
lazy val commonSettings = List(
scalacOptions in Compile := compilerOpts,
scalacOptions in Test := testCompilerOpts,
assemblyOption in assembly := (assemblyOption in assembly).value
.copy(includeScala = false),
@ -89,7 +90,8 @@ lazy val root = project
rpc,
bench,
eclairRpc,
testkit
testkit,
doc
)
.settings(commonSettings: _*)
@ -134,9 +136,6 @@ lazy val rpc = project
.dependsOn(
core
)
.settings(
testOptions in Test += Tests.Argument("-oF")
)
lazy val bench = project
.in(file("bench"))
@ -170,4 +169,15 @@ lazy val testkit = project
)
lazy val doc = project
.in(file("doc"))
.settings(
name := "bitcoin-s-doc",
libraryDependencies ++= Deps.doc
)
.dependsOn(
secp256k1jni,
core
)
publishArtifact in root := false

1
core-test/README.md Normal file
View file

@ -0,0 +1 @@
[ ![Download](https://api.bintray.com/packages/bitcoin-s/bitcoin-s-core/bitcoin-s-core-test/images/download.svg) ](https://bintray.com/bitcoin-s/bitcoin-s-core/bitcoin-s-core-test/_latestVersion)

157
core/README.md Normal file
View file

@ -0,0 +1,157 @@
[ ![Download](https://api.bintray.com/packages/bitcoin-s/bitcoin-s-core/bitcoin-s-core/images/download.svg) ](https://bintray.com/bitcoin-s/bitcoin-s-core/bitcoin-s-core/_latestVersion)
# `core` module
This is the core 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](http://www.scalatest.org/user_guide/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`](src/main/scala/org/bitcoins/core/protocol/NetworkElement.scala). `NetworkElement` provides methods to convert the data structure to hex or byte representation. When paired with [`Factory`](src/main/scala/org/bitcoins/core/util/Factory.scala) 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`](https://github.com/bitcoin-s/bitcoin-s-core/blob/1c7a7b9f46679a753248d9f55246c272bb3d63b9/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala#L462) 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`](src/main/scala/org/bitcoins/core/protocol) - basic protocol data structures. Useful for serializing/deserializing things
2. [`script`](src/main/scala/org/bitcoins/core/script) - an implementation of [Script](https://en.bitcoin.it/wiki/Script) - the programming language in Bitcoin
3. [`wallet`](src/main/scala/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.
4. [`config`](src/main/scala/org/bitcoins/core/config) - Contains information about a chain's genesis block and DNS seeds
5. [`number`](src/main/scala/org/bitcoins/core/number) - Implements number types that are native in C, i.e. `UInt8`, `UInt32`, `UInt64`, etc.
6. [`currency`](src/main/scala/org/bitcoins/core/currency) - Implements currency units in the Bitcoin protocol
7. [`bloom`](src/main/scala/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)
## Examples
### Serializing and deserializing a `Transaction`
Here is an example scala console session with bitcoins-core
```scala
$ sbt core/console
[info] Loading global plugins from /home/chris/.sbt/0.13/plugins
[info] Loading project definition from /home/chris/dev/bitcoin-s-core/project
[info] Set current project to bitcoin-s-core (in build file:/home/chris/dev/bitcoin-s-core/)
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_151).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.protocol.transaction._
scala> val hexTx = "0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f8$9c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1$a02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e$90c865c2f6f7a9710a474154ab1423abb5b9288ac00000000"
hexTx: String = 0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1$52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02$45f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c$65c2f6f7a9710a474154ab1423abb5b9288ac00000000
scala> val tx = Transaction.fromHex(hexTx)
tx: org.bitcoins.core.protocol.transaction.Transaction = BaseTransactionImpl(UInt32Impl(1),List(TransactionInputImpl(TransactionOutPointImpl$DoubleSha256DigestImpl(ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3),UInt32Impl(0)),P2PKHScriptSignatureImpl(6b483045022$008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf012102$1d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353),UInt32Impl(4294967295))),List(TransactionOutputImpl(SatoshisImpl(Int64Impl($9994000)),P2PKHScriptPubKeyImpl(1976a914b1d7591b69e9def0feb13254bace942923c7922d88ac)), TransactionOutputImpl(SatoshisImpl(Int64Impl(840)),P$PKHScriptPubKeyImpl(1976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac))),UInt32Impl(0))
scala> val hexAgain = tx.hex
hexAgain: String = 0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f88$c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1f$02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e6$0c865c2f6f7a9710a474154ab1423abb5b9288ac00000000
```
This gives us an example of a hex encoded Bitcoin transaction that is deserialized to a native Scala object called a [`Transaction`](https://github.com/bitcoin-s/bitcoin-s-core/blob/6358eb83067909771f989d615b422759222d060a/src/main/scala/org/bitcoins/core/protocol/transaction/Transaction.scala#L14-L42). 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`](https://github.com/bitcoin-s/bitcoin-s-core/blob/6358eb83067909771f989d615b422759222d060a/src/main/scala/org/bitcoins/core/crypto/ECKey.scala#L23-L67), [`ScriptPubKey`](https://github.com/bitcoin-s/bitcoin-s-core/blob/6358eb83067909771f989d615b422759222d060a/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala#L23), [`ScriptWitness`](https://github.com/bitcoin-s/bitcoin-s-core/blob/6358eb83067909771f989d615b422759222d060a/src/main/scala/org/bitcoins/core/protocol/script/ScriptWitness.scala#L13), and [`Block`](https://github.com/bitcoin-s/bitcoin-s-core/blob/6358eb83067909771f989d615b422759222d060a/src/main/scala/org/bitcoins/core/protocol/blockchain/Block.scala#L17).
### 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`](src/main/scala/org/bitcoins/core/wallet/utxo/UTXOSpendingInfo.scala). This contains all of the information needed to create a validly signed [`ScriptSignature`](src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala) that spends this output.
Our [`TxBuilder`](src/main/scala/org/bitcoins/core/wallet/builder/TxBuilder.scala) class requires you to provide the following:
1. `destinations` - the places we are sending bitcoin to. These are [TransactionOutputs](src/main/scala/org/bitcoins/core/protocol/transaction/TransactionOutput.scala) you are sending coins too
2. `utxos` - these are the [UTXOs](src/main/scala/org/bitcoins/core/wallet/utxo/UTXOSpendingInfo.scala) 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`](src/main/scala/org/bitcoins/core/config/NetworkParameters.scala) we are transacting on
After providing this information, you can generate a validly signed bitcoin transaction by calling the `sign` method.
### The [`Sign` API](src/main/scala/org/bitcoins/core/crypto/Sign.scala)
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`](src/main/scala/org/bitcoins/core/crypto/Sign.scala):
```scala
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`](src/main/scala/org/bitcoins/core/crypto/TransactionSignatureSerializer.scala)'s `hashForSignature` method. Our in-memory [`ECKey`](src/main/scala/org/bitcoins/core/crypto/ECKey.scala) 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`](src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala)s. The `Signer` subtypes (i.e. `P2PKHSigner`) implement the specific functionality needed to produce a valid digital signature for their corresponding script type.
#### Complete `TxBuilder` example
For an example of how to use the `TxBuilder` please see [`TxBuilderExample.scala`](../doc/src/test/scala/TxBuilderExample.scala).
### 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
chris@chris:~/dev/bitcoins-core$ sbt core/console
scala> import org.bitcoins.core.protocol.script._
scala> import org.bitcoins.core.protocol.transaction._
scala> import org.bitcoins.core.script._
scala> import org.bitcoins.core.script.interpreter._
scala> import org.bitcoins.core.policy._
scala> import org.bitcoins.core.number._
scala> import org.bitcoins.core.crypto._
scala> import org.bitcoins.core.currency._
scala> val spendingTx = Transaction.fromHex("0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000")
spendingTx: org.bitcoins.core.protocol.transaction.Transaction = ... // omitted for brevity
scala> val scriptPubKey = ScriptPubKey.fromAsmHex("76a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac")
scriptPubKey: org.bitcoins.core.protocol.script.ScriptPubKey = P2PKHScriptPubKeyImpl(1976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac)
scala> val output = TransactionOutput(CurrencyUnits.zero, scriptPubKey)
output: org.bitcoins.core.protocol.transaction.TransactionOutput = ... // omitted for brevity
scala> val inputIndex = UInt32.zero
inputIndex: org.bitcoins.core.number.UInt32 = UInt32Impl(0)
scala> val btxsc = BaseTxSigComponent(spendingTx,inputIndex,output,Policy.standardScriptVerifyFlags)
btxsc: org.bitcoins.core.crypto.BaseTxSigComponent = ... // omitted for brevity
scala> val preExecution = PreExecutionScriptProgram(btxsc)
preExecution: org.bitcoins.core.script.PreExecutionScriptProgram = ... // omitted for brevity
scala> val result = ScriptInterpreter.run(preExecution)
result: org.bitcoins.core.script.result.ScriptResult = ScriptOk
```
## Running `core` tests
To run the entire `core` test suite:
```bash
chris@chris:~/dev/bitcoins-core$ sbt coreTest/test
# lots of output, should end up with something like this
[info] All tests passed.
[info] Passed: Total 1008, Failed 0, Errors 0, Passed 1008
[success] Total time: 38 s, completed Dec 23, 2018 4:39:58 PM
```

View file

@ -139,8 +139,7 @@ object ECPrivateKey extends Factory[ECPrivateKey] {
extends ECPrivateKey {
require(
NativeSecp256k1.secKeyVerify(bytes.toArray),
"Invalid key according to secp256k1, hex: " + BitcoinSUtil.encodeHex(
bytes))
s"Invalid key according to secp256k1, hex: ${bytes.toHex}")
}
def apply(bytes: ByteVector, isCompressed: Boolean)(

58
doc/SECURITY.md Normal file
View file

@ -0,0 +1,58 @@
## Disclosure
Please send an email to stewart.chris1234@gmail.com encrypted with this gpg key
```
-----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-----
```

View file

@ -1,3 +1,5 @@
[ ![Download](https://api.bintray.com/packages/bitcoin-s/bitcoin-s-core/bitcoin-s-eclair-rpc/images/download.svg) ](https://bintray.com/bitcoin-s/bitcoin-s-core/bitcoin-s-eclair-rpc/_latestVersion)
# Bitcoin-s Eclair RPC client
This is a RPC client for [Eclair](https://github.com/acinq/eclair). It assumes that a bitcoind instance is running.

View file

@ -117,4 +117,9 @@ object Deps {
Compile.slf4j,
"org.scalacheck" %% "scalacheck" % V.scalacheck withSources() withJavadoc()
)
val doc = List(
Test.scalaTest,
Test.logback
)
}

1
rpc/README.md Normal file
View file

@ -0,0 +1 @@
[ ![Download](https://api.bintray.com/packages/bitcoin-s/bitcoin-s-core/bitcoin-s-bitcoind-rpc/images/download.svg) ](https://bintray.com/bitcoin-s/bitcoin-s-core/bitcoin-s-bitcoind-rpc/_latestVersion)

60
secp256k1jni/README.md Normal file
View file

@ -0,0 +1,60 @@
[ ![Download](https://api.bintray.com/packages/bitcoin-s/bitcoin-s-core/bitcoin-s-secp256k1jni/images/download.svg) ](https://bintray.com/bitcoin-s/bitcoin-s-core/bitcoin-s-secp256k1jni/_latestVersion)
## Secp256k1jni
This project gives people a conviinent way to use [libsecp256k1](https://github.com/bitcoin-core/secp256k1) on the JVM without compiling natives themselves.
Currently we have support for natives on
1. [linux 32 bit](natives/linux_32)
2. [linux 64 bit](natives/linux_64)
3. [mac osx 64 bit](natives/osx_64)
This uses a zero depdency library called `native-lib-loader`. The does the appropriate loading of the library onto your classpath to be accessed. To tell if you have access to libsecp256k1 you can do the following
```scala
sbt:root> project secp256k1jni
[info] Set current project to bitcoin-s-secp256k1jni (in build file:/home/chris/dev/bitcoin-s-core/)
sbt:bitcoin-s-secp256k1jni> console
[info] Starting scala interpreter...
Welcome to Scala 2.12.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_191).
Type in expressions for evaluation. Or try :help.
scala> import org.bitcoin.Secp256k1Context;
scala> Secp256k1Context.isEnabled()
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
res0: Boolean = true
```
## Adding secp256k1jni to your project
To add `bitcoin-s-secp256k1jni` to your project you add it like this
```
"org.bitcoins" % "bitcoin-s-secp256k1jni" % "0.0.1"
```
or with maven
```
<dependency>
<groupId>org.bitcoins</groupId>
<artifactId>bitcoin-s-secp256k1jni</artifactId>
<version>0.0.1</version>
</dependency>
```
## Using secp256k1
The file [NativeSecp256k1.java](src/main/java/org/bitcoin/NativeSecp256k1.java) contains basic functionality for
1. Verifying digital signatures
2. Producing digital signatures
3. Computing a public key from a private key
4. tweaking keys
5. Checking public key validity

1
testkit/README.md Normal file
View file

@ -0,0 +1 @@
[ ![Download](https://api.bintray.com/packages/bitcoin-s/bitcoin-s-core/bitcoin-s-testkit/images/download.svg) ](https://bintray.com/bitcoin-s/bitcoin-s-core/bitcoin-s-testkit/_latestVersion)