readme. bitcoindjs.stop. building.
This commit is contained in:
parent
ea706e329b
commit
2de298bbc3
75
README.md
75
README.md
@ -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
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user