Regtest testing

- Removed config option for build scripts, replaced with env variable
- Updated README
- Added regtest option under test build, wallet built-in
- added network key to bindings
- datadir for the bitcoind object instead of directory
- added new config_options scripts for test and debug
This commit is contained in:
Chris Kleeschulte 2015-07-20 17:55:49 -04:00 committed by Braydon Fuller
parent cda1e2a438
commit cf6225c495
9 changed files with 81 additions and 24 deletions

View File

@ -21,7 +21,7 @@ var BitcoinNode = require('bitcoind.js');
var configuration = { var configuration = {
datadir: '~/.bitcoin', datadir: '~/.bitcoin',
testnet: true network: 'testnet'
}; };
var node = new BitcoinNode(configuration); var node = new BitcoinNode(configuration);
@ -110,7 +110,7 @@ $ tail -f ~/.bitcoin/debug.log
## Building ## Building
There are two main parts of the build, compiling Bitcoin Core and the Node.js bindings. You can run both by using `npm install` and `npm run debug_install`. There are two main parts of the build, compiling Bitcoin Core and the Node.js bindings. You can run both by using `npm install` and set environment variable, $BITCOINDJS_ENV to 'test' or 'debug'. Both 'test' and 'debug' build libbitcoind with debug symbols whereas 'test' adds wallet capability so that regtest can be used.
### Node.js Bindings ### Node.js Bindings
@ -130,6 +130,11 @@ To be able to debug you'll need to have `gdb` and `node` compiled for debugging
$ gdb --args node_g path/to/example.js $ gdb --args node_g path/to/example.js
``` ```
To run mocha from within gdb (notice _mocha and not mocha so that the tests run in the same process):
```bash
$ gdb --args node /path/to/_mocha -R spec integration/index.js
```
To run integration tests against testnet or livenet data: To run integration tests against testnet or livenet data:
```bash ```bash
@ -161,7 +166,7 @@ Most of all the dependencies for building Bitcoin Core are needed, for more info
#### Shared Library Patch #### Shared Library Patch
To provide native bindings to JavaScript *(or any other language for that matter)*, Bitcoin code, itself, must be linkable. Currently, Bitcoin Core provides a JSON RPC interface to bitcoind as well as a shared library for script validation *(and hopefully more)* called libbitcoinconsensus. There is a node module, [node-libbitcoinconsensus](https://github.com/bitpay/node-libbitcoinconsensus), that exposes these methods. While these interfaces are useful for several use cases, there are additional use cases that are not fulfilled, and being able to implement customized interfaces is necessary. To be able to do this a few simple changes need to be made to Bitcoin Core to compile as a shared library. To provide native bindings to JavaScript *(or any other language for that matter)*, Bitcoin code, itself, must be linkable. Currently, Bitcoin Core provides a JSON RPC interface to bitcoind as well as a shared library for script validation *(and hopefully more)* called libbitcoinconsensus. There is a node module, [node-libbitcoinconsensus](https://github.com/bitpay/node-libbitcoinconsensus), that exposes these methods. While these interfaces are useful for several use cases, there are additional use cases that are not fulfilled, and being able to implement customized interfaces is necessary. To be able to do this a few simple changes need to be made to Bitcoin Core to compile as a shared library.
The patch is located at `etc/bitcoin.patch` and adds a configure option `--enable-daemonlib` to compile all object files with `-fPIC` (Position Independent Code - needed to create a shared object), exposes leveldb variables and objects, exposes the threadpool to the bindings, and conditionally includes the main function. The patch is located at `etc/bitcoin.patch` and adds a configure option `--enable-daemonlib` to compile all object files with `-fPIC` (Position Independent Code - needed to create a shared object), exposes leveldb variables and objects, exposes the threadpool to the bindings, and conditionally includes the main function.
@ -176,7 +181,7 @@ $ cd /path/to/bitcoind.js
$ ./bin/build-libbitcoind $ ./bin/build-libbitcoind
``` ```
The first argument is 'debug', this will compile node bindings and bitcoind with debug flags. The `PATCH_VERSION` file dictates what version/tag the patch goes clean against. The `PATCH_VERSION` file dictates what version/tag the patch goes clean against.
There is a config_options.sh that has the configure options used to build libbitcoind. `make` will then compile `libbitcoind/src/.libs/libbitcoind.{so|dylib}`. This will completely ignore compiling tests, QT object files and the wallet features in `bitcoind/libbitcoind.{so|dylib}`. There is a config_options.sh that has the configure options used to build libbitcoind. `make` will then compile `libbitcoind/src/.libs/libbitcoind.{so|dylib}`. This will completely ignore compiling tests, QT object files and the wallet features in `bitcoind/libbitcoind.{so|dylib}`.

View File

@ -28,7 +28,7 @@ var fixtureData = {
var bitcoind = require('../').daemon({ var bitcoind = require('../').daemon({
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin', datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin',
testnet: true network: 'testnet'
}); });
bitcoind.on('error', function(err) { bitcoind.on('error', function(err) {

View File

@ -3,6 +3,7 @@ set -e
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.." root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.."
cd "${root_dir}" cd "${root_dir}"
options=`cat ${root_dir}/bin/config_options.sh`
os_dir=$(./platform/os.sh osdir) os_dir=$(./platform/os.sh osdir)
@ -10,8 +11,13 @@ os_dir=$(./platform/os.sh osdir)
export LD_LIBRARY_PATH="${root_dir}/libbitcoind/src/leveldb":"${os_dir}":$LD_LIBRARY_PATH export LD_LIBRARY_PATH="${root_dir}/libbitcoind/src/leveldb":"${os_dir}":$LD_LIBRARY_PATH
debug= debug=
if test x"$1" = x'debug'; then if [ "${BITCOINDJS_ENV}" == "debug" ]; then
debug=--enable-debug options=`cat ${root_dir}/bin/config_options_debug.sh`
fi
test=
if [ "${BITCOINDJS_ENV}" == "test" ]; then
options=`cat ${root_dir}/bin/config_options_test.sh`
fi fi
btc_dir="${root_dir}/libbitcoind" btc_dir="${root_dir}/libbitcoind"
@ -50,12 +56,11 @@ if [ "${only_make}" = false ]; then
echo './autogen.sh' echo './autogen.sh'
./autogen.sh ./autogen.sh
options=`cat ${root_dir}/bin/config_options.sh`
full_options="${options}${os_dir} ${debug}"
echo "running the configure script with the following options:\n :::[\"${full_options}\"]:::"
${full_options}
fi fi
full_options="${options}${os_dir}"
echo "running the configure script with the following options:\n :::[\"${full_options}\"]:::"
${full_options}
echo 'make V=1' echo 'make V=1'
make V=1 make V=1

View File

@ -0,0 +1,2 @@
./configure --enable_debug --enable-tests=no --enable-daemonlib --with-gui=no --without-qt --without-miniupnpc --without-bdb --disable-wallet --without-utils --prefix=

View File

@ -0,0 +1,2 @@
./configure --enable-tests=no --enable-daemonlib --with-gui=no --without-qt --without-miniupnpc --prefix=

15
example/daemon.js Normal file
View File

@ -0,0 +1,15 @@
'use strict';
process.title = 'bitcoind.js';
var daemon = require('../').daemon({
directory: process.env.BITCOINDJS_DIR || '~/.bitcoin'
});
daemon.on('error', function(err) {
daemon.log('error="%s"', err.message);
});
daemon.on('open', function(status) {
daemon.log('status="%s"', status);
});

View File

@ -37,14 +37,6 @@ function Daemon(options) {
this.options = options || {}; this.options = options || {};
if (typeof this.options === 'string') {
this.options = { datadir: this.options };
}
if (this.options.directory) {
this.options.datadir = this.options.directory;
delete this.options.directory;
}
if (!this.options.datadir) { if (!this.options.datadir) {
this.options.datadir = '~/.bitcoind.js'; this.options.datadir = '~/.bitcoind.js';
@ -54,7 +46,13 @@ function Daemon(options) {
this.datadir = this.options.datadir; this.datadir = this.options.datadir;
this.config = this.datadir + '/bitcoin.conf'; this.config = this.datadir + '/bitcoin.conf';
this.network = Daemon[this.options.testnet ? 'testnet' : 'livenet']; this.network = Daemon['livenet'];
if (this.options.network === 'testnet') {
this.network = Daemon['testnet'];
} else if(this.options.network === 'regtest') {
this.network = Daemon['regtest'];
}
if (!fs.existsSync(this.datadir)) { if (!fs.existsSync(this.datadir)) {
mkdirp.sync(this.datadir); mkdirp.sync(this.datadir);
@ -83,7 +81,6 @@ function Daemon(options) {
fs.writeFileSync(data + peers); fs.writeFileSync(data + peers);
} }
// Copy config into testnet dir
if (this.network.name === 'testnet') { if (this.network.name === 'testnet') {
if (!fs.existsSync(this.datadir + '/testnet3')) { if (!fs.existsSync(this.datadir + '/testnet3')) {
fs.mkdirSync(this.datadir + '/testnet3'); fs.mkdirSync(this.datadir + '/testnet3');
@ -93,6 +90,15 @@ function Daemon(options) {
fs.readFileSync(this.config)); fs.readFileSync(this.config));
} }
if (this.network.name === 'regtest') {
if (!fs.existsSync(this.datadir + '/regtest')) {
fs.mkdirSync(this.datadir + '/regtest');
}
fs.writeFileSync(
this.datadir + '/regtest/bitcoin.conf',
fs.readFileSync(this.config));
}
Object.keys(exports).forEach(function(key) { Object.keys(exports).forEach(function(key) {
self[key] = exports[key]; self[key] = exports[key];
}); });
@ -120,6 +126,13 @@ Daemon.testnet = {
] ]
}; };
Bitcoin.regtest = {
name: 'regtest',
peers: [
// hardcoded peers
]
};
// Make sure signal handlers are not overwritten // Make sure signal handlers are not overwritten
Daemon._signalQueue = []; Daemon._signalQueue = [];
Daemon._processOn = process.on; Daemon._processOn = process.on;

View File

@ -30,7 +30,6 @@
"preinstall": "./bin/build-libbitcoind", "preinstall": "./bin/build-libbitcoind",
"install": "./bin/build-bindings", "install": "./bin/build-bindings",
"start": "node example", "start": "node example",
"debug_install": "./bin/build-libbitcoind debug && ./bin/build-bindings debug",
"test": "NODE_ENV=test mocha --recursive", "test": "NODE_ENV=test mocha --recursive",
"coverage": "istanbul cover _mocha -- --recursive" "coverage": "istanbul cover _mocha -- --recursive"
}, },

View File

@ -76,6 +76,7 @@ static volatile bool shutdown_complete = false;
static char *g_data_dir = NULL; static char *g_data_dir = NULL;
static bool g_rpc = false; static bool g_rpc = false;
static bool g_testnet = false; static bool g_testnet = false;
static bool g_regtest = false;
static bool g_txindex = false; static bool g_txindex = false;
/** /**
@ -105,6 +106,7 @@ struct async_node_data {
std::string datadir; std::string datadir;
bool rpc; bool rpc;
bool testnet; bool testnet;
bool regtest;
bool txindex; bool txindex;
Eternal<Function> callback; Eternal<Function> callback;
}; };
@ -298,6 +300,7 @@ NAN_METHOD(StartBitcoind) {
std::string datadir = std::string(""); std::string datadir = std::string("");
bool rpc = false; bool rpc = false;
bool testnet = false; bool testnet = false;
bool regtest = false;
bool txindex = false; bool txindex = false;
if (args.Length() >= 2 && args[0]->IsObject() && args[1]->IsFunction()) { if (args.Length() >= 2 && args[0]->IsObject() && args[1]->IsFunction()) {
@ -309,8 +312,14 @@ NAN_METHOD(StartBitcoind) {
if (options->Get(NanNew<String>("rpc"))->IsBoolean()) { if (options->Get(NanNew<String>("rpc"))->IsBoolean()) {
rpc = options->Get(NanNew<String>("rpc"))->ToBoolean()->IsTrue(); rpc = options->Get(NanNew<String>("rpc"))->ToBoolean()->IsTrue();
} }
if (options->Get(NanNew<String>("testnet"))->IsBoolean()) { if (options->Get(NanNew<String>("network"))->IsString()) {
testnet = options->Get(NanNew<String>("testnet"))->ToBoolean()->IsTrue(); String::Utf8Value network_(options->Get(NanNew<String>("network"))->ToString());
std::string network = std::string(*network_);
if (network == "testnet") {
testnet = true;
} else if (network == "regtest") {
regtest = true;
}
} }
if (options->Get(NanNew<String>("txindex"))->IsBoolean()) { if (options->Get(NanNew<String>("txindex"))->IsBoolean()) {
txindex = options->Get(NanNew<String>("txindex"))->ToBoolean()->IsTrue(); txindex = options->Get(NanNew<String>("txindex"))->ToBoolean()->IsTrue();
@ -337,6 +346,7 @@ NAN_METHOD(StartBitcoind) {
data->datadir = datadir; data->datadir = datadir;
data->rpc = rpc; data->rpc = rpc;
data->testnet = testnet; data->testnet = testnet;
data->regtest = regtest;
data->txindex = txindex; data->txindex = txindex;
Eternal<Function> eternal(isolate, callback); Eternal<Function> eternal(isolate, callback);
@ -370,6 +380,7 @@ async_start_node(uv_work_t *req) {
} }
g_rpc = (bool)data->rpc; g_rpc = (bool)data->rpc;
g_testnet = (bool)data->testnet; g_testnet = (bool)data->testnet;
g_regtest = (bool)data->regtest;
g_txindex = (bool)data->txindex; g_txindex = (bool)data->txindex;
tcgetattr(STDIN_FILENO, &orig_termios); tcgetattr(STDIN_FILENO, &orig_termios);
start_node(); start_node();
@ -475,6 +486,11 @@ start_node_thread(void) {
argc++; argc++;
} }
if (g_regtest) {
argv[argc] = (char *)"-regtest";
argc++;
}
argv[argc] = (char *)"-txindex"; argv[argc] = (char *)"-txindex";
argc++; argc++;