Contributing
Bitcoin-S is an open source project where anyone is welcome to contribute. All contributions are encouraged and appreciated, whether that is code, testing, documentation or something else entirely.
Communication Channels
It's possible to communicate with other developers through a variety of communication channels:
- Suredbits Slack - Suredbits is a company monetizing APIs through the Lightning Network. Suredbits doesn't own Bitcoin-S, but the Suredbits CEO Chris Stewart is the maintainer of this library. There's a separate Bitcoin-S channel on their Slack, this is probably the easiest way of getting in touch with someone working on this project.
- Bitcoin-S Gitter
- #bitcoin-scala on IRC Freenode
Developer productivity
Bloop
If you're tired of waiting around for sbt all day, there's a new, cool kid on the block. It is called Bloop, and it makes compilations in general faster, and in particular incremental, small compilation units (which greatly help editor performance). Bloop is a server that runs in the background of your computer, and keeps several "hot" JVMs running at all times. These JVMs serve compilation requests. Because the JVMs are running in the background you avoid the startup lag, and you also get code that's already JIT compiled for you.
The documentation on Bloops site is good, but here is the highlights:
Install Bloop by doing step 1 & 2 in the official guide
Enable the Bloop background daemon
- macOS:
$ brew services start bloop
- Ubuntu:
$ systemctl --user enable $HOME/.bloop/systemd/bloop.service $ systemctl --user daemon-reload $ systemctl --user start bloop
Enable shell completion for the Bloop CLI
- Bash:
$ echo '. $HOME/.bloop/bash/bloop' >> $HOME/.bash_profile
- Zsh:
$ echo 'autoload -U compinit' >> $HOME/.zshrc $ echo 'fpath=($HOME/.bloop/zsh $fpath)' >> $HOME/.bashrc $ echo 'compinit' >> $HOME/.bashrc
- Fish:
$ ln -s $HOME/.bloop/fish/bloop.fish ~/.config/fish/completions/bloop.fish
Generate configuration files
$ sbt bloopInstall
Import Bitcoin-S into IntelliJ again, as a bsp (Build Server Protocol) project (instead of a sbt project). Make sure you're running on the most recent IntelliJ and Scala plugin. See official docs for details.
(Bonus step): Lightning fast recompilations on file save:
$ bloop compile --project <name of module your're working on> --watch
Your editor should now be much faster and require less resources :tada:
Testing
Property based testing
This library aims to achieve high level of correctness via property based testing. At the simplest level, you can think of property based testing as specifying a invariant that must always hold true. Here is an example of a property in the bitcoin-s-core test suite
property("Serialization symmetry") =
Prop.forAll(TransactionGenerators.transactions) { tx =>
Transaction(tx.hex) == tx
}
What this property says is that for every transaction we can generate with
TransactionGenerators.transactions
we must be able to serialize it to hex format, then deserialize it back
to a transaction and get the original tx
back.
A more complex example of property based testing is checking that a
multisignature transaction was signed correctly (see
TransactionSignatureCreatorSpec
line 29-34). First we generate a supposedly validly signed multisig
transaction with TransactionGenerators.signedMultiSigTransaction
(line 102-108). These transactions have varying m
of n
requirements.
An interesting corner case if when you have 0 of n
signatures, which
means no signature is required. Property based testing is really good at
fleshing out these corner cases. We check to see if this transaction is
valid by running it through our ScriptInterpreter
.
If we have built our functionality correctly the ScriptInterpreter
should
always return ScriptOk
indicating the script was valid.
property("generate valid signatures for a multisignature transaction") =
Prop.forAllNoShrink(TransactionGenerators.signedMultiSigTransaction) {
case (txSignatureComponent: TxSigComponent, _) =>
//run it through the interpreter
val program = ScriptProgram(txSignatureComponent)
val result = ScriptInterpreter.run(program)
result == ScriptOk
}
Running tests
To run the entire test suite all you need to do is run the following command:
This takes a long time, and runs a lot of tests that require IO. It may hog your computer at times.
$ sbt test
[info] Elapsed time: 4 min 36.760 sec
[info] ScalaCheck
[info] Passed: Total 149, Failed 0, Errors 0, Passed 149
[info] ScalaTest
[info] Run completed in 4 minutes, 55 seconds.
[info] Total number of tests run: 744
[info] Suites: completed 97, aborted 0
[info] Tests: succeeded 744, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[info] Passed: Total 909, Failed 0, Errors 0, Passed 909
[success] Total time: 297 s, completed Jul 20, 2017 10:34:16 AM
To run a specific suite of tests you can specify the suite name in the following way
$ sbt testOnly *ScriptInterpreterTest*
[info] ScriptInterpreterTest:
[info] ScriptInterpreter
[info] - must evaluate all the scripts from the bitcoin core script_tests.json
[info] Run completed in 8 seconds, 208 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
The command sbt testQuick
can also be handy. It runs tests that either:
- Failed previously
- Has not been run previously
- Either the test or one of its dependencies has been recompiled
For more information on testQuick
, see the offical
sbt docs.