From d01e37cfa8ecedce474a96ffa21f967a52ce79e8 Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Tue, 8 Jan 2019 09:29:06 -0600 Subject: [PATCH] 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 --- README.md | 175 ++---------- bench/README.md | 2 + build.sbt | 18 +- core-test/README.md | 1 + .../wallet/builder/BitcoinTxBuilderTest.scala | 266 ++++++++++-------- core/README.md | 157 +++++++++++ .../org/bitcoins/core/crypto/ECKey.scala | 3 +- .../core/wallet/builder/TxBuilder.scala | 12 +- doc/SECURITY.md | 58 ++++ doc/src/test/scala/TxBuilderExample.scala | 157 +++++++++++ eclair-rpc/README.md | 2 + project/Deps.scala | 5 + rpc/README.md | 1 + secp256k1jni/README.md | 60 ++++ testkit/README.md | 1 + 15 files changed, 632 insertions(+), 286 deletions(-) create mode 100644 core-test/README.md create mode 100644 core/README.md create mode 100644 doc/SECURITY.md create mode 100644 doc/src/test/scala/TxBuilderExample.scala create mode 100644 rpc/README.md create mode 100644 secp256k1jni/README.md create mode 100644 testkit/README.md diff --git a/README.md b/README.md index 65c4280025..515c371d64 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/bench/README.md b/bench/README.md index 7368f6f830..183a7b367a 100644 --- a/bench/README.md +++ b/bench/README.md @@ -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 diff --git a/build.sbt b/build.sbt index 50d1ce20fa..03c6eedb5f 100644 --- a/build.sbt +++ b/build.sbt @@ -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 diff --git a/core-test/README.md b/core-test/README.md new file mode 100644 index 0000000000..f84787a334 --- /dev/null +++ b/core-test/README.md @@ -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) diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/BitcoinTxBuilderTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/BitcoinTxBuilderTest.scala index d2b77eaa3c..7041aec41f 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/BitcoinTxBuilderTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/BitcoinTxBuilderTest.scala @@ -21,25 +21,25 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk) val destinations = - Seq(TransactionOutput(Satoshis(Int64(1)), EmptyScriptPubKey)) - val creditingTx = BaseTransaction(tc.validLockVersion, - Nil, - Seq(creditingOutput), - tc.lockTime) + Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) + val creditingTx = BaseTransaction(version = tc.validLockVersion, + inputs = Nil, + outputs = Seq(creditingOutput), + lockTime = tc.lockTime) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) - val utxo = BitcoinUTXOSpendingInfo(outPoint, - creditingOutput, - Seq(privKey), - None, - None, - HashType.sigHashAll) + val utxo = BitcoinUTXOSpendingInfo(outPoint = outPoint, + output = creditingOutput, + signers = Seq(privKey), + redeemScriptOpt = None, + scriptWitnessOpt = None, + hashType = HashType.sigHashAll) val utxoMap: BitcoinTxBuilder.UTXOMap = Map(outPoint -> utxo) val feeUnit = SatoshisPerVirtualByte(Satoshis.one) - val txBuilder = BitcoinTxBuilder(destinations, - utxoMap, - feeUnit, - EmptyScriptPubKey, - TestNet3) + val txBuilder = BitcoinTxBuilder(destinations = destinations, + utxos = utxoMap, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey, + network = TestNet3) val resultFuture = txBuilder.flatMap(_.sign) recoverToSucceededIf[IllegalArgumentException] { resultFuture @@ -49,25 +49,25 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { it must "fail to build a transaction when we pass in a negative fee rate" in { val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk) val destinations = - Seq(TransactionOutput(Satoshis(Int64(1)), EmptyScriptPubKey)) - val creditingTx = BaseTransaction(tc.validLockVersion, - Nil, - Seq(creditingOutput), - tc.lockTime) + Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) + val creditingTx = BaseTransaction(version = tc.validLockVersion, + inputs = Nil, + outputs = Seq(creditingOutput), + lockTime = tc.lockTime) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) - val utxo = BitcoinUTXOSpendingInfo(outPoint, - creditingOutput, - Seq(privKey), - None, - None, - HashType.sigHashAll) + val utxo = BitcoinUTXOSpendingInfo(outPoint = outPoint, + output = creditingOutput, + signers = Seq(privKey), + redeemScriptOpt = None, + scriptWitnessOpt = None, + hashType = HashType.sigHashAll) val utxoMap: BitcoinTxBuilder.UTXOMap = Map(outPoint -> utxo) val feeUnit = SatoshisPerVirtualByte(Satoshis(Int64(-1))) - val txBuilder = BitcoinTxBuilder(destinations, - utxoMap, - feeUnit, - EmptyScriptPubKey, - TestNet3) + val txBuilder = BitcoinTxBuilder(destinations = destinations, + utxos = utxoMap, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey, + network = TestNet3) recoverToSucceededIf[IllegalArgumentException] { txBuilder } @@ -76,7 +76,7 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { it must "fail a transaction when the user invariants fail" in { val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk) val destinations = - Seq(TransactionOutput(Satoshis(Int64(1)), EmptyScriptPubKey)) + Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) val creditingTx = BaseTransaction(tc.validLockVersion, Nil, Seq(creditingOutput), @@ -89,12 +89,12 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { None, HashType.sigHashAll) val utxoMap: BitcoinTxBuilder.UTXOMap = Map(outPoint -> utxo) - val feeUnit = SatoshisPerVirtualByte(Satoshis(Int64(1))) - val txBuilder = BitcoinTxBuilder(destinations, - utxoMap, - feeUnit, - EmptyScriptPubKey, - TestNet3) + val feeUnit = SatoshisPerVirtualByte(currencyUnit = Satoshis(Int64(1))) + val txBuilder = BitcoinTxBuilder(destinations = destinations, + utxos = utxoMap, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey, + network = TestNet3) //trivially false val f = (_: Seq[BitcoinUTXOSpendingInfo], _: Transaction) => false val resultFuture = txBuilder.flatMap(_.sign(f)) @@ -104,39 +104,44 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { } it must "be able to create a BitcoinTxBuilder from UTXOTuple and UTXOMap" in { - val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk) - val destinations = - Seq(TransactionOutput(Satoshis(Int64(1)), EmptyScriptPubKey)) - val creditingTx = BaseTransaction(tc.validLockVersion, - Nil, - Seq(creditingOutput), - tc.lockTime) + val creditingOutput = + TransactionOutput(currencyUnit = CurrencyUnits.zero, scriptPubKey = spk) + val destinations = { + Seq( + TransactionOutput(currencyUnit = Satoshis.one, + scriptPubKey = EmptyScriptPubKey)) + } + val creditingTx = BaseTransaction(version = tc.validLockVersion, + inputs = Nil, + outputs = Seq(creditingOutput), + lockTime = tc.lockTime) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) - val utxo = BitcoinUTXOSpendingInfo(outPoint, - creditingOutput, - Seq(privKey), - None, - None, - HashType.sigHashAll) + val utxo = BitcoinUTXOSpendingInfo(outPoint = outPoint, + output = creditingOutput, + signers = Seq(privKey), + redeemScriptOpt = None, + scriptWitnessOpt = None, + hashType = HashType.sigHashAll) val utxoMap: BitcoinTxBuilder.UTXOMap = Map(outPoint -> utxo) - val utxoSpendingInfo = BitcoinUTXOSpendingInfo(outPoint, - creditingOutput, - Seq(privKey), - None, - None, - HashType.sigHashAll) + val utxoSpendingInfo = BitcoinUTXOSpendingInfo(outPoint = outPoint, + output = creditingOutput, + signers = Seq(privKey), + redeemScriptOpt = None, + scriptWitnessOpt = None, + hashType = + HashType.sigHashAll) - val feeUnit = SatoshisPerVirtualByte(Satoshis(Int64(1))) - val txBuilderMap = BitcoinTxBuilder(destinations, - utxoMap, - feeUnit, - EmptyScriptPubKey, - TestNet3) - val txBuilderTuple = BitcoinTxBuilder(destinations, - Seq(utxoSpendingInfo), - feeUnit, - EmptyScriptPubKey, - TestNet3) + val feeUnit = SatoshisPerVirtualByte(Satoshis.one) + val txBuilderMap = BitcoinTxBuilder(destinations = destinations, + utxos = utxoMap, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey, + network = TestNet3) + val txBuilderTuple = BitcoinTxBuilder(destinations = destinations, + utxos = Seq(utxoSpendingInfo), + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey, + network = TestNet3) txBuilderTuple.flatMap { tup => txBuilderMap.map { map => @@ -149,25 +154,27 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { val p2sh = P2SHScriptPubKey(spk) val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2sh) val destinations = - Seq(TransactionOutput(Satoshis(Int64(1)), EmptyScriptPubKey)) - val creditingTx = BaseTransaction(tc.validLockVersion, - Nil, - Seq(creditingOutput), - tc.lockTime) + Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) + val creditingTx = BaseTransaction(version = tc.validLockVersion, + inputs = Nil, + outputs = Seq(creditingOutput), + lockTime = tc.lockTime) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) - val utxo = BitcoinUTXOSpendingInfo(outPoint, - creditingOutput, - Seq(privKey), - Some(EmptyScriptPubKey), - None, - HashType.sigHashAll) + val utxo = BitcoinUTXOSpendingInfo( + outPoint = outPoint, + output = creditingOutput, + signers = Seq(privKey), + redeemScriptOpt = Some(EmptyScriptPubKey), + scriptWitnessOpt = None, + hashType = HashType.sigHashAll + ) val utxoMap: BitcoinTxBuilder.UTXOMap = Map(outPoint -> utxo) - val feeUnit = SatoshisPerVirtualByte(Satoshis(Int64(1))) - val txBuilderNoRedeem = BitcoinTxBuilder(destinations, - utxoMap, - feeUnit, - EmptyScriptPubKey, - TestNet3) + val feeUnit = SatoshisPerVirtualByte(Satoshis.one) + val txBuilderNoRedeem = BitcoinTxBuilder(destinations = destinations, + utxos = utxoMap, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey, + network = TestNet3) val resultFuture = txBuilderNoRedeem.flatMap(_.sign) recoverToSucceededIf[IllegalArgumentException] { resultFuture @@ -178,7 +185,7 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { val p2wsh = P2WSHWitnessSPKV0(spk) val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2wsh) val destinations = - Seq(TransactionOutput(Satoshis(Int64(1)), EmptyScriptPubKey)) + Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) val creditingTx = BaseTransaction(tc.validLockVersion, Nil, Seq(creditingOutput), @@ -192,7 +199,7 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { HashType.sigHashAll) val utxoMap: BitcoinTxBuilder.UTXOMap = Map(outPoint -> utxo) - val feeUnit = SatoshisPerVirtualByte(Satoshis(Int64(1))) + val feeUnit = SatoshisPerVirtualByte(Satoshis.one) val txBuilderWitness = BitcoinTxBuilder(destinations, utxoMap, feeUnit, @@ -208,7 +215,7 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { val p2pkh = P2PKHScriptPubKey(privKey.publicKey) val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2pkh) val destinations = - Seq(TransactionOutput(Satoshis(Int64(1)), EmptyScriptPubKey)) + Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) val creditingTx = BaseTransaction(tc.validLockVersion, Nil, Seq(creditingOutput), @@ -222,7 +229,7 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { HashType.sigHashAll) val utxoMap: BitcoinTxBuilder.UTXOMap = Map(outPoint -> utxo) - val feeUnit = SatoshisPerVirtualByte(Satoshis(Int64(1))) + val feeUnit = SatoshisPerVirtualByte(Satoshis.one) val txBuilderWitness = BitcoinTxBuilder(destinations, utxoMap, feeUnit, @@ -239,26 +246,29 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { val pubKey2 = ECPrivateKey().publicKey val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2pkh) val destinations = - Seq(TransactionOutput(Satoshis(Int64(1)), EmptyScriptPubKey)) - val creditingTx = BaseTransaction(tc.validLockVersion, - Nil, - Seq(creditingOutput), - tc.lockTime) - val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) - val utxo = BitcoinUTXOSpendingInfo(outPoint, - creditingOutput, - Seq(privKey), - None, - Some(P2WSHWitnessV0(EmptyScriptPubKey)), - HashType.sigHashAll) + Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) + val creditingTx = BaseTransaction(version = tc.validLockVersion, + inputs = Nil, + outputs = Seq(creditingOutput), + lockTime = tc.lockTime) + val outPoint = + TransactionOutPoint(txId = creditingTx.txId, index = UInt32.zero) + val utxo = BitcoinUTXOSpendingInfo( + outPoint = outPoint, + output = creditingOutput, + signers = Seq(privKey), + redeemScriptOpt = None, + scriptWitnessOpt = Some(P2WSHWitnessV0(EmptyScriptPubKey)), + hashType = HashType.sigHashAll + ) val utxoMap: BitcoinTxBuilder.UTXOMap = Map(outPoint -> utxo) - val feeUnit = SatoshisPerVirtualByte(Satoshis(Int64(1))) - val txBuilderWitness = BitcoinTxBuilder(destinations, - utxoMap, - feeUnit, - EmptyScriptPubKey, - TestNet3) + val feeUnit = SatoshisPerVirtualByte(Satoshis.one) + val txBuilderWitness = BitcoinTxBuilder(destinations = destinations, + utxos = utxoMap, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey, + network = TestNet3) val resultFuture = txBuilderWitness.flatMap(_.sign) recoverToSucceededIf[IllegalArgumentException] { resultFuture @@ -266,24 +276,30 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { } it must "fail to sign a p2wpkh if we don't pass in the public key" in { - val p2wpkh = P2WPKHWitnessSPKV0(privKey.publicKey) - val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2wpkh) + val p2wpkh = P2WPKHWitnessSPKV0(pubKey = privKey.publicKey) + val creditingOutput = TransactionOutput(currencyUnit = CurrencyUnits.zero, + scriptPubKey = p2wpkh) val destinations = - Seq(TransactionOutput(Satoshis(Int64(1)), EmptyScriptPubKey)) - val creditingTx = BaseTransaction(tc.validLockVersion, - Nil, - Seq(creditingOutput), - tc.lockTime) - val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) - val utxo = BitcoinUTXOSpendingInfo(outPoint, - creditingOutput, - Seq(privKey), - None, - Some(P2WSHWitnessV0(EmptyScriptPubKey)), - HashType.sigHashAll) + Seq( + TransactionOutput(currencyUnit = Satoshis.one, + scriptPubKey = EmptyScriptPubKey)) + val creditingTx = BaseTransaction(version = tc.validLockVersion, + inputs = Nil, + outputs = Seq(creditingOutput), + lockTime = tc.lockTime) + val outPoint = + TransactionOutPoint(txId = creditingTx.txId, index = UInt32.zero) + val utxo = BitcoinUTXOSpendingInfo( + outPoint = outPoint, + output = creditingOutput, + signers = Seq(privKey), + redeemScriptOpt = None, + scriptWitnessOpt = Some(P2WSHWitnessV0(EmptyScriptPubKey)), + hashType = HashType.sigHashAll + ) val utxoMap: BitcoinTxBuilder.UTXOMap = Map(outPoint -> utxo) - val feeUnit = SatoshisPerVirtualByte(Satoshis(Int64(1))) + val feeUnit = SatoshisPerVirtualByte(Satoshis.one) val txBuilderWitness = BitcoinTxBuilder(destinations, utxoMap, feeUnit, @@ -300,7 +316,7 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { val pubKey2 = ECPrivateKey().publicKey val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2wpkh) val destinations = - Seq(TransactionOutput(Satoshis(Int64(1)), EmptyScriptPubKey)) + Seq(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) val creditingTx = BaseTransaction(tc.validLockVersion, Nil, Seq(creditingOutput), @@ -314,7 +330,7 @@ class BitcoinTxBuilderTest extends AsyncFlatSpec with MustMatchers { HashType.sigHashAll) val utxoMap: BitcoinTxBuilder.UTXOMap = Map(outPoint -> utxo) - val feeUnit = SatoshisPerVirtualByte(Satoshis(Int64(1))) + val feeUnit = SatoshisPerVirtualByte(Satoshis.one) val txBuilderWitness = BitcoinTxBuilder(destinations, utxoMap, feeUnit, diff --git a/core/README.md b/core/README.md new file mode 100644 index 0000000000..56eb7ea1a5 --- /dev/null +++ b/core/README.md @@ -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 +``` diff --git a/core/src/main/scala/org/bitcoins/core/crypto/ECKey.scala b/core/src/main/scala/org/bitcoins/core/crypto/ECKey.scala index c9506343b6..909498f675 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/ECKey.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/ECKey.scala @@ -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)( diff --git a/core/src/main/scala/org/bitcoins/core/wallet/builder/TxBuilder.scala b/core/src/main/scala/org/bitcoins/core/wallet/builder/TxBuilder.scala index 4ee165c5db..51ee24f25f 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/builder/TxBuilder.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/builder/TxBuilder.scala @@ -932,12 +932,12 @@ object BitcoinTxBuilder { utxos match { case Nil => accum case h :: t => - val u = BitcoinUTXOSpendingInfo(h.outPoint, - h.output, - h.signers, - h.redeemScriptOpt, - h.scriptWitnessOpt, - h.hashType) + val u = BitcoinUTXOSpendingInfo(outPoint = h.outPoint, + output = h.output, + signers = h.signers, + redeemScriptOpt = h.redeemScriptOpt, + scriptWitnessOpt = h.scriptWitnessOpt, + hashType = h.hashType) val result: BitcoinTxBuilder.UTXOMap = accum.updated(h.outPoint, u) loop(t, result) } diff --git a/doc/SECURITY.md b/doc/SECURITY.md new file mode 100644 index 0000000000..f7982ebc6e --- /dev/null +++ b/doc/SECURITY.md @@ -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----- +``` diff --git a/doc/src/test/scala/TxBuilderExample.scala b/doc/src/test/scala/TxBuilderExample.scala new file mode 100644 index 0000000000..6f01d0e7bf --- /dev/null +++ b/doc/src/test/scala/TxBuilderExample.scala @@ -0,0 +1,157 @@ +import org.bitcoins.core.config.RegTest +import org.bitcoins.core.crypto.ECPrivateKey +import org.bitcoins.core.currency.Satoshis +import org.bitcoins.core.number.{Int32, Int64, UInt32} +import org.bitcoins.core.protocol.script.P2PKHScriptPubKey +import org.bitcoins.core.protocol.transaction.{ + BaseTransaction, + Transaction, + TransactionOutPoint, + TransactionOutput +} +import org.bitcoins.core.script.crypto.HashType +import org.bitcoins.core.wallet.builder.BitcoinTxBuilder +import org.bitcoins.core.wallet.fee.SatoshisPerByte +import org.bitcoins.core.wallet.utxo.BitcoinUTXOSpendingInfo +import org.scalatest.{FlatSpec, MustMatchers} + +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.Future + +class TxBuilderExample extends FlatSpec with MustMatchers { + + behavior of "TxBuilderExample" + + it must "build a signed tx" in { + + //This is a documented example of how to create a signed bitcoin transaction + //with bitcoin-s. You can run this test case with the following sbt command + + //$ sbt "doc/testOnly *TxBuilderExample -- -z signed" + + //generate a fresh private key that we are going to use in the scriptpubkey + val privKey = ECPrivateKey.freshPrivateKey + + //this is the script that the TxBuilder is going to create a + //script signature that validly spends this scriptPubKey + val creditingSpk = P2PKHScriptPubKey(pubKey = privKey.publicKey) + val amount = Satoshis(Int64(10000)) + + //this is the utxo we are going to be spending + val utxo = + TransactionOutput(currencyUnit = amount, scriptPubKey = creditingSpk) + + //the private key that locks the funds for the script we are spending too + val destinationPrivKey = ECPrivateKey.freshPrivateKey + + //the amount we are sending -- 5000 satoshis -- to the destinationSPK + val destinationAmount = Satoshis(Int64(5000)) + + //the script that corresponds to destination private key, this is what is protecting the money + val destinationSPK = + P2PKHScriptPubKey(pubKey = destinationPrivKey.publicKey) + + //this is where we are sending money too + //we could add more destinations here if we + //wanted to batch transactions + val destinations = { + val destination1 = TransactionOutput(currencyUnit = destinationAmount, + scriptPubKey = destinationSPK) + + List(destination1) + } + + //we have to fabricate a transaction that contains the + //utxo we are trying to spend. If this were a real blockchain + //we would need to reference the utxo set + val creditingTx = BaseTransaction(version = Int32.one, + inputs = List.empty, + outputs = List(utxo), + lockTime = UInt32.zero) + + //this is the information we need from the crediting tx + //to properly "link" it in the transaction we are creating + val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) + + // this contains all the information we need to + // validly sign the utxo above + val utxoSpendingInfo = BitcoinUTXOSpendingInfo(outPoint = outPoint, + output = utxo, + signers = List(privKey), + redeemScriptOpt = None, + scriptWitnessOpt = None, + hashType = + HashType.sigHashAll) + + //all of the utxo spending information, since we are only + //spending one utxo, this is just one element + val utxos: List[BitcoinUTXOSpendingInfo] = List(utxoSpendingInfo) + + //this is how much we are going to pay as a fee to the network + //for this example, we are going to pay 1 satoshi per byte + val feeRate = SatoshisPerByte(Satoshis.one) + + val changePrivKey = ECPrivateKey.freshPrivateKey + val changeSPK = P2PKHScriptPubKey(pubKey = changePrivKey.publicKey) + + // the network we are on, for this example we are using + // the regression test network. This is a network you control + // on your own machine + val networkParams = RegTest + + //yay! Now we have a TxBuilder object that we can use + //to sign the tx. + val txBuilder: Future[BitcoinTxBuilder] = { + BitcoinTxBuilder( + destinations = destinations, + utxos = utxos, + feeRate = feeRate, + changeSPK = changeSPK, + network = networkParams + ) + } + + txBuilder.failed.foreach { case err => println(err.getMessage) } + + //let's finally produce a validly signed tx + //The 'sign' method is going produce a validly signed transaction + //This is going to iterate through each of the 'utxos' and use + //the corresponding 'UTXOSpendingInfo' to produce a validly + //signed input. This tx has a + // + //1 input + //2 outputs (destination and change outputs) + //3 a fee rate of 1 satoshi/byte + val signedTxF: Future[Transaction] = txBuilder.flatMap(_.sign) + + //let's print these things out so you can example them + signedTxF.map { tx => + println("\nInputs:") + tx.inputs.foreach(println) + + println("\nOutputs:") + tx.outputs.foreach(println) + + //here is the fully signed serialized tx that + //you COULD broadcast to a cryptocurrency p2p network + println(s"\nFully signed tx in hex:") + + println(s"${tx.hex}") + } + + //The output from the print statements should read something like this + + //Inputs: + //TransactionInputImpl(TransactionOutPointImpl(DoubleSha256DigestImpl(43c75d1d59e6f13f2ad3baf6e124685ba0919bccdbdf89c362fe2f30fee4bdfc),UInt32Impl(0)),P2PKHScriptSignature(6a4730440220573a7bbbd59192c4bf01b8f1dcafe981d11ab8528fead9d66d702c1b72e5dc76022007946a423073c949e85a4ca3901ab10a2d6b72873a347d2a55ef873016adae8601210356d581971934349333066ed933cdea45ae9c72829ce34d8dd6a758d56967e4cb),UInt32Impl(0)) + // + //Outputs: + //TransactionOutputImpl(SatoshisImpl(Int64Impl(5000)),P2PKHScriptPubKeyImpl(1976a914dbdadae42124c46a00d81181e5d9ab28fbf546ed88ac)) + //TransactionOutputImpl(SatoshisImpl(Int64Impl(4774)),P2PKHScriptPubKeyImpl(1976a914a95eb0d284593f0c8f818f64a55fa6e3852012a688ac)) + // + //Fully signed tx in hex: + //020000000143c75d1d59e6f13f2ad3baf6e124685ba0919bccdbdf89c362fe2f30fee4bdfc000000006a4730440220573a7bbbd59192c4bf01b8f1dcafe981d11ab8528fead9d66d702c1b72e5dc76022007946a423073c949e85a4ca3901ab10a2d6b72873a347d2a55ef873016adae8601210356d581971934349333066ed933cdea45ae9c72829ce34d8dd6a758d56967e4cb000000000288130000000000001976a914dbdadae42124c46a00d81181e5d9ab28fbf546ed88aca6120000000000001976a914a95eb0d284593f0c8f818f64a55fa6e3852012a688ac00000000 + + //remember, you can call .hex on any bitcoin-s data structure to get the hex representation! + } + +} diff --git a/eclair-rpc/README.md b/eclair-rpc/README.md index 289b8e3033..bf00e14c28 100644 --- a/eclair-rpc/README.md +++ b/eclair-rpc/README.md @@ -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. diff --git a/project/Deps.scala b/project/Deps.scala index 27f2280d9c..9fcd24484b 100644 --- a/project/Deps.scala +++ b/project/Deps.scala @@ -117,4 +117,9 @@ object Deps { Compile.slf4j, "org.scalacheck" %% "scalacheck" % V.scalacheck withSources() withJavadoc() ) + + val doc = List( + Test.scalaTest, + Test.logback + ) } diff --git a/rpc/README.md b/rpc/README.md new file mode 100644 index 0000000000..f846ae45e7 --- /dev/null +++ b/rpc/README.md @@ -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) diff --git a/secp256k1jni/README.md b/secp256k1jni/README.md new file mode 100644 index 0000000000..31329624e4 --- /dev/null +++ b/secp256k1jni/README.md @@ -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 + +``` + + org.bitcoins + bitcoin-s-secp256k1jni + 0.0.1 + +``` + +## 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 diff --git a/testkit/README.md b/testkit/README.md new file mode 100644 index 0000000000..1fc56a89e0 --- /dev/null +++ b/testkit/README.md @@ -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)