Merge pull request #44 from braydonf/regtest
Add "regtest" testing capabilities
This commit is contained in:
commit
6cc6d7f4de
|
@ -1,7 +1,15 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
|
env:
|
||||||
|
- BITCOINDJS_ENV=test
|
||||||
node_js:
|
node_js:
|
||||||
- "0.12"
|
- "0.12"
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get install libboost1.48-all-dev
|
- sudo apt-get install libboost1.48-all-dev
|
||||||
|
- sudo add-apt-repository -y ppa:bitcoin/bitcoin
|
||||||
|
- sudo apt-get update
|
||||||
|
- sudo apt-get install libdb4.8-dev libdb4.8++-dev
|
||||||
- git config --global user.email "dev@bitpay.com"
|
- git config --global user.email "dev@bitpay.com"
|
||||||
- git config --global user.name "BitPay, Inc."
|
- git config --global user.name "BitPay, Inc."
|
||||||
|
script:
|
||||||
|
- _mocha -R spec integration/regtest.js
|
||||||
|
- _mocha -R spec --recursive
|
||||||
|
|
11
README.md
11
README.md
|
@ -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
|
||||||
|
@ -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}`.
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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=
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
./configure --enable-debug --enable-tests=no --enable-daemonlib --with-gui=no --without-qt --without-miniupnpc --prefix=
|
||||||
|
|
|
@ -1,18 +1,8 @@
|
||||||
From 05084f2a640b862132588b322461ec8e13058fc3 Mon Sep 17 00:00:00 2001
|
commit 29c1ca452ba6178d6b17be0a0b5a65567ba846af
|
||||||
From: Chris Kleeschulte <chrisk@bitpay.com>
|
Author: Chris Kleeschulte <chrisk@bitpay.com>
|
||||||
Date: Mon, 13 Jul 2015 12:49:30 -0400
|
Date: Mon Jul 13 16:35:37 2015 -0400
|
||||||
Subject: [PATCH] libbitcoind
|
|
||||||
|
|
||||||
---
|
allow compiling of libbitcoind.so.
|
||||||
config_me.sh | 1 +
|
|
||||||
configure.ac | 37 ++++++++++++++++++++++++++++++++-----
|
|
||||||
src/Makefile.am | 42 ++++++++++++++++++++++++++++++++++--------
|
|
||||||
src/bitcoind.cpp | 6 ++++++
|
|
||||||
src/init.h | 5 +++++
|
|
||||||
src/leveldb/Makefile | 6 +++++-
|
|
||||||
src/leveldbwrapper.h | 12 ++++++++++++
|
|
||||||
7 files changed, 95 insertions(+), 14 deletions(-)
|
|
||||||
create mode 100644 config_me.sh
|
|
||||||
|
|
||||||
diff --git a/config_me.sh b/config_me.sh
|
diff --git a/config_me.sh b/config_me.sh
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
|
@ -22,7 +12,7 @@ index 0000000..19e9a1b
|
||||||
@@ -0,0 +1 @@
|
@@ -0,0 +1 @@
|
||||||
+./configure --enable-tests=no --enable-daemonlib --with-gui=no --without-qt --without-miniupnpc --without-bdb --enable-debug --disable-wallet --without-utils
|
+./configure --enable-tests=no --enable-daemonlib --with-gui=no --without-qt --without-miniupnpc --without-bdb --enable-debug --disable-wallet --without-utils
|
||||||
diff --git a/configure.ac b/configure.ac
|
diff --git a/configure.ac b/configure.ac
|
||||||
index 37fe47e..27a9b9a 100644
|
index 37fe47e..83cfe70 100644
|
||||||
--- a/configure.ac
|
--- a/configure.ac
|
||||||
+++ b/configure.ac
|
+++ b/configure.ac
|
||||||
@@ -119,6 +119,12 @@ AC_ARG_ENABLE([reduce-exports],
|
@@ -119,6 +119,12 @@ AC_ARG_ENABLE([reduce-exports],
|
||||||
|
@ -96,18 +86,19 @@ index 37fe47e..27a9b9a 100644
|
||||||
LIBLEVELDB=
|
LIBLEVELDB=
|
||||||
LIBMEMENV=
|
LIBMEMENV=
|
||||||
diff --git a/src/Makefile.am b/src/Makefile.am
|
diff --git a/src/Makefile.am b/src/Makefile.am
|
||||||
index 1c2f770..632f608 100644
|
index 1c2f770..ddcae0f 100644
|
||||||
--- a/src/Makefile.am
|
--- a/src/Makefile.am
|
||||||
+++ b/src/Makefile.am
|
+++ b/src/Makefile.am
|
||||||
@@ -1,6 +1,7 @@
|
@@ -1,6 +1,8 @@
|
||||||
DIST_SUBDIRS = secp256k1
|
DIST_SUBDIRS = secp256k1
|
||||||
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS)
|
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS)
|
||||||
|
|
||||||
+lib_LTLIBRARIES =
|
+lib_LTLIBRARIES =
|
||||||
|
+libbitcoind_la_LIBADD =
|
||||||
|
|
||||||
if EMBEDDED_LEVELDB
|
if EMBEDDED_LEVELDB
|
||||||
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include
|
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include
|
||||||
@@ -15,6 +16,10 @@ $(LIBLEVELDB) $(LIBMEMENV):
|
@@ -15,6 +17,10 @@ $(LIBLEVELDB) $(LIBMEMENV):
|
||||||
@echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \
|
@echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \
|
||||||
CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \
|
CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \
|
||||||
OPT="$(CXXFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS"
|
OPT="$(CXXFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS"
|
||||||
|
@ -118,7 +109,7 @@ index 1c2f770..632f608 100644
|
||||||
endif
|
endif
|
||||||
|
|
||||||
BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
|
BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
|
||||||
@@ -49,16 +54,16 @@ BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
|
@@ -49,16 +55,16 @@ BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
|
||||||
EXTRA_LIBRARIES += libbitcoin_wallet.a
|
EXTRA_LIBRARIES += libbitcoin_wallet.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -142,7 +133,7 @@ index 1c2f770..632f608 100644
|
||||||
if BUILD_BITCOIND
|
if BUILD_BITCOIND
|
||||||
bin_PROGRAMS += bitcoind
|
bin_PROGRAMS += bitcoind
|
||||||
endif
|
endif
|
||||||
@@ -66,6 +71,9 @@ endif
|
@@ -66,6 +72,9 @@ endif
|
||||||
if BUILD_BITCOIN_UTILS
|
if BUILD_BITCOIN_UTILS
|
||||||
bin_PROGRAMS += bitcoin-cli bitcoin-tx
|
bin_PROGRAMS += bitcoin-cli bitcoin-tx
|
||||||
endif
|
endif
|
||||||
|
@ -152,7 +143,7 @@ index 1c2f770..632f608 100644
|
||||||
|
|
||||||
.PHONY: FORCE
|
.PHONY: FORCE
|
||||||
# bitcoin core #
|
# bitcoin core #
|
||||||
@@ -169,8 +177,9 @@ obj/build.h: FORCE
|
@@ -169,8 +178,9 @@ obj/build.h: FORCE
|
||||||
@$(MKDIR_P) $(builddir)/obj
|
@$(MKDIR_P) $(builddir)/obj
|
||||||
@$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \
|
@$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \
|
||||||
$(abs_top_srcdir)
|
$(abs_top_srcdir)
|
||||||
|
@ -163,7 +154,7 @@ index 1c2f770..632f608 100644
|
||||||
# server: shared between bitcoind and bitcoin-qt
|
# server: shared between bitcoind and bitcoin-qt
|
||||||
libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS)
|
libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS)
|
||||||
libbitcoin_server_a_SOURCES = \
|
libbitcoin_server_a_SOURCES = \
|
||||||
@@ -309,9 +318,18 @@ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
|
@@ -309,9 +319,18 @@ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h
|
||||||
bitcoind_SOURCES = bitcoind.cpp
|
bitcoind_SOURCES = bitcoind.cpp
|
||||||
bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES)
|
bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES)
|
||||||
bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||||
|
@ -182,8 +173,12 @@ index 1c2f770..632f608 100644
|
||||||
endif
|
endif
|
||||||
|
|
||||||
bitcoind_LDADD = \
|
bitcoind_LDADD = \
|
||||||
@@ -328,7 +346,15 @@ if ENABLE_WALLET
|
@@ -326,9 +345,19 @@ bitcoind_LDADD = \
|
||||||
|
|
||||||
|
if ENABLE_WALLET
|
||||||
bitcoind_LDADD += libbitcoin_wallet.a
|
bitcoind_LDADD += libbitcoin_wallet.a
|
||||||
|
+libbitcoind_la_LIBADD += $(BDB_LIBS)
|
||||||
|
+libbitcoind_la_SOURCES += $(libbitcoin_wallet_a_SOURCES)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
+MEMOBJ = helpers/memenv/memenv.lo
|
+MEMOBJ = helpers/memenv/memenv.lo
|
||||||
|
@ -191,7 +186,7 @@ index 1c2f770..632f608 100644
|
||||||
+ @echo "Building the Memenv shared library..." && $(MAKE) -C ./leveldb $@
|
+ @echo "Building the Memenv shared library..." && $(MAKE) -C ./leveldb $@
|
||||||
+
|
+
|
||||||
bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
|
bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
|
||||||
+libbitcoind_la_LIBADD = $(BOOST_LIBS) $(SSL_LIBS) $(LIBSECP256K1) $(CRYPTO_LIBS) leveldb/$(MEMOBJ)
|
+libbitcoind_la_LIBADD += $(BOOST_LIBS) $(SSL_LIBS) $(LIBSECP256K1) $(CRYPTO_LIBS) leveldb/$(MEMOBJ)
|
||||||
+libbitcoind_la_CPPFLAGS = $(BITCOIN_INCLUDES)
|
+libbitcoind_la_CPPFLAGS = $(BITCOIN_INCLUDES)
|
||||||
+libbitcoind_la_LDFLAGS = -lleveldb -L./leveldb $(RELDFLAGS) -no-undefined
|
+libbitcoind_la_LDFLAGS = -lleveldb -L./leveldb $(RELDFLAGS) -no-undefined
|
||||||
+libbitcoind_la_DEPENDENCIES = $(LIBSECP256K1) LIBLEVELDB_SHARED $(MEMOBJ)
|
+libbitcoind_la_DEPENDENCIES = $(LIBSECP256K1) LIBLEVELDB_SHARED $(MEMOBJ)
|
||||||
|
@ -309,6 +304,3 @@ index c65e842..0e44bb5 100644
|
||||||
CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
|
CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
|
||||||
~CLevelDBWrapper();
|
~CLevelDBWrapper();
|
||||||
|
|
||||||
--
|
|
||||||
2.3.2 (Apple Git-55)
|
|
||||||
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bitcoind.js example
|
|
||||||
*/
|
|
||||||
|
|
||||||
process.title = 'bitcoind.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* daemon
|
|
||||||
*/
|
|
||||||
|
|
||||||
var daemon = require('../index.js').daemon({
|
|
||||||
directory: process.env.BITCOINDJS_DIR || '~/.bitcoin'
|
|
||||||
});
|
|
||||||
|
|
||||||
daemon.on('error', function(err) {
|
|
||||||
daemon.log('error="%s"', err.message);
|
|
||||||
});
|
|
||||||
|
|
||||||
daemon.on('ready', function(err, result) {
|
|
||||||
console.log('Ready!');
|
|
||||||
|
|
||||||
daemon.getBlock('000000000000000082ccf8f1557c5d40b21edabb18d2d691cfbf87118bac7254', function(err, block) {
|
|
||||||
if (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
console.log('block', block);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
daemon.on('open', function(status) {
|
|
||||||
daemon.log('status="%s"', status);
|
|
||||||
});
|
|
|
@ -13,7 +13,8 @@ process.title = 'bitcoind.js';
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var daemon = require('../').daemon({
|
var daemon = require('../').daemon({
|
||||||
directory: process.env.BITCOINDJS_DIR || '~/.bitcoin'
|
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin',
|
||||||
|
network: 'regtest'
|
||||||
});
|
});
|
||||||
|
|
||||||
daemon.on('error', function(err) {
|
daemon.on('error', function(err) {
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bitcoind.js example
|
|
||||||
*/
|
|
||||||
|
|
||||||
process.title = 'bitcoind_stripped.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* daemon
|
|
||||||
*/
|
|
||||||
|
|
||||||
var daemon = require('../index_stripped.js')({
|
|
||||||
directory: '~/.libbitcoind-example'
|
|
||||||
});
|
|
||||||
|
|
||||||
daemon.on('error', function(err) {
|
|
||||||
daemon.log('error="%s"', err.message);
|
|
||||||
});
|
|
||||||
|
|
||||||
daemon.on('open', function(status) {
|
|
||||||
daemon.log('status="%s"', status);
|
|
||||||
});
|
|
|
@ -8,7 +8,7 @@ var log = chainlib.log;
|
||||||
|
|
||||||
var configuration = {
|
var configuration = {
|
||||||
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin',
|
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin',
|
||||||
testnet: true
|
network: 'testnet'
|
||||||
};
|
};
|
||||||
|
|
||||||
var node = new BitcoinNode(configuration);
|
var node = new BitcoinNode(configuration);
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
server=1
|
||||||
|
whitelist=127.0.0.1
|
||||||
|
txindex=1
|
||||||
|
rpcallowip=127.0.0.1
|
||||||
|
rpcuser=bitcoin
|
||||||
|
rpcpassword=local321
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// These tests require a fully synced Bitcore Code data directory.
|
// These tests require a fully synced Bitcore Code data directory.
|
||||||
// To run the tests: $ mocha -R spec index.js
|
// To run the tests: $ mocha -R spec livenet.js
|
||||||
|
|
||||||
var chai = require('chai');
|
var chai = require('chai');
|
||||||
var bitcore = require('bitcore');
|
var bitcore = require('bitcore');
|
||||||
|
@ -23,7 +23,7 @@ describe('Basic Functionality', function() {
|
||||||
before(function(done) {
|
before(function(done) {
|
||||||
this.timeout(30000);
|
this.timeout(30000);
|
||||||
bitcoind = require('../').daemon({
|
bitcoind = require('../').daemon({
|
||||||
directory: process.env.BITCOINDJS_DIR || '~/.bitcoin',
|
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin',
|
||||||
});
|
});
|
||||||
|
|
||||||
bitcoind.on('error', function(err) {
|
bitcoind.on('error', function(err) {
|
|
@ -0,0 +1,172 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// These tests require bitcoind.js Bitcoin Core bindings to be compiled with
|
||||||
|
// the environment variable BITCOINDJS_ENV=test. This enables the use of regtest
|
||||||
|
// functionality by including the wallet in the build.
|
||||||
|
// To run the tests: $ mocha -R spec integration/regtest.js
|
||||||
|
|
||||||
|
if (process.env.BITCOINDJS_ENV !== 'test') {
|
||||||
|
console.log('Please set the environment variable BITCOINDJS_ENV=test and make sure bindings are compiled for testing');
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
var chai = require('chai');
|
||||||
|
var bitcore = require('bitcore');
|
||||||
|
var rimraf = require('rimraf');
|
||||||
|
var bitcoind;
|
||||||
|
|
||||||
|
/* jshint unused: false */
|
||||||
|
var should = chai.should();
|
||||||
|
var assert = chai.assert;
|
||||||
|
var sinon = require('sinon');
|
||||||
|
var BitcoinRPC = require('bitcoind-rpc');
|
||||||
|
var blockHashes = [];
|
||||||
|
|
||||||
|
describe('Basic Functionality', function() {
|
||||||
|
|
||||||
|
before(function(done) {
|
||||||
|
this.timeout(30000);
|
||||||
|
|
||||||
|
var datadir = __dirname + '/data';
|
||||||
|
|
||||||
|
rimraf(datadir + '/regtest', function(err) {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitcoind = require('../').daemon({
|
||||||
|
datadir: datadir,
|
||||||
|
network: 'regtest'
|
||||||
|
});
|
||||||
|
|
||||||
|
bitcoind.on('error', function(err) {
|
||||||
|
bitcoind.log('error="%s"', err.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
bitcoind.on('open', function(status) {
|
||||||
|
bitcoind.log('status="%s"', status);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Waiting for Bitcoin Core to initialize...');
|
||||||
|
|
||||||
|
bitcoind.on('ready', function() {
|
||||||
|
|
||||||
|
var client = new BitcoinRPC({
|
||||||
|
protocol: 'http',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 18332,
|
||||||
|
user: 'bitcoin',
|
||||||
|
pass: 'local321'
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Generating 100 blocks...');
|
||||||
|
|
||||||
|
client.generate(100, function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
blockHashes = response.result;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function(done) {
|
||||||
|
this.timeout(20000);
|
||||||
|
bitcoind.stop(function(err, result) {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('mempool functionality', function() {
|
||||||
|
|
||||||
|
var fromAddress = 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1';
|
||||||
|
var utxo = {
|
||||||
|
address: fromAddress,
|
||||||
|
txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
|
||||||
|
outputIndex: 0,
|
||||||
|
script: bitcore.Script.buildPublicKeyHashOut(fromAddress).toString(),
|
||||||
|
satoshis: 100000
|
||||||
|
};
|
||||||
|
var toAddress = 'mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc';
|
||||||
|
var changeAddress = 'mgBCJAsvzgT2qNNeXsoECg2uPKrUsZ76up';
|
||||||
|
var changeAddressP2SH = '2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf';
|
||||||
|
var privateKey = 'cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY';
|
||||||
|
var private1 = '6ce7e97e317d2af16c33db0b9270ec047a91bff3eff8558afb5014afb2bb5976';
|
||||||
|
var private2 = 'c9b26b0f771a0d2dad88a44de90f05f416b3b385ff1d989343005546a0032890';
|
||||||
|
var tx = new bitcore.Transaction();
|
||||||
|
tx.from(utxo);
|
||||||
|
tx.to(toAddress, 50000);
|
||||||
|
tx.change(changeAddress);
|
||||||
|
tx.sign(privateKey);
|
||||||
|
|
||||||
|
it('will add an unchecked transaction', function() {
|
||||||
|
var added = bitcoind.addMempoolUncheckedTransaction(tx.serialize());
|
||||||
|
added.should.equal(true);
|
||||||
|
bitcoind.getTransaction(tx.hash, true, function(err, txBuffer) {
|
||||||
|
if(err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
var expected = tx.toBuffer().toString('hex');
|
||||||
|
txBuffer.toString('hex').should.equal(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('get outputs by address', function() {
|
||||||
|
var outputs = bitcoind.getMempoolOutputs(changeAddress);
|
||||||
|
var expected = [
|
||||||
|
{
|
||||||
|
script: 'OP_DUP OP_HASH160 073b7eae2823efa349e3b9155b8a735526463a0f OP_EQUALVERIFY OP_CHECKSIG',
|
||||||
|
satoshis: 40000,
|
||||||
|
txid: tx.hash,
|
||||||
|
outputIndex: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
outputs.should.deep.equal(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('get blocks by hash', function() {
|
||||||
|
|
||||||
|
[0,1,2,3,5,6,7,8,9].forEach(function(i) {
|
||||||
|
it('generated block ' + i, function(done) {
|
||||||
|
bitcoind.getBlock(blockHashes[i], function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
should.exist(response);
|
||||||
|
var block = bitcore.Block.fromBuffer(response);
|
||||||
|
block.hash.should.equal(blockHashes[i]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('get blocks by height', function() {
|
||||||
|
|
||||||
|
[0,1,2,3,5,6,7,8,9].forEach(function(i) {
|
||||||
|
it('generated block ' + i, function(done) {
|
||||||
|
// add the genesis block
|
||||||
|
var height = i + 1;
|
||||||
|
bitcoind.getBlock(i + 1, function(err, response) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
should.exist(response);
|
||||||
|
var block = bitcore.Block.fromBuffer(response);
|
||||||
|
block.hash.should.equal(blockHashes[i]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -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 = {
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Daemon.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;
|
||||||
|
|
|
@ -1,959 +0,0 @@
|
||||||
/**
|
|
||||||
* bitcoind.js
|
|
||||||
* Copyright (c) 2014, BitPay (MIT License)
|
|
||||||
* A bitcoind node.js binding.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var net = require('net');
|
|
||||||
var EventEmitter = require('events').EventEmitter;
|
|
||||||
var bitcoindjs = require('../build/Debug/bitcoindjs.node');
|
|
||||||
var util = require('util');
|
|
||||||
var fs = require('fs');
|
|
||||||
var mkdirp = require('mkdirp');
|
|
||||||
var tiny = require('tiny').json;
|
|
||||||
|
|
||||||
// Compatibility with old node versions:
|
|
||||||
var setImmediate = global.setImmediate || process.nextTick.bind(process);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Daemon
|
|
||||||
*/
|
|
||||||
|
|
||||||
var daemon = Daemon;
|
|
||||||
|
|
||||||
function Daemon(options) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if (!(this instanceof Daemon)) {
|
|
||||||
return new Daemon(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.keys(this.instances).length) {
|
|
||||||
throw new
|
|
||||||
Error('bitcoind.js cannot be instantiated more than once.');
|
|
||||||
}
|
|
||||||
|
|
||||||
EventEmitter.call(this);
|
|
||||||
|
|
||||||
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) {
|
|
||||||
this.options.datadir = '~/.bitcoind.js';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.options.datadir = this.options.datadir.replace(/^~/, process.env.HOME);
|
|
||||||
|
|
||||||
this.datadir = this.options.datadir;
|
|
||||||
this.config = this.datadir + '/bitcoin.conf';
|
|
||||||
this.network = Daemon[this.options.testnet ? 'testnet' : 'livenet'];
|
|
||||||
|
|
||||||
if (!fs.existsSync(this.datadir)) {
|
|
||||||
mkdirp.sync(this.datadir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fs.existsSync(this.config)) {
|
|
||||||
var password = ''
|
|
||||||
+ Math.random().toString(36).slice(2)
|
|
||||||
+ Math.random().toString(36).slice(2)
|
|
||||||
+ Math.random().toString(36).slice(2);
|
|
||||||
fs.writeFileSync(this.config, ''
|
|
||||||
+ 'rpcuser=bitcoinrpc\n'
|
|
||||||
+ 'rpcpassword=' + password + '\n'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add hardcoded peers
|
|
||||||
var data = fs.readFileSync(this.config, 'utf8');
|
|
||||||
if (this.network.peers.length) {
|
|
||||||
var peers = this.network.peers.reduce(function(out, peer) {
|
|
||||||
if (!~data.indexOf('addnode=' + peer)) {
|
|
||||||
return out + 'addnode=' + peer + '\n';
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}, '\n');
|
|
||||||
fs.writeFileSync(data + peers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy config into testnet dir
|
|
||||||
if (this.network.name === 'testnet') {
|
|
||||||
if (!fs.existsSync(this.datadir + '/testnet3')) {
|
|
||||||
fs.mkdirSync(this.datadir + '/testnet3');
|
|
||||||
}
|
|
||||||
fs.writeFileSync(
|
|
||||||
this.datadir + '/testnet3/bitcoin.conf',
|
|
||||||
fs.readFileSync(this.config));
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(exports).forEach(function(key) {
|
|
||||||
self[key] = exports[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('newListener', function(name) {
|
|
||||||
if (name === 'open') {
|
|
||||||
self.start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Daemon.prototype.__proto__ = EventEmitter.prototype;
|
|
||||||
|
|
||||||
Daemon.livenet = {
|
|
||||||
name: 'livenet',
|
|
||||||
peers: [
|
|
||||||
// hardcoded peers
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.testnet = {
|
|
||||||
name: 'testnet',
|
|
||||||
peers: [
|
|
||||||
// hardcoded peers
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make sure signal handlers are not overwritten
|
|
||||||
Daemon._signalQueue = [];
|
|
||||||
Daemon._processOn = process.on;
|
|
||||||
process.addListener =
|
|
||||||
process.on = function(name, listener) {
|
|
||||||
if (~['SIGINT', 'SIGHUP', 'SIGQUIT'].indexOf(name.toUpperCase())) {
|
|
||||||
if (!Daemon.global || !Daemon.global._started) {
|
|
||||||
Daemon._signalQueue.push([name, listener]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Daemon._processOn.apply(this, arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.instances = {};
|
|
||||||
Daemon.prototype.instances = Daemon.instances;
|
|
||||||
|
|
||||||
Daemon.__defineGetter__('global', function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return Daemon.instances[Object.keys(Daemon.instances)[0]];
|
|
||||||
});
|
|
||||||
|
|
||||||
Daemon.prototype.__defineGetter__('global', function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return Daemon.global;
|
|
||||||
});
|
|
||||||
|
|
||||||
tiny.debug = function() {};
|
|
||||||
tiny.prototype.debug = function() {};
|
|
||||||
tiny.error = function() {};
|
|
||||||
tiny.prototype.error = function() {};
|
|
||||||
|
|
||||||
Daemon.db = tiny({
|
|
||||||
file: process.env.HOME + '/.bitcoindjs.db',
|
|
||||||
saveIndex: false,
|
|
||||||
initialCache: false
|
|
||||||
});
|
|
||||||
|
|
||||||
Daemon.prototype.start = function(options, callback) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
if (!callback) {
|
|
||||||
callback = options;
|
|
||||||
options = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options) {
|
|
||||||
options = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!callback) {
|
|
||||||
callback = utils.NOOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.instances[this.datadir]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.instances[this.datadir] = true;
|
|
||||||
|
|
||||||
var none = {};
|
|
||||||
var isSignal = {};
|
|
||||||
var sigint = { name: 'SIGINT', signal: isSignal };
|
|
||||||
var sighup = { name: 'SIGHUP', signal: isSignal };
|
|
||||||
var sigquit = { name: 'SIGQUIT', signal: isSignal };
|
|
||||||
var exitCaught = none;
|
|
||||||
var errorCaught = none;
|
|
||||||
|
|
||||||
Object.keys(this.options).forEach(function(key) {
|
|
||||||
if (options[key] == null) {
|
|
||||||
options[key] = self.options[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
bitcoindjs.start(options, function(err, status) {
|
|
||||||
self._started = true;
|
|
||||||
|
|
||||||
|
|
||||||
[sigint, sighup, sigquit].forEach(function(signal) {
|
|
||||||
process.on(signal.name, signal.listener = function() {
|
|
||||||
if (process.listeners(signal.name).length > 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!self._shutdown) {
|
|
||||||
process.exit(0);
|
|
||||||
} else {
|
|
||||||
self.stop();
|
|
||||||
exitCaught = signal;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Finally set signal handlers
|
|
||||||
process.on = process.addListener = Daemon._processOn;
|
|
||||||
Daemon._signalQueue.forEach(function(event) {
|
|
||||||
process.on(event[0], event[1]);
|
|
||||||
});
|
|
||||||
|
|
||||||
var exit = process.exit;
|
|
||||||
self._exit = function() {
|
|
||||||
return exit.apply(process, arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
process.exit = function(code) {
|
|
||||||
exitCaught = code || 0;
|
|
||||||
if (!self._shutdown) {
|
|
||||||
return self._exit(code);
|
|
||||||
}
|
|
||||||
self.stop();
|
|
||||||
};
|
|
||||||
|
|
||||||
process.on('uncaughtException', function(err) {
|
|
||||||
if (process.listeners('uncaughtException').length > 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
errorCaught = err;
|
|
||||||
self.error('Uncaught error: shutting down safely before throwing...');
|
|
||||||
if (!self._shutdown) {
|
|
||||||
if (err && err.stack) {
|
|
||||||
console.error(err.stack);
|
|
||||||
}
|
|
||||||
self._exit(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(function callee() {
|
|
||||||
// Wait until wallet is loaded:
|
|
||||||
if (callback) {
|
|
||||||
callback(err ? err : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
self.emit('error', err);
|
|
||||||
} else {
|
|
||||||
if (callback) {
|
|
||||||
self.emit('open', status);
|
|
||||||
} else {
|
|
||||||
self.emit('status', status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callback) {
|
|
||||||
callback = null;
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
|
|
||||||
// bitcoind's boost threads aren't in the thread pool
|
|
||||||
// or on node's event loop, so we need to keep node open.
|
|
||||||
this._shutdown = setInterval(function() {
|
|
||||||
if (!self._stoppingSaid && bitcoindjs.stopping()) {
|
|
||||||
self._stoppingSaid = true;
|
|
||||||
self.log('shutting down...');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bitcoindjs.stopped()) {
|
|
||||||
self.log('shut down.');
|
|
||||||
|
|
||||||
clearInterval(self._shutdown);
|
|
||||||
delete self._shutdown;
|
|
||||||
|
|
||||||
if (exitCaught !== none) {
|
|
||||||
if (exitCaught.signal === isSignal) {
|
|
||||||
process.removeListener(exitCaught.name, exitCaught.listener);
|
|
||||||
setImmediate(function() {
|
|
||||||
process.kill(process.pid, exitCaught.name);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return self._exit(exitCaught);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorCaught !== none) {
|
|
||||||
if (errorCaught && errorCaught.stack) {
|
|
||||||
console.error(errorCaught.stack);
|
|
||||||
}
|
|
||||||
return self._exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getBlock = function(blockhash, callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getBlock(blockhash, function(err, block) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
return callback(null, daemon.block(block));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getBlockHeight = function(height, callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getBlock(+height, function(err, block) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
return callback(null, daemon.block(block));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getTransaction =
|
|
||||||
Daemon.prototype.getTx = function(txid, blockhash, callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
if (typeof txid === 'object' && txid) {
|
|
||||||
var options = txid;
|
|
||||||
callback = blockhash;
|
|
||||||
txid = options.txid || options.tx || options.txhash || options.id || options.hash;
|
|
||||||
blockhash = options.blockhash || options.block;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof blockhash === 'function') {
|
|
||||||
callback = blockhash;
|
|
||||||
blockhash = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof blockhash !== 'string') {
|
|
||||||
if (blockhash) {
|
|
||||||
blockhash = blockhash.hash
|
|
||||||
|| blockhash.blockhash
|
|
||||||
|| (blockhash.getHash && blockhash.getHash())
|
|
||||||
|| '';
|
|
||||||
} else {
|
|
||||||
blockhash = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bitcoindjs.getTransaction(txid, blockhash, function(err, tx) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
return callback(null, daemon.tx(tx));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getTransactionWithBlock = function(txid, blockhash, callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
var slow = true;
|
|
||||||
|
|
||||||
if (typeof txid === 'object' && txid) {
|
|
||||||
var options = txid;
|
|
||||||
callback = blockhash;
|
|
||||||
txid = options.txid || options.tx || options.txhash || options.id || options.hash;
|
|
||||||
blockhash = options.blockhash || options.block;
|
|
||||||
slow = options.slow !== false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof blockhash === 'function') {
|
|
||||||
callback = blockhash;
|
|
||||||
blockhash = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof blockhash !== 'string') {
|
|
||||||
if (blockhash) {
|
|
||||||
blockhash = blockhash.hash
|
|
||||||
|| blockhash.blockhash
|
|
||||||
|| (blockhash.getHash && blockhash.getHash())
|
|
||||||
|| '';
|
|
||||||
} else {
|
|
||||||
blockhash = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bitcoindjs.getTransaction(txid, blockhash, function(err, tx) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
|
|
||||||
if (slow && !tx.blockhash) {
|
|
||||||
return self.getBlockByTx(txid, function(err, block, tx_) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
return callback(null, tx, block);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return bitcoindjs.getBlock(tx.blockhash, function(err, block) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
return callback(null, daemon.tx(tx), daemon.block(block));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getInfo = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getInfo();
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getPeerInfo = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getPeerInfo();
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getAddresses = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getAddresses();
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getProgress = function(callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getProgress(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.setGenerate = function(options) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.setGenerate(options || {});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getGenerate = function(options) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getGenerate(options || {});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getMiningInfo = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getMiningInfo();
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getAddrTransactions = function(address, callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return daemon.db.get('addr-tx/' + address, function(err, records) {
|
|
||||||
var options = {
|
|
||||||
address: address,
|
|
||||||
blockheight: (records || []).reduce(function(out, record) {
|
|
||||||
return record.blockheight > out
|
|
||||||
? record.blockheight
|
|
||||||
: out;
|
|
||||||
}, -1),
|
|
||||||
blocktime: (records || []).reduce(function(out, record) {
|
|
||||||
return record.blocktime > out
|
|
||||||
? record.blocktime
|
|
||||||
: out;
|
|
||||||
}, -1)
|
|
||||||
};
|
|
||||||
return bitcoindjs.getAddrTransactions(options, function(err, addr) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
addr = daemon.addr(addr);
|
|
||||||
if (addr.tx[0] && !addr.tx[0].vout[0]) {
|
|
||||||
return daemon.db.set('addr-tx/' + address, [{
|
|
||||||
txid: null,
|
|
||||||
blockhash: null,
|
|
||||||
blockheight: null,
|
|
||||||
blocktime: null
|
|
||||||
}], function() {
|
|
||||||
return callback(null, daemon.addr({
|
|
||||||
address: addr.address,
|
|
||||||
tx: []
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var set = [];
|
|
||||||
if (records && records.length) {
|
|
||||||
set = records;
|
|
||||||
}
|
|
||||||
addr.tx.forEach(function(tx) {
|
|
||||||
set.push({
|
|
||||||
txid: tx.txid,
|
|
||||||
blockhash: tx.blockhash,
|
|
||||||
blockheight: tx.blockheight,
|
|
||||||
blocktime: tx.blocktime
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return daemon.db.set('addr-tx/' + address, set, function() {
|
|
||||||
return callback(null, addr);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getBestBlock = function(callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var hash = bitcoindjs.getBestBlock();
|
|
||||||
return bitcoindjs.getBlock(hash, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getChainHeight = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getChainHeight();
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.__defineGetter__('chainHeight', function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return this.getChainHeight();
|
|
||||||
});
|
|
||||||
|
|
||||||
Daemon.prototype.getBlockByTxid =
|
|
||||||
Daemon.prototype.getBlockByTx = function(txid, callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return daemon.db.get('block-tx/' + txid, function(err, block) {
|
|
||||||
if (block) {
|
|
||||||
return self.getBlock(block.hash, function(err, block) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
var tx_ = block.tx.filter(function(tx) {
|
|
||||||
return tx.txid === txid;
|
|
||||||
})[0];
|
|
||||||
return callback(null, block, tx_);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return bitcoindjs.getBlockByTx(txid, function(err, block, tx_) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
daemon.db.set('block-tx/' + txid, { hash: block.hash }, utils.NOOP);
|
|
||||||
return callback(null, daemon.block(block), daemon.tx(tx_));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getBlocksByDate =
|
|
||||||
Daemon.prototype.getBlocksByTime = function(options, callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getBlocksByTime(options, function(err, blocks) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
return callback(null, blocks.map(function(block) {
|
|
||||||
return daemon.block(block)
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getFromTx = function(txid, callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getFromTx(txid, function(err, txs) {
|
|
||||||
if (err) return callback(err);
|
|
||||||
return callback(null, txs.map(function(tx) {
|
|
||||||
return daemon.tx(tx)
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.getLastFileIndex = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return bitcoindjs.getLastFileIndex();
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.log =
|
|
||||||
Daemon.prototype.info = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
if (this.options.silent) return;
|
|
||||||
if (typeof arguments[0] !== 'string') {
|
|
||||||
var out = util.inspect(arguments[0], null, 20, true);
|
|
||||||
return process.stdout.write('bitcoind.js: ' + out + '\n');
|
|
||||||
}
|
|
||||||
var out = util.format.apply(util, arguments);
|
|
||||||
return process.stdout.write('bitcoind.js: ' + out + '\n');
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.error = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
if (this.options.silent) return;
|
|
||||||
if (typeof arguments[0] !== 'string') {
|
|
||||||
var out = util.inspect(arguments[0], null, 20, true);
|
|
||||||
return process.stderr.write('bitcoind.js: ' + out + '\n');
|
|
||||||
}
|
|
||||||
var out = util.format.apply(util, arguments);
|
|
||||||
return process.stderr.write('bitcoind.js: ' + out + '\n');
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.stop =
|
|
||||||
Daemon.prototype.close = function(callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var self = this;
|
|
||||||
return bitcoindjs.stop(function(err, status) {
|
|
||||||
if (err) {
|
|
||||||
self.error(err.message);
|
|
||||||
} else {
|
|
||||||
self.log(status);
|
|
||||||
}
|
|
||||||
if (!callback) return;
|
|
||||||
return callback(err, status);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Daemon.prototype.__defineGetter__('stopping', function() {
|
|
||||||
return bitcoindjs.stopping() || bitcoindjs.stopped();
|
|
||||||
});
|
|
||||||
|
|
||||||
Daemon.prototype.__defineGetter__('stopped', function() {
|
|
||||||
return bitcoindjs.stopped();
|
|
||||||
});
|
|
||||||
|
|
||||||
Daemon.__defineGetter__('stopping', function() {
|
|
||||||
return bitcoindjs.stopping() || bitcoindjs.stopped();
|
|
||||||
});
|
|
||||||
|
|
||||||
Daemon.__defineGetter__('stopped', function() {
|
|
||||||
return bitcoindjs.stopped();
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block
|
|
||||||
*/
|
|
||||||
|
|
||||||
function Block(data) {
|
|
||||||
if (!(this instanceof Block)) {
|
|
||||||
return new Block(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
return Block.fromHex(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data instanceof Block) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
Object.keys(data).forEach(function(key) {
|
|
||||||
if (!self[key]) {
|
|
||||||
self[key] = data[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.tx = this.tx.map(function(tx) {
|
|
||||||
return daemon.tx(tx);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!this.hex) {
|
|
||||||
this.hex = this.toHex();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.defineProperty(Block.prototype, '_blockFlag', {
|
|
||||||
__proto__: null,
|
|
||||||
configurable: false,
|
|
||||||
enumerable: false,
|
|
||||||
writable: false,
|
|
||||||
value: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
Block.isBlock = function(block) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return block._blockFlag === Block.prototype._blockFlag;
|
|
||||||
};
|
|
||||||
|
|
||||||
Block.fromHex = function(hex) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return daemon.block(bitcoindjs.blockFromHex(hex));
|
|
||||||
};
|
|
||||||
|
|
||||||
Block.prototype.getHash = function(enc) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var data = bitcoindjs.getBlockHex(this);
|
|
||||||
if (!this.hash || this.hash !== data.hash) {
|
|
||||||
this.hash = data.hash;
|
|
||||||
}
|
|
||||||
if (enc === 'hex') return data.hash;
|
|
||||||
var buf = new Buffer(data.hash, 'hex');
|
|
||||||
var out = enc ? buf.toString(enc) : buf;
|
|
||||||
return out;
|
|
||||||
};
|
|
||||||
|
|
||||||
Block.prototype.verify = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return this.verified = this.verified || bitcoindjs.verifyBlock(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
Block.prototype.toHex = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var hex = Block.toHex(this);
|
|
||||||
if (!this.hex || this.hex !== hex) {
|
|
||||||
this.hex = hex;
|
|
||||||
}
|
|
||||||
return hex;
|
|
||||||
};
|
|
||||||
|
|
||||||
Block.toHex = function(block) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var data = bitcoindjs.getBlockHex(block);
|
|
||||||
return data.hex;
|
|
||||||
};
|
|
||||||
|
|
||||||
Block.prototype.toBinary = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return Block.toBinary(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
Block.toBinary = function(block) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var data = bitcoindjs.getBlockHex(block);
|
|
||||||
return new Buffer(data.hex, 'hex');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transaction
|
|
||||||
*/
|
|
||||||
|
|
||||||
function Transaction(data) {
|
|
||||||
if (!(this instanceof Transaction)) {
|
|
||||||
return new Transaction(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
return Transaction.fromHex(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data instanceof Transaction) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
Object.keys(data).forEach(function(key) {
|
|
||||||
if (!self[key]) {
|
|
||||||
self[key] = data[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!this.hex) {
|
|
||||||
this.hex = this.toHex();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.defineProperty(Transaction.prototype, '_txFlag', {
|
|
||||||
__proto__: null,
|
|
||||||
configurable: false,
|
|
||||||
enumerable: false,
|
|
||||||
writable: false,
|
|
||||||
value: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
Transaction.isTransaction =
|
|
||||||
Transaction.isTx = function(tx) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return tx._txFlag === Transaction.prototype._txFlag;
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.fromHex = function(hex) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return daemon.tx(bitcoindjs.txFromHex(hex));
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.prototype.verify = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return this.verified = this.verified || bitcoindjs.verifyTransaction(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.prototype.sign =
|
|
||||||
Transaction.prototype.fill = function(options) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return Transaction.fill(this, options);
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.sign =
|
|
||||||
Transaction.fill = function(tx, options) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var isTx = daemon.tx.isTx(tx)
|
|
||||||
, newTx;
|
|
||||||
|
|
||||||
if (!isTx) {
|
|
||||||
tx = daemon.tx(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
newTx = bitcoindjs.fillTransaction(tx, options || {});
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(newTx).forEach(function(key) {
|
|
||||||
tx[key] = newTx[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
return tx;
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.prototype.getHash = function(enc) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var data = bitcoindjs.getTxHex(this);
|
|
||||||
if (!this.txid || this.txid !== data.hash) {
|
|
||||||
this.txid = data.hash;
|
|
||||||
}
|
|
||||||
if (enc === 'hex') return data.hash;
|
|
||||||
var buf = new Buffer(data.hash, 'hex');
|
|
||||||
var out = enc ? buf.toString(enc) : buf;
|
|
||||||
return out;
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.prototype.isCoinbase = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return this.vin.length === 1 && this.vin[0].coinbase;
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.prototype.toHex = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var hex = Transaction.toHex(this);
|
|
||||||
if (!this.hex || hex !== this.hex) {
|
|
||||||
this.hex = hex;
|
|
||||||
}
|
|
||||||
return hex;
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.toHex = function(tx) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var data = bitcoindjs.getTxHex(tx);
|
|
||||||
return data.hex;
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.prototype.toBinary = function() {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return Transaction.toBinary(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.toBinary = function(tx) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var data = bitcoindjs.getTxHex(tx);
|
|
||||||
return new Buffer(data.hex, 'hex');
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.broadcast = function(tx, options, callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
if (typeof tx === 'string') {
|
|
||||||
tx = { hex: tx };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!callback) {
|
|
||||||
callback = options;
|
|
||||||
options = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options) {
|
|
||||||
options = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
var fee = options.overrideFees = options.overrideFees || false;
|
|
||||||
var own = options.ownOnly = options.ownOnly || false;
|
|
||||||
|
|
||||||
if (!callback) {
|
|
||||||
callback = utils.NOOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!daemon.isTx(tx)) {
|
|
||||||
tx = daemon.tx(tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bitcoindjs.broadcastTx(tx, fee, own, function(err, hash, tx) {
|
|
||||||
if (err) {
|
|
||||||
if (callback === utils.NOOP) {
|
|
||||||
daemon.global.emit('error', err);
|
|
||||||
}
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
tx = daemon.tx(tx);
|
|
||||||
daemon.global.emit('broadcast', tx);
|
|
||||||
return callback(null, hash, tx);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction.prototype.broadcast = function(options, callback) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
if (!callback) {
|
|
||||||
callback = options;
|
|
||||||
options = null;
|
|
||||||
}
|
|
||||||
return Transaction.broadcast(this, options, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Addresses
|
|
||||||
*/
|
|
||||||
|
|
||||||
function Addresses(data) {
|
|
||||||
if (!(this instanceof Addresses)) {
|
|
||||||
return new Addresses(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data instanceof Addresses) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
Object.keys(data).forEach(function(key) {
|
|
||||||
if (!self[key]) {
|
|
||||||
self[key] = data[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.defineProperty(Transaction.prototype, '_addrFlag', {
|
|
||||||
__proto__: null,
|
|
||||||
configurable: false,
|
|
||||||
enumerable: false,
|
|
||||||
writable: false,
|
|
||||||
value: {}
|
|
||||||
});
|
|
||||||
|
|
||||||
Addresses.isAddresses =
|
|
||||||
Addresses.isAddr = function(addr) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
return addr._txFlag === Addresses.prototype._addrFlag;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utils
|
|
||||||
*/
|
|
||||||
|
|
||||||
var utils = {};
|
|
||||||
|
|
||||||
utils.forEach = function(obj, iter, done) {
|
|
||||||
if (daemon.stopping) return [];
|
|
||||||
var pending = obj.length;
|
|
||||||
if (!pending) return done();
|
|
||||||
var next = function() {
|
|
||||||
if (!--pending) done();
|
|
||||||
};
|
|
||||||
obj.forEach(function(item) {
|
|
||||||
iter(item, next);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
utils.NOOP = function() {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expose
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = exports = daemon;
|
|
||||||
|
|
||||||
exports.Daemon = daemon;
|
|
||||||
exports.daemon = daemon;
|
|
||||||
exports.bitcoind = daemon;
|
|
||||||
|
|
||||||
exports.native = bitcoindjs;
|
|
||||||
exports.bitcoindjs = bitcoindjs;
|
|
||||||
|
|
||||||
exports.Block = Block;
|
|
||||||
exports.block = Block;
|
|
||||||
|
|
||||||
exports.Transaction = Transaction;
|
|
||||||
exports.transaction = Transaction;
|
|
||||||
exports.tx = Transaction;
|
|
||||||
|
|
||||||
exports.Addresses = Addresses;
|
|
||||||
exports.addresses = Addresses;
|
|
||||||
exports.addr = Addresses;
|
|
||||||
|
|
||||||
exports.utils = utils;
|
|
31
lib/node.js
31
lib/node.js
|
@ -74,7 +74,7 @@ Node.prototype._loadBitcoinConf = function(config) {
|
||||||
Node.prototype._loadBitcoind = function(config) {
|
Node.prototype._loadBitcoind = function(config) {
|
||||||
var bitcoindConfig = {};
|
var bitcoindConfig = {};
|
||||||
bitcoindConfig.datadir = config.datadir;
|
bitcoindConfig.datadir = config.datadir;
|
||||||
bitcoindConfig.testnet = config.testnet;
|
bitcoindConfig.network = config.network;
|
||||||
|
|
||||||
// start the bitcoind daemon
|
// start the bitcoind daemon
|
||||||
this.bitcoind = daemon(bitcoindConfig);
|
this.bitcoind = daemon(bitcoindConfig);
|
||||||
|
@ -117,11 +117,23 @@ Node.prototype._syncBitcoind = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Node.prototype._loadNetwork = function(config) {
|
Node.prototype._loadNetwork = function(config) {
|
||||||
if (config.network) {
|
if (config.network === 'testnet') {
|
||||||
Networks.add(config.network);
|
|
||||||
this.network = Networks.get(config.network.name);
|
|
||||||
} else if (config.testnet) {
|
|
||||||
this.network = Networks.get('testnet');
|
this.network = Networks.get('testnet');
|
||||||
|
} else if (config.network === 'regtest') {
|
||||||
|
Networks.remove(Networks.testnet);
|
||||||
|
Networks.add({
|
||||||
|
name: 'regtest',
|
||||||
|
alias: 'regtest',
|
||||||
|
pubkeyhash: 0x6f,
|
||||||
|
privatekey: 0xef,
|
||||||
|
scripthash: 0xc4,
|
||||||
|
xpubkey: 0x043587cf,
|
||||||
|
xprivkey: 0x04358394,
|
||||||
|
networkMagic: 0xfabfb5da,
|
||||||
|
port: 18444,
|
||||||
|
dnsSeeds: [ ]
|
||||||
|
});
|
||||||
|
this.network = Networks.get('regtest');
|
||||||
} else {
|
} else {
|
||||||
this.network = Networks.get('livenet');
|
this.network = Networks.get('livenet');
|
||||||
}
|
}
|
||||||
|
@ -142,11 +154,14 @@ Node.prototype._loadDB = function(config) {
|
||||||
// based on the network configuration and the datadir
|
// based on the network configuration and the datadir
|
||||||
$.checkArgument(config.datadir, 'Please specify "datadir" in configuration options');
|
$.checkArgument(config.datadir, 'Please specify "datadir" in configuration options');
|
||||||
$.checkState(this.network, 'Network property not defined');
|
$.checkState(this.network, 'Network property not defined');
|
||||||
|
var regtest = Networks.get('regtest');
|
||||||
var datadir = config.datadir.replace(/^~/, process.env.HOME);
|
var datadir = config.datadir.replace(/^~/, process.env.HOME);
|
||||||
if (this.network === Networks.testnet) {
|
if (this.network === Networks.livenet) {
|
||||||
config.db.path = datadir + '/testnet3/bitcoindjs.db';
|
|
||||||
} else if (this.network === Networks.livenet) {
|
|
||||||
config.db.path = datadir + '/bitcoindjs.db';
|
config.db.path = datadir + '/bitcoindjs.db';
|
||||||
|
} else if (this.network === Networks.testnet) {
|
||||||
|
config.db.path = datadir + '/testnet3/bitcoindjs.db';
|
||||||
|
} else if (this.network === regtest) {
|
||||||
|
config.db.path = datadir + '/regtest/bitcoindjs.db';
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown network: ' + this.network);
|
throw new Error('Unknown network: ' + this.network);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
},
|
},
|
||||||
|
@ -51,10 +50,12 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"benchmark": "1.0.0",
|
"benchmark": "1.0.0",
|
||||||
"bitcoin": "^2.3.2",
|
"bitcoin": "^2.3.2",
|
||||||
|
"bitcoind-rpc": "^0.3.0",
|
||||||
"bitcore": "^0.12.12",
|
"bitcore": "^0.12.12",
|
||||||
"chai": "^3.0.0",
|
"chai": "^3.0.0",
|
||||||
"mocha": "~1.16.2",
|
"mocha": "~1.16.2",
|
||||||
"sinon": "^1.15.4",
|
"proxyquire": "^1.3.1",
|
||||||
"proxyquire": "^1.3.1"
|
"rimraf": "^2.4.2",
|
||||||
|
"sinon": "^1.15.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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++;
|
||||||
|
|
||||||
|
|
|
@ -168,38 +168,24 @@ describe('Bitcoind Node', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#_loadNetwork', function() {
|
describe('#_loadNetwork', function() {
|
||||||
it('should add the network that was listed in the config', function() {
|
|
||||||
var config = {
|
|
||||||
network: {
|
|
||||||
name: 'chainlib',
|
|
||||||
alias: 'chainlib',
|
|
||||||
pubkeyhash: 0x1c,
|
|
||||||
privatekey: 0x1e,
|
|
||||||
scripthash: 0x28,
|
|
||||||
xpubkey: 0x02e8de8f,
|
|
||||||
xprivkey: 0x02e8da54,
|
|
||||||
networkMagic: 0x0c110907,
|
|
||||||
port: 9333
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var node = new Node(config);
|
|
||||||
node._loadNetwork(config);
|
|
||||||
var network = Networks.get('chainlib');
|
|
||||||
should.exist(network);
|
|
||||||
node.network.name.should.equal('chainlib');
|
|
||||||
});
|
|
||||||
it('should use the testnet network if testnet is specified', function() {
|
it('should use the testnet network if testnet is specified', function() {
|
||||||
var config = {
|
var config = {
|
||||||
testnet: true
|
network: 'testnet'
|
||||||
};
|
};
|
||||||
|
|
||||||
var node = new Node(config);
|
var node = new Node(config);
|
||||||
node._loadNetwork(config);
|
node._loadNetwork(config);
|
||||||
node.network.name.should.equal('testnet');
|
node.network.name.should.equal('testnet');
|
||||||
});
|
});
|
||||||
|
it('should use the regtest network if regtest is specified', function() {
|
||||||
|
var config = {
|
||||||
|
network: 'regtest'
|
||||||
|
};
|
||||||
|
var node = new Node(config);
|
||||||
|
node._loadNetwork(config);
|
||||||
|
node.network.name.should.equal('regtest');
|
||||||
|
});
|
||||||
it('should use the livenet network if nothing is specified', function() {
|
it('should use the livenet network if nothing is specified', function() {
|
||||||
var config = {};
|
var config = {};
|
||||||
|
|
||||||
var node = new Node(config);
|
var node = new Node(config);
|
||||||
node._loadNetwork(config);
|
node._loadNetwork(config);
|
||||||
node.network.name.should.equal('livenet');
|
node.network.name.should.equal('livenet');
|
||||||
|
@ -245,6 +231,54 @@ describe('Bitcoind Node', function() {
|
||||||
node._loadDB(config);
|
node._loadDB(config);
|
||||||
}).should.throw('Unknown network');
|
}).should.throw('Unknown network');
|
||||||
});
|
});
|
||||||
|
it('should load the db with regtest', function() {
|
||||||
|
var DB = function(config) {
|
||||||
|
config.path.should.equal(process.env.HOME + '/.bitcoin/regtest/bitcoindjs.db');
|
||||||
|
};
|
||||||
|
var config = {
|
||||||
|
DB: DB,
|
||||||
|
datadir: '~/.bitcoin'
|
||||||
|
};
|
||||||
|
|
||||||
|
var node = new Node(config);
|
||||||
|
// Switch to use regtest
|
||||||
|
Networks.remove(Networks.testnet);
|
||||||
|
Networks.add({
|
||||||
|
name: 'regtest',
|
||||||
|
alias: 'regtest',
|
||||||
|
pubkeyhash: 0x6f,
|
||||||
|
privatekey: 0xef,
|
||||||
|
scripthash: 0xc4,
|
||||||
|
xpubkey: 0x043587cf,
|
||||||
|
xprivkey: 0x04358394,
|
||||||
|
networkMagic: 0xfabfb5da,
|
||||||
|
port: 18444,
|
||||||
|
dnsSeeds: [ ]
|
||||||
|
});
|
||||||
|
var regtest = Networks.get('regtest');
|
||||||
|
node.network = regtest;
|
||||||
|
node._loadDB(config);
|
||||||
|
node.db.should.be.instanceof(DB);
|
||||||
|
Networks.remove(regtest);
|
||||||
|
// Add testnet back
|
||||||
|
Networks.add({
|
||||||
|
name: 'testnet',
|
||||||
|
alias: 'testnet',
|
||||||
|
pubkeyhash: 0x6f,
|
||||||
|
privatekey: 0xef,
|
||||||
|
scripthash: 0xc4,
|
||||||
|
xpubkey: 0x043587cf,
|
||||||
|
xprivkey: 0x04358394,
|
||||||
|
networkMagic: 0x0b110907,
|
||||||
|
port: 18333,
|
||||||
|
dnsSeeds: [
|
||||||
|
'testnet-seed.bitcoin.petertodd.org',
|
||||||
|
'testnet-seed.bluematt.me',
|
||||||
|
'testnet-seed.alexykot.me',
|
||||||
|
'testnet-seed.bitcoin.schildbach.de'
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe('#_loadP2P', function() {
|
describe('#_loadP2P', function() {
|
||||||
it('should load p2p', function() {
|
it('should load p2p', function() {
|
||||||
|
|
Loading…
Reference in New Issue