Update name to Bitcore Node

This commit is contained in:
Braydon Fuller 2015-07-31 11:40:15 -04:00
parent 47219a745a
commit f4061037b6
15 changed files with 89 additions and 629 deletions

View File

@ -1,7 +1,7 @@
sudo: false
language: node_js
env:
- BITCOINDJS_ENV=test BITCOINDJS_ASSUME_YES=true
- BITCORENODE_ENV=test BITCORENODE_ASSUME_YES=true
node_js:
- "0.12"
before_install:

View File

@ -1,15 +1,13 @@
bitcoind.js
Bitcore Node
=======
[![Build Status](https://img.shields.io/travis/bitpay/bitcoind.js.svg?branch=master&style=flat-square)](https://travis-ci.org/bitpay/bitcoind.js)
[![Coverage Status](https://img.shields.io/coveralls/bitpay/bitcoind.js.svg?style=flat-square)](https://coveralls.io/r/bitpay/bitcoind.js)
A Node.js module that adds a native interface to Bitcoin Core for querying information about the Bitcoin blockchain. Bindings are linked to Bitcore Core compiled as a shared library.
## Install
```bash
git clone https://github.com/bitpay/bitcoind.js.git
cd bitcoind.js
git clone https://github.com/bitpay/bitcore-node.git
cd bitcore-node
npm install
```
@ -17,7 +15,7 @@ npm install
```js
var BitcoinNode = require('bitcoind.js');
var BitcoinNode = require('bitcore-node');
var configuration = {
datadir: '~/.bitcoin',
@ -101,22 +99,22 @@ $ tail -f ~/.bitcoin/debug.log
## Modules
Bitcoind.js has a module system where additional information can be indexed and queried from
Bitcore Node has a module system where additional information can be indexed and queried from
the blockchain. One built-in module is the address module which exposes the API methods for getting balances and outputs.
### Writing a Module
A new module can be created by inheriting from `BitcoindJS.Module`, implementing the methods `blockHandler()`, `getAPIMethods()`, `getPublishEvents()` and any additional methods for querying the data. Here is an example:
A new module can be created by inheriting from `Node.Module`, implementing the methods `blockHandler()`, `getAPIMethods()`, `getPublishEvents()` and any additional methods for querying the data. Here is an example:
```js
var inherits = require('util').inherits;
var BitcoindJS = require('bitcoind.js');
var Node = require('bitcore-node').Node;
var MyModule = function(options) {
BitcoindJS.Module.call(this, options);
Node.Module.call(this, options);
};
inherits(MyModule, BitcoindJS.Module);
inherits(MyModule, Node.Module);
/**
* blockHandler
@ -195,13 +193,13 @@ The module can then be used when running a node:
```js
var configuration = {
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin',
datadir: process.env.BITCORENODE_DIR || '~/.bitcoin',
db: {
modules: [MyModule]
}
};
var node = new BitcoindJS.Node(configuration);
var node = new Node(configuration);
node.on('ready', function() {
node.getData('key', function(err, value) {
@ -210,7 +208,7 @@ node.on('ready', function() {
});
```
Note that if you already have a bitcoind.js database, and you want to query data from previous blocks in the blockchain, you will need to reindex. Reindexing right now means deleting your bitcoind.js database and resyncing.
Note that if you already have a bitcore-node database, and you want to query data from previous blocks in the blockchain, you will need to reindex. Reindexing right now means deleting your bitcore-node database and resyncing.
## Daemon Documentation
@ -290,7 +288,7 @@ Every effort will be made to ensure that this patch stays up-to-date with the la
There is a build script that will download Bitcoin Core v0.10.2 and apply the necessary patch, compile `libbitcoind.{so|dylib}` and copy the artifact into `platform/<os_dir>`. Unix/Linux uses the file extension "so" whereas Mac OSX uses "dylib" *(bitcoind compiled as a shared library)*.
```bash
$ cd /path/to/bitcoind.js
$ cd /path/to/bitcore-node
$ ./bin/build-libbitcoind
```
@ -327,10 +325,9 @@ $ cp -R libbitcoind/src/.libs/libbitcoind.*dylib platform/osx/lib
## License
Code released under [the MIT license](https://github.com/bitpay/bitcoind.js/blob/master/LICENSE).
Code released under [the MIT license](https://github.com/bitpay/bitcore-node/blob/master/LICENSE).
Copyright 2013-2015 BitPay, Inc.
- bitcoin: Copyright (c) 2009-2015 Bitcoin Core Developers (MIT License)
- bcoin (some code borrowed temporarily): Copyright Fedor Indutny, 2014.

View File

@ -64,12 +64,12 @@ compare_patch () {
}
debug=
if [ "${BITCOINDJS_ENV}" == "debug" ]; then
if [ "${BITCORENODE_ENV}" == "debug" ]; then
options=`cat ${root_dir}/bin/config_options_debug.sh`
fi
test=false
if [ "${BITCOINDJS_ENV}" == "test" ]; then
if [ "${BITCORENODE_ENV}" == "test" ]; then
test=true
options=`cat ${root_dir}/bin/config_options_test.sh`
fi
@ -96,7 +96,7 @@ if [ "${shared_file_built}" = false ]; then
${root_dir}/etc/bitcoin.patch."
echo -n "Would you like to remove the current patch, checkout the tag: ${tag} and \
apply the current patch from "${root_dir}"/etc/bitcoin.patch? (y/N): "
if [ "${BITCOINDJS_ASSUME_YES}" = true ]; then
if [ "${BITCORENODE_ASSUME_YES}" = true ]; then
input=y
echo ""
else

View File

@ -1,6 +1,6 @@
{
'targets': [{
'target_name': 'bitcoindjs',
'target_name': 'libbitcoind',
'include_dirs' : [
'<!(node -e "require(\'nan\')")',
'<!(./platform/os.sh artifacts_dir)/include/libbitcoind/src',
@ -8,7 +8,7 @@
'<!(./platform/os.sh artifacts_dir)/include/libbitcoind/src/leveldb/include'
],
'sources': [
'./src/bitcoindjs.cc',
'./src/libbitcoind.cc',
],
'conditions': [
['OS=="mac"', {

View File

@ -12,7 +12,7 @@ process.title = 'bitcoind.js';
* daemon
*/
var daemon = require('../').daemon({
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin',
datadir: process.env.BITCORENODE_DIR || '~/.bitcoin',
});
daemon.on('ready', function() {

View File

@ -7,7 +7,7 @@ var log = chainlib.log;
log.debug = function() {};
var configuration = {
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin'
datadir: process.env.BITCORENODE_DIR || '~/.bitcoin'
};
var node = new BitcoinNode(configuration);

View File

@ -1,6 +1,6 @@
'use strict';
module.exports = {};
module.exports = require('./lib/node');
module.exports.daemon = require('./lib/daemon');
module.exports.Node = require('./lib/node');
module.exports.Block = require('./lib/block');
@ -14,4 +14,4 @@ module.exports.modules = {};
module.exports.modules.AddressModule = require('./lib/modules/address');
module.exports.deps = {};
module.exports.deps.chainlib = require('chainlib');
module.exports.deps.chainlib = require('chainlib');

View File

@ -1 +0,0 @@
module.exports = require('./lib/bitcoind_stripped.js');

View File

@ -5,8 +5,8 @@
// 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');
if (process.env.BITCORENODE_ENV !== 'test') {
console.log('Please set the environment variable BITCORENODE_ENV=test and make sure bindings are compiled for testing');
process.exit();
}

View File

@ -1,6 +1,6 @@
var net = require('net');
var EventEmitter = require('events').EventEmitter;
var bitcoindjs = require('bindings')('bitcoindjs.node');
var bitcoind = require('bindings')('bitcoind.node');
var util = require('util');
var fs = require('fs');
var mkdirp = require('mkdirp');
@ -106,7 +106,7 @@ tiny.error = function() {};
tiny.prototype.error = function() {};
Daemon.db = tiny({
file: process.env.HOME + '/.bitcoindjs.db',
file: process.env.HOME + '/.bitcoind.db',
saveIndex: false,
initialCache: false
});
@ -146,7 +146,7 @@ Daemon.prototype.start = function(options, callback) {
}
});
bitcoindjs.start(options, function(err, status) {
bitcoind.start(options, function(err, status) {
self._started = true;
// Poll for queued packet
@ -199,22 +199,22 @@ Daemon.prototype.start = function(options, callback) {
self.stop();
});
bitcoindjs.onBlocksReady(function(err, result) {
bitcoind.onBlocksReady(function(err, result) {
function onTipUpdateListener(result) {
if (result) {
// Emit and event that the tip was updated
self.emit('tip', result);
// Recursively wait until the next update
bitcoindjs.onTipUpdate(onTipUpdateListener);
bitcoind.onTipUpdate(onTipUpdateListener);
}
}
bitcoindjs.onTipUpdate(onTipUpdateListener);
bitcoind.onTipUpdate(onTipUpdateListener);
self.emit('ready', result);
bitcoindjs.startTxMon(function(txs) {
bitcoind.startTxMon(function(txs) {
for(var i = 0; i < txs.length; i++) {
self.emit('tx', txs[i]);
}
@ -247,12 +247,12 @@ Daemon.prototype.start = function(options, callback) {
// 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()) {
if (!self._stoppingSaid && bitcoind.stopping()) {
self._stoppingSaid = true;
self.log('shutting down...');
}
if (bitcoindjs.stopped()) {
if (bitcoind.stopped()) {
self.log('shut down.');
clearInterval(self._shutdown);
@ -281,7 +281,7 @@ Daemon.prototype.start = function(options, callback) {
Daemon.prototype.getBlock = function(blockhash, callback) {
if (daemon.stopping) return [];
return bitcoindjs.getBlock(blockhash, function(err, block) {
return bitcoind.getBlock(blockhash, function(err, block) {
if (err) return callback(err);
return callback(null, block);
});
@ -289,30 +289,30 @@ Daemon.prototype.getBlock = function(blockhash, callback) {
Daemon.prototype.getBlockHeight = function(height, callback) {
if (daemon.stopping) return [];
return bitcoindjs.getBlock(+height, function(err, block) {
return bitcoind.getBlock(+height, function(err, block) {
if (err) return callback(err);
return callback(null, daemon.block(block));
});
};
Daemon.prototype.isSpent = function(txid, outputIndex) {
return bitcoindjs.isSpent(txid, outputIndex);
return bitcoind.isSpent(txid, outputIndex);
};
Daemon.prototype.getBlockIndex = function(blockHash) {
return bitcoindjs.getBlockIndex(blockHash);
return bitcoind.getBlockIndex(blockHash);
};
Daemon.prototype.estimateFee = function(blocks) {
return bitcoindjs.estimateFee(blocks);
return bitcoind.estimateFee(blocks);
};
Daemon.prototype.sendTransaction = function(transaction, allowAbsurdFees) {
return bitcoindjs.sendTransaction(transaction, allowAbsurdFees);
return bitcoind.sendTransaction(transaction, allowAbsurdFees);
};
Daemon.prototype.getTransaction = function(txid, queryMempool, callback) {
return bitcoindjs.getTransaction(txid, queryMempool, callback);
return bitcoind.getTransaction(txid, queryMempool, callback);
};
Daemon.prototype.getTransactionWithBlock = function(txid, blockhash, callback) {
@ -345,7 +345,7 @@ Daemon.prototype.getTransactionWithBlock = function(txid, blockhash, callback) {
}
}
return bitcoindjs.getTransaction(txid, blockhash, function(err, tx) {
return bitcoind.getTransaction(txid, blockhash, function(err, tx) {
if (err) return callback(err);
if (slow && !tx.blockhash) {
@ -355,7 +355,7 @@ Daemon.prototype.getTransactionWithBlock = function(txid, blockhash, callback) {
});
}
return bitcoindjs.getBlock(tx.blockhash, function(err, block) {
return bitcoind.getBlock(tx.blockhash, function(err, block) {
if (err) return callback(err);
return callback(null, daemon.tx(tx), daemon.block(block));
});
@ -363,49 +363,49 @@ Daemon.prototype.getTransactionWithBlock = function(txid, blockhash, callback) {
};
Daemon.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback) {
return bitcoindjs.getTransactionWithBlockInfo(txid, queryMempool, callback);
return bitcoind.getTransactionWithBlockInfo(txid, queryMempool, callback);
};
Daemon.prototype.getMempoolOutputs = function(address) {
return bitcoindjs.getMempoolOutputs(address);
return bitcoind.getMempoolOutputs(address);
};
Daemon.prototype.addMempoolUncheckedTransaction = function(txBuffer) {
return bitcoindjs.addMempoolUncheckedTransaction(txBuffer);
return bitcoind.addMempoolUncheckedTransaction(txBuffer);
};
Daemon.prototype.getInfo = function() {
if (daemon.stopping) return [];
return bitcoindjs.getInfo();
return bitcoind.getInfo();
};
Daemon.prototype.getPeerInfo = function() {
if (daemon.stopping) return [];
return bitcoindjs.getPeerInfo();
return bitcoind.getPeerInfo();
};
Daemon.prototype.getAddresses = function() {
if (daemon.stopping) return [];
return bitcoindjs.getAddresses();
return bitcoind.getAddresses();
};
Daemon.prototype.getProgress = function(callback) {
return bitcoindjs.getProgress(callback);
return bitcoind.getProgress(callback);
};
Daemon.prototype.setGenerate = function(options) {
if (daemon.stopping) return [];
return bitcoindjs.setGenerate(options || {});
return bitcoind.setGenerate(options || {});
};
Daemon.prototype.getGenerate = function(options) {
if (daemon.stopping) return [];
return bitcoindjs.getGenerate(options || {});
return bitcoind.getGenerate(options || {});
};
Daemon.prototype.getMiningInfo = function() {
if (daemon.stopping) return [];
return bitcoindjs.getMiningInfo();
return bitcoind.getMiningInfo();
};
Daemon.prototype.getAddrTransactions = function(address, callback) {
@ -424,7 +424,7 @@ Daemon.prototype.getAddrTransactions = function(address, callback) {
: out;
}, -1)
};
return bitcoindjs.getAddrTransactions(options, function(err, addr) {
return bitcoind.getAddrTransactions(options, function(err, addr) {
if (err) return callback(err);
addr = daemon.addr(addr);
if (addr.tx[0] && !addr.tx[0].vout[0]) {
@ -461,13 +461,13 @@ Daemon.prototype.getAddrTransactions = function(address, callback) {
Daemon.prototype.getBestBlock = function(callback) {
if (daemon.stopping) return [];
var hash = bitcoindjs.getBestBlock();
return bitcoindjs.getBlock(hash, callback);
var hash = bitcoind.getBestBlock();
return bitcoind.getBlock(hash, callback);
};
Daemon.prototype.getChainHeight = function() {
if (daemon.stopping) return [];
return bitcoindjs.getChainHeight();
return bitcoind.getChainHeight();
};
Daemon.prototype.__defineGetter__('chainHeight', function() {
@ -488,7 +488,7 @@ Daemon.prototype.getBlockByTx = function(txid, callback) {
return callback(null, block, tx_);
});
}
return bitcoindjs.getBlockByTx(txid, function(err, block, tx_) {
return bitcoind.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_));
@ -499,7 +499,7 @@ Daemon.prototype.getBlockByTx = function(txid, callback) {
Daemon.prototype.getBlocksByDate =
Daemon.prototype.getBlocksByTime = function(options, callback) {
if (daemon.stopping) return [];
return bitcoindjs.getBlocksByTime(options, function(err, blocks) {
return bitcoind.getBlocksByTime(options, function(err, blocks) {
if (err) return callback(err);
return callback(null, blocks.map(function(block) {
return daemon.block(block);
@ -509,7 +509,7 @@ Daemon.prototype.getBlocksByTime = function(options, callback) {
Daemon.prototype.getFromTx = function(txid, callback) {
if (daemon.stopping) return [];
return bitcoindjs.getFromTx(txid, function(err, txs) {
return bitcoind.getFromTx(txid, function(err, txs) {
if (err) return callback(err);
return callback(null, txs.map(function(tx) {
return daemon.tx(tx)
@ -519,7 +519,7 @@ Daemon.prototype.getFromTx = function(txid, callback) {
Daemon.prototype.getLastFileIndex = function() {
if (daemon.stopping) return [];
return bitcoindjs.getLastFileIndex();
return bitcoind.getLastFileIndex();
};
Daemon.prototype.log =
@ -549,7 +549,7 @@ Daemon.prototype.stop =
Daemon.prototype.close = function(callback) {
if (daemon.stopping) return [];
var self = this;
return bitcoindjs.stop(function(err, status) {
return bitcoind.stop(function(err, status) {
if (err) {
self.error(err.message);
} else {
@ -561,19 +561,19 @@ Daemon.prototype.close = function(callback) {
};
Daemon.prototype.__defineGetter__('stopping', function() {
return bitcoindjs.stopping() || bitcoindjs.stopped();
return bitcoind.stopping() || bitcoind.stopped();
});
Daemon.prototype.__defineGetter__('stopped', function() {
return bitcoindjs.stopped();
return bitcoind.stopped();
});
Daemon.__defineGetter__('stopping', function() {
return bitcoindjs.stopping() || bitcoindjs.stopped();
return bitcoind.stopping() || bitcoind.stopped();
});
Daemon.__defineGetter__('stopped', function() {
return bitcoindjs.stopped();
return bitcoind.stopped();
});
/**
@ -627,12 +627,12 @@ Block.isBlock = function(block) {
Block.fromHex = function(hex) {
if (daemon.stopping) return [];
return daemon.block(bitcoindjs.blockFromHex(hex));
return daemon.block(bitcoind.blockFromHex(hex));
};
Block.prototype.getHash = function(enc) {
if (daemon.stopping) return [];
var data = bitcoindjs.getBlockHex(this);
var data = bitcoind.getBlockHex(this);
if (!this.hash || this.hash !== data.hash) {
this.hash = data.hash;
}
@ -644,7 +644,7 @@ Block.prototype.getHash = function(enc) {
Block.prototype.verify = function() {
if (daemon.stopping) return [];
return this.verified = this.verified || bitcoindjs.verifyBlock(this);
return this.verified = this.verified || bitcoind.verifyBlock(this);
};
Block.prototype.toHex = function() {
@ -658,7 +658,7 @@ Block.prototype.toHex = function() {
Block.toHex = function(block) {
if (daemon.stopping) return [];
var data = bitcoindjs.getBlockHex(block);
var data = bitcoind.getBlockHex(block);
return data.hex;
};
@ -669,7 +669,7 @@ Block.prototype.toBinary = function() {
Block.toBinary = function(block) {
if (daemon.stopping) return [];
var data = bitcoindjs.getBlockHex(block);
var data = bitcoind.getBlockHex(block);
return new Buffer(data.hex, 'hex');
};
@ -721,12 +721,12 @@ Transaction.isTx = function(tx) {
Transaction.fromHex = function(hex) {
if (daemon.stopping) return [];
return daemon.tx(bitcoindjs.txFromHex(hex));
return daemon.tx(bitcoind.txFromHex(hex));
};
Transaction.prototype.verify = function() {
if (daemon.stopping) return [];
return this.verified = this.verified || bitcoindjs.verifyTransaction(this);
return this.verified = this.verified || bitcoind.verifyTransaction(this);
};
Transaction.prototype.sign =
@ -746,7 +746,7 @@ Transaction.fill = function(tx, options) {
}
try {
newTx = bitcoindjs.fillTransaction(tx, options || {});
newTx = bitcoind.fillTransaction(tx, options || {});
} catch (e) {
return false;
}
@ -760,7 +760,7 @@ Transaction.fill = function(tx, options) {
Transaction.prototype.getHash = function(enc) {
if (daemon.stopping) return [];
var data = bitcoindjs.getTxHex(this);
var data = bitcoind.getTxHex(this);
if (!this.txid || this.txid !== data.hash) {
this.txid = data.hash;
}
@ -786,7 +786,7 @@ Transaction.prototype.toHex = function() {
Transaction.toHex = function(tx) {
if (daemon.stopping) return [];
var data = bitcoindjs.getTxHex(tx);
var data = bitcoind.getTxHex(tx);
return data.hex;
};
@ -797,7 +797,7 @@ Transaction.prototype.toBinary = function() {
Transaction.toBinary = function(tx) {
if (daemon.stopping) return [];
var data = bitcoindjs.getTxHex(tx);
var data = bitcoind.getTxHex(tx);
return new Buffer(data.hex, 'hex');
};
@ -827,7 +827,7 @@ Transaction.broadcast = function(tx, options, callback) {
tx = daemon.tx(tx);
}
return bitcoindjs.broadcastTx(tx, fee, own, function(err, hash, tx) {
return bitcoind.broadcastTx(tx, fee, own, function(err, hash, tx) {
if (err) {
if (callback === utils.NOOP) {
daemon.global.emit('error', err);
@ -917,8 +917,8 @@ exports.Daemon = daemon;
exports.daemon = daemon;
exports.bitcoind = daemon;
exports.native = bitcoindjs;
exports.bitcoindjs = bitcoindjs;
exports.native = bitcoind;
exports.bitcoind = bitcoind;
exports.Block = Block;
exports.block = Block;

View File

@ -1,13 +1,13 @@
{
"name": "bitcoind.js",
"description": "Node binding for bitcoind",
"name": "bitcore-node",
"description": "Full node with extended capabilities using Bitcore and Bitcoin Core",
"author": "BitPay <dev@bitpay.com>",
"version": "0.0.8",
"version": "0.2.0",
"main": "./index.js",
"repository": "git://github.com/bitpay/bitcoind.js.git",
"homepage": "https://github.com/bitpay/bitcoind.js",
"repository": "git://github.com/bitpay/bitcore-node.git",
"homepage": "https://github.com/bitpay/bitcore-node.js",
"bugs": {
"url": "https://github.com/bitpay/bitcoind.js/issues"
"url": "https://github.com/bitpay/bitcore-node/issues"
},
"contributors": [
{

View File

@ -1,517 +0,0 @@
/**
* bitcoind.js - a binding for node.js which links to libbitcoind.so/dylib.
* Copyright (c) 2015, BitPay (MIT License)
*
* bitcoindjs.cc:
* A bitcoind node.js binding.
*/
#include "bitcoindjs_stripped.h"
using namespace std;
using namespace boost;
using namespace node;
using namespace v8;
/**
* Bitcoin Globals
*/
// These global functions and variables are
// required to be defined/exposed here.
extern void DetectShutdownThread(boost::thread_group*);
extern int nScriptCheckThreads;
static termios orig_termios;
/**
* Node.js Internal Function Templates
*/
static void
async_start_node(uv_work_t *req);
static void
async_start_node_after(uv_work_t *req);
static void
async_stop_node(uv_work_t *req);
static void
async_stop_node_after(uv_work_t *req);
static int
start_node(void);
static void
start_node_thread(void);
extern "C" void
init(Handle<Object>);
/**
* Private Global Variables
* Used only by bitcoindjs functions.
*/
static volatile bool shutdown_complete = false;
static char *g_data_dir = NULL;
static bool g_rpc = false;
static bool g_testnet = false;
static bool g_txindex = false;
/**
* Private Structs
* Used for async functions and necessary linked lists at points.
*/
/**
* async_node_data
* Where the uv async request data resides.
*/
struct async_node_data {
std::string err_msg;
std::string result;
std::string datadir;
bool rpc;
bool testnet;
bool txindex;
Eternal<Function> callback;
};
/**
* Helpers
*/
static bool
set_cooked(void);
/**
* Functions
*/
/**
* StartBitcoind()
* bitcoind.start(callback)
* Start the bitcoind node with AppInit2() on a separate thread.
*/
NAN_METHOD(StartBitcoind) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
Local<Function> callback;
std::string datadir = std::string("");
bool rpc = false;
bool testnet = false;
bool txindex = false;
if (args.Length() >= 2 && args[0]->IsObject() && args[1]->IsFunction()) {
Local<Object> options = Local<Object>::Cast(args[0]);
if (options->Get(NanNew<String>("datadir"))->IsString()) {
String::Utf8Value datadir_(options->Get(NanNew<String>("datadir"))->ToString());
datadir = std::string(*datadir_);
}
if (options->Get(NanNew<String>("rpc"))->IsBoolean()) {
rpc = options->Get(NanNew<String>("rpc"))->ToBoolean()->IsTrue();
}
if (options->Get(NanNew<String>("testnet"))->IsBoolean()) {
testnet = options->Get(NanNew<String>("testnet"))->ToBoolean()->IsTrue();
}
if (options->Get(NanNew<String>("txindex"))->IsBoolean()) {
txindex = options->Get(NanNew<String>("txindex"))->ToBoolean()->IsTrue();
}
callback = Local<Function>::Cast(args[1]);
} else if (args.Length() >= 2
&& (args[0]->IsUndefined() || args[0]->IsNull())
&& args[1]->IsFunction()) {
callback = Local<Function>::Cast(args[1]);
} else if (args.Length() >= 1 && args[0]->IsFunction()) {
callback = Local<Function>::Cast(args[0]);
} else {
return NanThrowError(
"Usage: bitcoind.start(callback)");
}
//
// Run bitcoind's StartNode() on a separate thread.
//
async_node_data *data = new async_node_data();
data->err_msg = std::string("");
data->result = std::string("");
data->datadir = datadir;
data->rpc = rpc;
data->testnet = testnet;
data->txindex = txindex;
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_start_node,
(uv_after_work_cb)async_start_node_after);
assert(status == 0);
NanReturnValue(Undefined(isolate));
}
/**
* async_start_node()
* Call start_node() and start all our boost threads.
*/
static void
async_start_node(uv_work_t *req) {
async_node_data *data = static_cast<async_node_data*>(req->data);
if (data->datadir != "") {
g_data_dir = (char *)data->datadir.c_str();
} else {
g_data_dir = (char *)malloc(sizeof(char) * 512);
snprintf(g_data_dir, sizeof(char) * 512, "%s/.bitcoind.js", getenv("HOME"));
}
g_rpc = (bool)data->rpc;
g_testnet = (bool)data->testnet;
g_txindex = (bool)data->txindex;
tcgetattr(STDIN_FILENO, &orig_termios);
start_node();
data->result = std::string("bitcoind opened.");
}
/**
* async_start_node_after()
* Execute our callback.
*/
static void
async_start_node_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
async_node_data *data = static_cast<async_node_data*>(req->data);
Local<Function> cb = data->callback.Get(isolate);
if (data->err_msg != "") {
Local<Value> err = Exception::Error(NanNew<String>(data->err_msg));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
v8::Null(isolate),
Local<Value>::New(isolate, NanNew<String>(data->result))
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
delete data;
delete req;
}
/**
* start_node(void)
* Start AppInit2() on a separate thread, wait for
* Unfortunately, we need to wait for the initialization
* to unhook the signal handlers so we can use them
* from node.js in javascript.
*/
static int
start_node(void) {
SetupEnvironment();
noui_connect();
new boost::thread(boost::bind(&start_node_thread));
// Drop the bitcoind signal handlers: we want our own.
signal(SIGINT, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
// Hook into packet handling
//new boost::thread(boost::bind(&hook_packets));
return 0;
}
static void
start_node_thread(void) {
boost::thread_group threadGroup;
boost::thread* detectShutdownThread = NULL;
// Workaround for AppInit2() arg parsing. Not ideal, but it works.
int argc = 0;
char **argv = (char **)malloc((4 + 1) * sizeof(char **));
argv[argc] = (char *)"bitcoind";
argc++;
if (g_data_dir) {
const int argl = 9 + strlen(g_data_dir) + 1;
char *arg = (char *)malloc(sizeof(char) * argl);
int w = snprintf(arg, argl, "-datadir=%s", g_data_dir);
if (w >= 10 && w <= argl) {
arg[w] = '\0';
argv[argc] = arg;
argc++;
} else {
if (set_cooked()) {
fprintf(stderr, "bitcoind.js: Bad -datadir value.\n");
}
}
}
if (g_rpc) {
argv[argc] = (char *)"-server";
argc++;
}
if (g_testnet) {
argv[argc] = (char *)"-testnet";
argc++;
}
if (g_txindex) {
argv[argc] = (char *)"-txindex";
argc++;
}
argv[argc] = NULL;
bool fRet = false;
try {
ParseParameters((const int)argc, (const char **)argv);
if (!boost::filesystem::is_directory(GetDataDir(false))) {
if (set_cooked()) {
fprintf(stderr,
"bitcoind.js: Specified data directory \"%s\" does not exist.\n",
mapArgs["-datadir"].c_str());
}
shutdown_complete = true;
_exit(1);
return;
}
try {
ReadConfigFile(mapArgs, mapMultiArgs);
} catch(std::exception &e) {
if (set_cooked()) {
fprintf(stderr,
"bitcoind.js: Error reading configuration file: %s\n", e.what());
}
shutdown_complete = true;
_exit(1);
return;
}
if (!SelectParamsFromCommandLine()) {
if (set_cooked()) {
fprintf(stderr,
"bitcoind.js: Invalid combination of -regtest and -testnet.\n");
}
shutdown_complete = true;
_exit(1);
return;
}
CreatePidFile(GetPidFile(), getpid());
detectShutdownThread = new boost::thread(
boost::bind(&DetectShutdownThread, &threadGroup));
fRet = AppInit2(threadGroup);
} catch (std::exception& e) {
if (set_cooked()) {
fprintf(stderr, "bitcoind.js: AppInit(): std::exception\n");
}
} catch (...) {
if (set_cooked()) {
fprintf(stderr, "bitcoind.js: AppInit(): other exception\n");
}
}
if (!fRet) {
if (detectShutdownThread) {
detectShutdownThread->interrupt();
}
threadGroup.interrupt_all();
}
if (detectShutdownThread) {
detectShutdownThread->join();
delete detectShutdownThread;
detectShutdownThread = NULL;
}
Shutdown();
// bitcoind is shutdown. Notify the main thread
// which is polling this variable:
shutdown_complete = true;
}
/**
* StopBitcoind()
* bitcoind.stop(callback)
*/
NAN_METHOD(StopBitcoind) {
fprintf(stderr, "Stopping Bitcoind please wait!");
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
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 = new async_node_data();
data->err_msg = std::string("");
data->result = std::string("");
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_stop_node,
(uv_after_work_cb)async_stop_node_after);
assert(status == 0);
NanReturnValue(Undefined(isolate));
}
/**
* async_stop_node()
* Call StartShutdown() to join the boost threads, which will call Shutdown()
* and set shutdown_complete to true to notify the main node.js thread.
*/
static void
async_stop_node(uv_work_t *req) {
async_node_data *data = static_cast<async_node_data*>(req->data);
StartShutdown();
data->result = std::string("bitcoind shutdown.");
}
/**
* async_stop_node_after()
* Execute our callback.
*/
static void
async_stop_node_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
async_node_data* data = static_cast<async_node_data*>(req->data);
Local<Function> cb = data->callback.Get(isolate);
if (data->err_msg != "") {
Local<Value> err = Exception::Error(NanNew<String>(data->err_msg));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(isolate, NanNull()),
Local<Value>::New(isolate, NanNew<String>(data->result))
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
delete data;
delete req;
}
/**
* IsStopping()
* bitcoind.stopping()
* Check whether bitcoind is in the process of shutting down. This is polled
* from javascript.
*/
NAN_METHOD(IsStopping) {
NanScope();
NanReturnValue(NanNew<Boolean>(ShutdownRequested()));
}
/**
* IsStopped()
* bitcoind.stopped()
* Check whether bitcoind has shutdown completely. This will be polled by
* javascript to check whether the libuv event loop is safe to stop.
*/
NAN_METHOD(IsStopped) {
NanScope();
NanReturnValue(NanNew<Boolean>(shutdown_complete));
}
/**
* Helpers
*/
static bool
set_cooked(void) {
uv_tty_t tty;
tty.mode = 1;
tty.orig_termios = orig_termios;
if (!uv_tty_set_mode(&tty, 0)) {
printf("\x1b[H\x1b[J");
return true;
}
return false;
}
/**
* Init()
* Initialize the singleton object known as bitcoindjs.
*/
extern "C" void
init(Handle<Object> target) {
NanScope();
NODE_SET_METHOD(target, "start", StartBitcoind);
NODE_SET_METHOD(target, "stop", StopBitcoind);
NODE_SET_METHOD(target, "stopping", IsStopping);
NODE_SET_METHOD(target, "stopped", IsStopped);
}
NODE_MODULE(bitcoindjs, init)

View File

@ -1,19 +0,0 @@
/**
* bitcoind.js
* Copyright (c) 2014, BitPay (MIT License)
*
* bitcoindjs.h:
* A bitcoind node.js binding header file.
*/
#include "nan.h"
#include "addrman.h"
#include "base58.h"
#include "init.h"
#include "noui.h"
#include <boost/thread.hpp>
#include <boost/filesystem.hpp>
NAN_METHOD(StartBitcoind);
NAN_METHOD(IsStopping);
NAN_METHOD(IsStopped);
NAN_METHOD(StopBitcoind);

View File

@ -6,7 +6,7 @@
* A bitcoind node.js binding.
*/
#include "bitcoindjs.h"
#include "libbitcoind.h"
using namespace std;
using namespace boost;
@ -1634,4 +1634,4 @@ init(Handle<Object> target) {
}
NODE_MODULE(bitcoindjs, init)
NODE_MODULE(libbitcoind, init)