readme. bitcoindjs.stop. building.

This commit is contained in:
Christopher Jeffrey 2014-09-11 17:18:36 -07:00
parent ea706e329b
commit 2de298bbc3
5 changed files with 199 additions and 29 deletions

View File

@ -4,39 +4,58 @@ Bitcoind as a node.js module.
## Building ## Building
### bitcoind: ### bitcoind
- NOTE (to self): Arch is using bitcoin-daemon 0.9.2.1, the latest boost headers - NOTE (to self): Arch is using bitcoin-daemon 0.9.2.1, the latest boost headers
in Arch should be correct. in Arch should be correct.
Cloning libbitcoind:
``` bash ``` bash
$ cd ~/bitcoin $ cd ~
$ git clean -xdf $ git clone git@github.com:bitpay/libbitcoind.git bitcoin
$ cd bitcoin
```
... This is a fork of bitcoin v0.9.0 right now, but it has the ability to compile
bitcoind as a shared object. This may not be ideal yet.
$ git checkout v0.9.2.1 #### Compiling bticoind as a library
OR:
$ git checkout v0.9.0
... ``` bash
# ensure clean up
$ make clean
$ find ~/bitcoin -type f -name '*.o' -or -name '*.so' -print0 | xargs -0 rm -f
# create configure file
$ ./autogen.sh $ ./autogen.sh
... # configure as a library with -fPIC on all object files
# use --with-incompatible-bdb if necessary
# use --prefix=/usr if necessary
$ ./configure --enable-library --with-incompatible-bdb
$ ./configure --with-incompatible-bdb --prefix=/usr # build libbitcoind.so
OR: $ time make library
$ ./configure --prefix=/usr
...
$ time make
real 31m33.128s real 31m33.128s
user 16m23.930s user 16m23.930s
sys 2m52.310s sys 2m52.310s
``` ```
`--enable-library` will compile all object files with `-fPIC` (Position
Independent Code - needed to create a shared object).
`make library` will then compile `./src/libbitcoind.so` (with `-shared -fPIC`),
linking to all the freshly compiled PIC object files.
Without `--enable-library`, the Makefile with compile bitcoind with -fPIE
(Position Independent for Executable), this allows compiling of bitcoind.
#### Todo
- Find a way to compile bitcoind and libbitcoind.so at the same time without
recompiling object files each time?
### bitcoind.js: ### bitcoind.js:
- NOTE: This will eventually try to include our included version of boost. - NOTE: This will eventually try to include our included version of boost.
@ -47,6 +66,30 @@ $ cd ~/work/node_modules/bitcoind.js
$ PYTHON=/usr/bin/python2.7 make gyp $ PYTHON=/usr/bin/python2.7 make gyp
``` ```
#### Running bitcoind.js
You can run bitcoind.js to start downloading the blockchain by doing:
``` bash
$ node example/ &
bitcoind: log pipe opened: 12
bitcoind: status="start_node(): bitcoind opened."
```
However, if you look at the bitcoind log files:
``` bash
$ tail -f ~/.bitcoin/debug.log
connect() to [2001:470:c1f2:3::201]:8333 failed: 101
connect() to [2001:470:6c:778::2]:8333 failed: 101
connect() to [2001:470:c1f2:3::201]:8333 failed: 101
```
Right now, the `connect(3)` call is failing due to some conflict with node or
libuv I'm guessing. This is being investigated.
^C (SIGINT) will call `StartShutdown()` in bitcoind on the node thread pool.
## Contribution and License Agreement ## Contribution and License Agreement
If you contribute code to this project, you are implicitly allowing your code If you contribute code to this project, you are implicitly allowing your code

View File

@ -15,6 +15,7 @@
'defines': [ 'defines': [
'HAVE_WORKING_BOOST_SLEEP', 'HAVE_WORKING_BOOST_SLEEP',
#'HAVE_WORKING_BOOST_SLEEP_FOR', #'HAVE_WORKING_BOOST_SLEEP_FOR',
'ENABLE_WALLET',
], ],
'cflags_cc': [ 'cflags_cc': [
'-fexceptions', '-fexceptions',

View File

@ -2,10 +2,18 @@
var bitcoind = require('../')(); var bitcoind = require('../')();
bitcoind.on('error', function(err) { bitcoind.start(function(err) {
console.log('bitcoind: error="%s"', err.message); bitcoind.on('error', function(err) {
console.log('bitcoind: error="%s"', err.message);
});
bitcoind.on('open', function(status) {
console.log('bitcoind: status="%s"', status);
});
}); });
bitcoind.on('open', function(status) { process.on('SIGINT', function() {
console.log('bitcoind: status="%s"', status); return bitcoind.stop(function(err) {
if (err) throw err;
return process.exit(0);
});
}); });

View File

@ -23,13 +23,23 @@ function Bitcoin(options) {
EventEmitter.call(this); EventEmitter.call(this);
this.options = options; this.options = options;
}
Bitcoin.prototype.__proto__ = EventEmitter.prototype;
Bitcoin.prototype.start = function(callback) {
var self = this;
this.log_pipe = bitcoindjs.start(function(err, status) { this.log_pipe = bitcoindjs.start(function(err, status) {
if (callback) {
callback(err);
callback = null;
}
if (err) { if (err) {
self.emit('error', err); self.emit('error', err);
return; } else {
self.emit('open', status);
} }
self.emit('open', status);
}); });
// bitcoind's boost threads aren't in the thread pool // bitcoind's boost threads aren't in the thread pool
@ -38,10 +48,8 @@ function Bitcoin(options) {
; ;
}, 10000); }, 10000);
this.log('log pipe opened: %d', this.log_pipe); return this.log('log pipe opened: %d', this.log_pipe);
} };
Bitcoin.prototype.__proto__ = EventEmitter.prototype;
Bitcoin.prototype.log = Bitcoin.prototype.log =
Bitcoin.prototype.info = function() { Bitcoin.prototype.info = function() {
@ -62,10 +70,20 @@ Bitcoin.prototype.error = function() {
return process.stderr.write('bitcoind: ' + out + '\n'); return process.stderr.write('bitcoind: ' + out + '\n');
}; };
Bitcoin.prototype.close = function() { Bitcoin.prototype.stop =
Bitcoin.prototype.close = function(callback) {
var self = this;
clearInterval(this._interval); clearInterval(this._interval);
delete this._interval; delete this._interval;
// XXX Call bitcoind's shutdown here return bitcoindjs.stop(function(err, status) {
if (err) {
self.error(err.message);
} else {
self.log(status);
}
if (!callback) return;
return callback(err, status);
});
}; };
/** /**

View File

@ -78,8 +78,8 @@ extern void (ThreadImport)(std::vector<boost::filesystem::path>);
extern void (DetectShutdownThread)(boost::thread_group*); extern void (DetectShutdownThread)(boost::thread_group*);
extern void (StartNode)(boost::thread_group&); extern void (StartNode)(boost::thread_group&);
extern void (ThreadScriptCheck)(); extern void (ThreadScriptCheck)();
extern void (StartShutdown)();
extern int nScriptCheckThreads; extern int nScriptCheckThreads;
// extern const int DEFAULT_SCRIPTCHECK_THREADS; // static!!
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
extern std::string strWalletFile; extern std::string strWalletFile;
extern CWallet *pwalletMain; extern CWallet *pwalletMain;
@ -108,6 +108,12 @@ async_start_node_work(uv_work_t *req);
static void static void
async_start_node_after(uv_work_t *req); async_start_node_after(uv_work_t *req);
static void
async_stop_node_work(uv_work_t *req);
static void
async_stop_node_after(uv_work_t *req);
static int static int
start_node(void); start_node(void);
@ -275,6 +281,8 @@ async_start_node_after(uv_work_t *req) {
static int static int
start_node(void) { start_node(void) {
boost::thread_group threadGroup; boost::thread_group threadGroup;
// XXX Run this in a node thread instead to keep the event loop open:
boost::thread *detectShutdownThread = NULL; boost::thread *detectShutdownThread = NULL;
detectShutdownThread = new boost::thread( detectShutdownThread = new boost::thread(
boost::bind(&DetectShutdownThread, &threadGroup)); boost::bind(&DetectShutdownThread, &threadGroup));
@ -451,6 +459,97 @@ async_parse_logs_after(uv_work_t *req) {
delete req; delete req;
} }
/**
* StopBitcoind
* bitcoind.stop(callback)
*/
NAN_METHOD(StopBitcoind) {
NanScope();
if (args.Length() < 1 || !args[0]->IsFunction()) {
return NanThrowError(
"Usage: bitcoind.stop(callback)");
}
Local<Function> callback = Local<Function>::Cast(args[0]);
//
// Run bitcoind's StartShutdown() on a separate thread.
//
async_node_data* data_stop_node = new async_node_data();
data_stop_node->err_msg = NULL;
data_stop_node->result = NULL;
data_stop_node->callback = Persistent<Function>::New(callback);
uv_work_t *req_stop_node = new uv_work_t();
req_stop_node->data = data_stop_node;
int status_stop_node = uv_queue_work(uv_default_loop(),
req_stop_node, async_stop_node_work,
(uv_after_work_cb)async_stop_node_after);
assert(status_stop_node == 0);
NanReturnValue(Undefined());
}
/**
* async_stop_node_work()
* Call StartShutdown() to join the boost threads, which will call Shutdown().
*/
static void
async_stop_node_work(uv_work_t *req) {
async_node_data* node_data = static_cast<async_node_data*>(req->data);
StartShutdown();
node_data->result = (char *)strdup("stop_node(): bitcoind shutdown.");
}
/**
* async_stop_node_after()
* Execute our callback.
*/
static void
async_stop_node_after(uv_work_t *req) {
NanScope();
async_node_data* node_data = static_cast<async_node_data*>(req->data);
if (node_data->err_msg != NULL) {
Local<Value> err = Exception::Error(String::New(node_data->err_msg));
free(node_data->err_msg);
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
node_data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(String::New(node_data->result))
};
TryCatch try_catch;
node_data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
node_data->callback.Dispose();
if (node_data->result != NULL) {
free(node_data->result);
}
delete node_data;
delete req;
}
/** /**
* Init * Init
*/ */
@ -459,6 +558,7 @@ extern "C" void
init(Handle<Object> target) { init(Handle<Object> target) {
NanScope(); NanScope();
NODE_SET_METHOD(target, "start", StartBitcoind); NODE_SET_METHOD(target, "start", StartBitcoind);
NODE_SET_METHOD(target, "stop", StopBitcoind);
} }
NODE_MODULE(bitcoindjs, init) NODE_MODULE(bitcoindjs, init)