2016-05-07 18:29:38 +02:00
[![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)
2016-04-30 18:22:39 +02:00
# Bitcoin-S-Core
2016-04-30 03:39:31 +02:00
This is the core functionality of bitcoin-s.
This repostitory includes the following functionality:
2016-04-30 03:40:01 +02:00
- Native Scala objects for various protocol types (Transaction, TransactionInput, ScriptSignatures...)
2016-04-30 03:39:31 +02:00
- Serializers and deserializers for bitcoin data structures mentioned above
- An implementation of Bitcoin's Script programming language
2016-05-25 14:53:33 +02:00
- 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 )
2016-05-07 20:17:07 +02:00
- Currently up to date through OP_CHECKSEQUENCEVERIFY
2016-04-30 03:39:31 +02:00
- 90% test coverage throughout the codebase to ensure high quality code.
- Functions documented with Scaladocs for user friendliness
2016-04-30 18:22:39 +02:00
2016-05-25 14:53:33 +02:00
# Design Principles
- Immutable data structures everywhere
- Using Algebraic Data Types to allow the compiler to check for exhaustiveness on match statements
- Favoring readability over terseness
2016-06-06 14:33:04 +02:00
# TODO
- Segwit support
2016-07-27 18:41:08 +02:00
- Java support
- Android support
2016-06-06 14:33:04 +02:00
2016-04-30 18:22:39 +02:00
# Examples
Here is an example scala console session with bitcoin-core-s
```scala
chris@chris:~/dev/bitcoins-core-chris$ sbt console
2016-05-21 15:23:12 +02:00
scala> import org.bitcoins.core.protocol.transaction._
2016-04-30 18:22:39 +02:00
import org.bitcoins.protocol.transaction._
2016-05-21 15:23:12 +02:00
scala> import org.bitcoins.core.protocol.script._
2016-04-30 18:22:39 +02:00
import org.bitcoins.protocol.script._
scala> val simpleRawTransaction = "0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000"
simpleRawTransaction: String = 0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000
scala> val tx = Transaction(simpleRawTransaction)
2016-05-21 15:23:12 +02:00
tx: 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(89994000 ...
2016-04-30 18:22:39 +02:00
```
2016-05-02 16:15:34 +02:00
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.
2016-05-02 02:24:16 +02:00
2016-05-02 16:15:34 +02:00
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:
2016-05-02 02:24:16 +02:00
- The transaction that is being checked
2016-05-04 14:53:43 +02:00
- The specific input index that it is checking
2016-05-02 02:24:16 +02:00
- The scriptPubKey for the crediting transaction
- The flags used to verify the script
2016-05-02 16:15:34 +02:00
Here is an example of a transaction spending a scriptPubKey which is correctly evaluated with our interpreter implementation:
2016-05-02 15:44:47 +02:00
```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.
2016-05-21 15:23:12 +02:00
scala> import org.bitcoins.core.protocol.script._
import org.bitcoins.core.protocol.script._
2016-05-02 15:44:47 +02:00
2016-05-21 15:23:12 +02:00
scala> import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.protocol.transaction._
2016-05-02 15:44:47 +02:00
2016-05-21 15:23:12 +02:00
scala> import org.bitcoins.core.script._
import org.bitcoins.core.script._
2016-05-02 15:44:47 +02:00
2016-05-21 15:23:12 +02:00
scala> import org.bitcoins.core.script.interpreter._
import org.bitcoins.core.script.interpreter._
2016-05-02 15:44:47 +02:00
2016-05-21 15:23:12 +02:00
scala> import org.bitcoins.core.policy._
import org.bitcoins.core.policy._
2016-05-02 15:44:47 +02:00
scala> val spendingTx = Transaction("0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000")
2016-05-21 15:23:12 +02:00
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...
2016-05-02 15:44:47 +02:00
scala> val scriptPubKey = ScriptPubKey("76a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac")
2016-05-21 15:23:12 +02:00
scriptPubKey: org.bitcoins.core.protocol.script.ScriptPubKey = P2PKHScriptPubKeyImpl(76a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac,List(OP_DUP, OP_HASH160, BytesToPushOntoStackImpl(20), ScriptConstantImpl(31a420903c05a0a7de2de40c9f02ebedbacdc172), OP_EQUALVERIFY, OP_CHECKSIG))
2016-05-02 15:44:47 +02:00
scala> val inputIndex = 0
inputIndex: Int = 0
scala> val program = ScriptProgram(spendingTx,scriptPubKey,inputIndex, Policy.standardScriptVerifyFlags)
2016-05-21 15:23:12 +02:00
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...
2016-05-02 15:44:47 +02:00
scala> ScriptInterpreter.run(program)
2016-05-21 15:23:12 +02:00
res0: org.bitcoins.core.script.result.ScriptResult = ScriptOk
2016-05-02 15:44:47 +02:00
```
2016-05-07 20:17:07 +02:00
# Running tests
To run the entire test suite all you need to do is run the following command
```scala
chris@chris:~/dev/bitcoins-core$ sbt test
[info] Run completed in 8 seconds, 805 milliseconds.
[info] Total number of tests run: 613
[info] Suites: completed 91, aborted 0
[info] Tests: succeeded 613, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 17 s, completed May 7, 2016 1:11:34 PM
chris@chris:~/dev/bitcoins-core$
```
To run a specific suite of tests you can specify the suite name in the following way
```scala
chris@chris:~/dev/bitcoins-core$ sbt
> test-only *ScriptInterpreterTest*
[info] ScriptInterpreterTest:
[info] ScriptInterpreter
[info] - must evaluate all the scripts from the bitcoin core script_tests.json
[info] Run completed in 8 seconds, 208 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
>
```