bitcore-node-zcash/src/bitcoindjs.cc

1054 lines
29 KiB
C++
Raw Normal View History

2014-08-12 12:03:04 -07:00
/**
* bitcoind.js
* Copyright (c) 2014, BitPay (MIT License)
*
* bitcoindjs.cc:
* A bitcoind node.js binding.
*/
#include "nan.h"
#include "bitcoindjs.h"
2014-08-20 17:00:09 -07:00
/**
* Bitcoin headers
*/
2014-09-17 12:14:20 -07:00
#if defined(HAVE_CONFIG_H)
#include "bitcoin-config.h"
#endif
#include "core.h"
#include "addrman.h"
#include "checkpoints.h"
#include "crypter.h"
#include "main.h"
// #include "random.h"
// #include "timedata.h"
2014-09-17 12:14:20 -07:00
#ifdef ENABLE_WALLET
#include "db.h"
#include "wallet.h"
#include "walletdb.h"
2014-09-17 12:14:20 -07:00
#endif
// #include "walletdb.h"
#include "alert.h"
#include "checkqueue.h"
2014-09-17 12:14:20 -07:00
// #include "db.h"
#include "miner.h"
#include "rpcclient.h"
#include "tinyformat.h"
2014-09-17 12:14:20 -07:00
// #include "wallet.h"
#include "allocators.h"
#include "clientversion.h"
#include "hash.h"
#include "mruset.h"
#include "rpcprotocol.h"
#include "txdb.h"
#include "base58.h"
#include "coincontrol.h"
#include "init.h"
#include "netbase.h"
#include "rpcserver.h"
#include "txmempool.h"
#include "bloom.h"
#include "coins.h"
#include "key.h"
#include "net.h"
#include "script.h"
#include "ui_interface.h"
// #include "chainparamsbase.h"
#include "compat.h"
#include "keystore.h"
#include "noui.h"
#include "serialize.h"
#include "uint256.h"
#include "chainparams.h"
#include "core.h"
#include "leveldbwrapper.h"
// #include "pow.h"
#include "sync.h"
#include "util.h"
// #include "chainparamsseeds.h"
// #include "core_io.h"
#include "limitedmap.h"
#include "protocol.h"
#include "threadsafety.h"
#include "version.h"
2014-08-20 17:00:09 -07:00
/**
* Bitcoin Globals
* Relevant:
* ~/bitcoin/src/init.cpp
* ~/bitcoin/src/bitcoind.cpp
* ~/bitcoin/src/main.h
*/
2014-09-17 12:14:20 -07:00
#include <stdint.h>
#include <signal.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include <openssl/crypto.h>
#define MIN_CORE_FILEDESCRIPTORS 150
using namespace std;
using namespace boost;
2014-09-17 11:23:38 -07:00
extern void ThreadImport(std::vector<boost::filesystem::path>);
extern void DetectShutdownThread(boost::thread_group*);
extern void StartNode(boost::thread_group&);
extern void ThreadScriptCheck();
extern void StartShutdown();
2014-09-17 14:08:26 -07:00
extern bool ShutdownRequested();
2014-09-17 11:23:38 -07:00
extern bool AppInit2(boost::thread_group&);
extern bool AppInit(int, char**);
extern bool SoftSetBoolArg(const std::string&, bool);
extern void PrintExceptionContinue(std::exception*, const char*);
extern void Shutdown();
2014-09-12 18:13:21 -07:00
extern void noui_connect();
extern int nScriptCheckThreads;
2014-09-12 18:13:21 -07:00
extern bool fDaemon;
2014-09-12 15:44:57 -07:00
extern std::map<std::string, std::string> mapArgs;
2014-08-20 17:00:09 -07:00
#ifdef ENABLE_WALLET
extern std::string strWalletFile;
extern CWallet *pwalletMain;
#endif
#include <node.h>
#include <string>
2014-08-12 12:03:04 -07:00
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
using namespace node;
using namespace v8;
NAN_METHOD(StartBitcoind);
2014-09-19 13:53:55 -07:00
NAN_METHOD(IsStopping);
NAN_METHOD(IsStopped);
NAN_METHOD(StopBitcoind);
NAN_METHOD(GetBlock);
2014-08-12 12:03:04 -07:00
static void
async_start_node_work(uv_work_t *req);
static void
async_start_node_after(uv_work_t *req);
2014-08-12 12:03:04 -07:00
2014-09-11 17:18:36 -07:00
static void
async_stop_node_work(uv_work_t *req);
static void
async_stop_node_after(uv_work_t *req);
static int
start_node(void);
2014-09-17 14:08:26 -07:00
static void
start_node_thread(void);
2014-09-17 12:52:35 -07:00
2014-09-18 14:57:03 -07:00
#if OUTPUT_REDIR
static void
open_pipes(int **out_pipe, int **log_pipe);
static void
parse_logs(int **out_pipe, int **log_pipe);
static void
async_parse_logs(uv_work_t *req);
static void
async_parse_logs_after(uv_work_t *req);
2014-09-18 14:57:03 -07:00
#endif
2014-09-19 13:53:55 -07:00
static void
async_get_block(uv_work_t *req);
static void
async_get_block_after(uv_work_t *req);
2014-08-12 12:03:04 -07:00
extern "C" void
init(Handle<Object>);
static volatile bool shutdownComplete = false;
2014-09-19 13:53:55 -07:00
/**
* async_block_data
*/
struct async_block_data {
std::string hash;
std::string err_msg;
2014-09-19 15:39:05 -07:00
CBlock result_block;
CBlockIndex* result_blockindex;
2014-09-19 13:53:55 -07:00
Persistent<Function> callback;
};
2014-08-20 17:00:09 -07:00
/**
* async_node_data
2014-08-20 17:00:09 -07:00
* Where the uv async request data resides.
*/
struct async_node_data {
char *err_msg;
char *result;
2014-09-04 15:16:32 -07:00
Persistent<Function> callback;
};
/**
* async_log_data
* Where the uv async request data resides.
*/
struct async_log_data {
int **out_pipe;
int **log_pipe;
char *err_msg;
char *result;
2014-09-04 15:16:32 -07:00
Persistent<Function> callback;
};
2014-08-12 12:03:04 -07:00
/**
* StartBitcoind
* bitcoind.start(callback)
*/
NAN_METHOD(StartBitcoind) {
NanScope();
if (args.Length() < 1 || !args[0]->IsFunction()) {
return NanThrowError(
"Usage: bitcoind.start(callback)");
}
Local<Function> callback = Local<Function>::Cast(args[0]);
//
// Setup pipes to differentiate our logs from bitcoind's.
// Run in a separate thread.
//
2014-09-17 14:08:26 -07:00
#if OUTPUT_REDIR
int *out_pipe = (int *)malloc(2 * sizeof(int));
int *log_pipe = (int *)malloc(2 * sizeof(int));
open_pipes(&out_pipe, &log_pipe);
uv_work_t *req_parse_logs = new uv_work_t();
async_log_data* data_parse_logs = new async_log_data();
data_parse_logs->out_pipe = &out_pipe;
data_parse_logs->log_pipe = &log_pipe;
2014-09-04 15:16:32 -07:00
data_parse_logs->err_msg = NULL;
data_parse_logs->result = NULL;
data_parse_logs->callback = Persistent<Function>::New(callback);
req_parse_logs->data = data_parse_logs;
2014-09-17 14:08:26 -07:00
int status_parse_logs = uv_queue_work(uv_default_loop(),
req_parse_logs, async_parse_logs,
(uv_after_work_cb)async_parse_logs_after);
2014-09-17 14:08:26 -07:00
assert(status_parse_logs == 0);
2014-09-02 19:29:36 -07:00
#endif
//
// Run bitcoind's StartNode() on a separate thread.
//
2014-09-19 15:39:05 -07:00
async_node_data *data_start_node = new async_node_data();
2014-09-04 15:16:32 -07:00
data_start_node->err_msg = NULL;
data_start_node->result = NULL;
data_start_node->callback = Persistent<Function>::New(callback);
uv_work_t *req_start_node = new uv_work_t();
req_start_node->data = data_start_node;
int status_start_node = uv_queue_work(uv_default_loop(),
req_start_node, async_start_node_work,
(uv_after_work_cb)async_start_node_after);
assert(status_start_node == 0);
2014-08-12 12:03:04 -07:00
2014-09-17 14:08:26 -07:00
#if OUTPUT_REDIR
2014-09-02 19:28:20 -07:00
NanReturnValue(NanNew<Number>(log_pipe[1]));
2014-09-17 14:08:26 -07:00
#else
NanReturnValue(NanNew<Number>(-1));
#endif
2014-08-12 12:03:04 -07:00
}
2014-08-20 17:00:09 -07:00
/**
* async_start_node_work()
2014-08-20 17:00:09 -07:00
* Call start_node() and start all our boost threads.
*/
static void
async_start_node_work(uv_work_t *req) {
2014-09-19 15:39:05 -07:00
async_node_data *node_data = static_cast<async_node_data*>(req->data);
2014-09-05 15:07:38 -07:00
start_node();
node_data->result = (char *)strdup("start_node(): bitcoind opened.");
}
2014-08-20 17:00:09 -07:00
/**
* async_start_node_after()
2014-08-20 17:00:09 -07:00
* Execute our callback.
*/
static void
async_start_node_after(uv_work_t *req) {
NanScope();
2014-09-19 15:39:05 -07:00
async_node_data *node_data = static_cast<async_node_data*>(req->data);
2014-09-04 15:16:32 -07:00
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);
}
}
2014-09-04 15:16:32 -07:00
// node_data->callback.Dispose();
if (node_data->result != NULL) {
free(node_data->result);
}
2014-08-12 12:03:04 -07:00
delete node_data;
delete req;
2014-08-12 12:03:04 -07:00
}
2014-09-17 14:08:26 -07:00
/**
* IsStopping()
* bitcoind.stopping()
*/
NAN_METHOD(IsStopping) {
NanScope();
NanReturnValue(NanNew<Boolean>(ShutdownRequested()));
}
2014-09-17 12:52:35 -07:00
/**
* IsStopped()
* bitcoind.stopped()
*/
2014-09-17 14:08:26 -07:00
NAN_METHOD(IsStopped) {
2014-09-17 12:52:35 -07:00
NanScope();
2014-09-17 14:08:26 -07:00
NanReturnValue(NanNew<Boolean>(shutdownComplete));
2014-09-17 12:52:35 -07:00
}
2014-08-20 17:00:09 -07:00
/**
* start_node(void)
2014-09-17 14:08:26 -07:00
* start_node_thread(void)
2014-08-20 17:00:09 -07:00
* A reimplementation of AppInit2 minus
* the logging and argument parsing.
*/
static int
start_node(void) {
2014-09-17 12:14:20 -07:00
noui_connect();
2014-09-17 14:08:26 -07:00
(boost::thread *)new boost::thread(boost::bind(&start_node_thread));
2014-09-17 12:14:20 -07:00
2014-09-17 14:08:26 -07:00
// horrible fix for a race condition
sleep(2);
signal(SIGINT, SIG_DFL);
signal(SIGHUP, SIG_DFL);
2014-09-17 12:14:20 -07:00
2014-09-17 12:52:35 -07:00
return 0;
}
2014-09-17 12:14:20 -07:00
2014-09-17 14:08:26 -07:00
static void
start_node_thread(void) {
2014-09-17 12:52:35 -07:00
boost::thread_group threadGroup;
2014-09-19 15:39:05 -07:00
boost::thread *detectShutdownThread = NULL;
2014-09-17 12:14:20 -07:00
2014-09-17 12:52:35 -07:00
const int argc = 0;
const char *argv[argc + 1] = {
//"-server",
NULL
};
ParseParameters(argc, argv);
ReadConfigFile(mapArgs, mapMultiArgs);
if (!SelectParamsFromCommandLine()) {
2014-09-17 14:08:26 -07:00
return;
2014-09-17 12:14:20 -07:00
}
2014-09-17 12:52:35 -07:00
// CreatePidFile(GetPidFile(), getpid());
detectShutdownThread = new boost::thread(
boost::bind(&DetectShutdownThread, &threadGroup));
2014-09-17 12:14:20 -07:00
2014-09-17 12:52:35 -07:00
int fRet = AppInit2(threadGroup);
2014-09-17 12:14:20 -07:00
if (!fRet) {
if (detectShutdownThread)
detectShutdownThread->interrupt();
threadGroup.interrupt_all();
}
if (detectShutdownThread) {
detectShutdownThread->join();
delete detectShutdownThread;
detectShutdownThread = NULL;
}
Shutdown();
2014-09-17 14:08:26 -07:00
shutdownComplete = true;
}
2014-09-18 14:57:03 -07:00
#if OUTPUT_REDIR
/**
* parse_logs(int **out_pipe, int **log_pipe)
* Differentiate our logs and bitcoind's logs.
* Send bitcoind's logs to a pipe instead.
*/
const char bitcoind_char[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2014-09-17 14:31:20 -07:00
0, 0, 0, 0, 0, 0, 0, /* <- ' ' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '.',
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ':', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2014-09-17 14:31:20 -07:00
'b', 'c', 'd', 0, 0, 0, 0, 'i', 'j', 0, 0, 0, 'n', 'o', 0, 0, 0, 's', 't', 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2014-09-17 14:31:20 -07:00
0, 0, 0, 0, 0, 0, 0, 0,
};
static void
open_pipes(int **out_pipe, int **log_pipe) {
pipe(*out_pipe);
2014-09-17 15:33:21 -07:00
dup2((*out_pipe)[1], STDOUT_FILENO);
dup2((*out_pipe)[1], STDERR_FILENO);
pipe(*log_pipe);
}
static void
parse_logs(int **out_pipe, int **log_pipe) {
unsigned int rtotal = 0;
ssize_t r = 0;
size_t rcount = 80 * sizeof(char);
char *buf = (char *)malloc(rcount);
2014-09-17 15:33:21 -07:00
char cur[13];
unsigned int cp = 0;
unsigned int reallocs = 0;
2014-09-17 15:33:21 -07:00
while ((r = read((*out_pipe)[0], buf, rcount))) {
unsigned int i;
char *rbuf;
if (r == -1) {
2014-09-17 14:31:20 -07:00
fprintf(stderr, "bitcoind.js: error=\"parse_logs(): bad read.\"\n");
sleep(1);
continue;
}
if (r <= 0) continue;
// Grab the buffer at the start of the bytes that were read:
2014-09-17 15:33:21 -07:00
rbuf = (char *)(buf + rtotal);
// If these are our logs, write them to stdout:
for (i = 0; i < r; i++) {
// A naive semi-boyer-moore string search (is it a bitcoind: char?):
unsigned char ch = rbuf[i];
if (bitcoind_char[ch]) {
cur[cp] = rbuf[0];
cp++;
cur[cp] = '\0';
2014-09-17 14:31:20 -07:00
if (strcmp(cur, "bitcoind.js:") == 0) {
size_t wcount = r;
ssize_t w = 0;
ssize_t wtotal = 0;
// undo redirection
2014-09-17 15:33:21 -07:00
close((*out_pipe)[0]);
close((*out_pipe)[1]);
w = write(STDOUT_FILENO, cur, cp);
wtotal += w;
while ((w = write(STDOUT_FILENO, rbuf + i + wtotal, wcount))) {
if (w == -1) {
2014-09-17 14:31:20 -07:00
fprintf(stderr, "bitcoind.js: error=\"parse_logs(): bad write.\"\n");
sleep(1);
break;
}
if (w == 0 || (size_t)wtotal == rcount) break;
wtotal += w;
}
// reopen redirection
pipe(*out_pipe);
2014-09-17 15:33:21 -07:00
dup2((*out_pipe)[1], STDOUT_FILENO);
dup2((*out_pipe)[1], STDERR_FILENO);
break;
2014-09-17 11:31:10 -07:00
} else if (cp == sizeof cur - 1) {
cp = 0;
}
}
}
// If these logs are from bitcoind, write them to the log pipe:
for (i = 0; i < r; i++) {
if ((rbuf[i] == '\r' && rbuf[i] == '\n')
|| rbuf[i] == '\r' || rbuf[i] == '\n') {
size_t wcount = r;
ssize_t w = 0;
ssize_t wtotal = 0;
2014-09-17 15:33:21 -07:00
while ((w = write((*log_pipe)[1], rbuf + i + wtotal + 1, wcount))) {
if (w == -1) {
2014-09-17 14:31:20 -07:00
fprintf(stderr, "bitcoind.js: error=\"parse_logs(): bad write.\"\n");
sleep(1);
break;
}
if (w == 0 || (size_t)wtotal == rcount) break;
wtotal += w;
}
}
}
rtotal += r;
while (rtotal > rcount) {
reallocs++;
rcount = (rcount * 2) / reallocs;
buf = (char *)realloc(buf, rcount);
}
}
free(buf);
}
static void
async_parse_logs(uv_work_t *req) {
2014-09-19 15:39:05 -07:00
async_log_data *log_data = static_cast<async_log_data*>(req->data);
parse_logs(log_data->out_pipe, log_data->log_pipe);
log_data->err_msg = (char *)strdup("parse_logs(): failed.");
}
static void
async_parse_logs_after(uv_work_t *req) {
NanScope();
2014-09-19 15:39:05 -07:00
async_log_data *log_data = static_cast<async_log_data*>(req->data);
2014-09-04 15:16:32 -07:00
if (log_data->err_msg != NULL) {
Local<Value> err = Exception::Error(String::New(log_data->err_msg));
free(log_data->err_msg);
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
log_data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
assert(0 && "parse_logs(): should never happen.");
}
2014-09-04 15:16:32 -07:00
// log_data->callback.Dispose();
delete log_data;
delete req;
}
2014-09-18 14:57:03 -07:00
#endif
2014-09-11 17:18:36 -07:00
/**
* 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.
//
2014-09-19 15:39:05 -07:00
async_node_data *data_stop_node = new async_node_data();
2014-09-11 17:18:36 -07:00
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) {
2014-09-19 15:39:05 -07:00
async_node_data *node_data = static_cast<async_node_data*>(req->data);
2014-09-11 17:18:36 -07:00
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;
}
2014-09-19 13:53:55 -07:00
/**
2014-09-19 15:39:05 -07:00
* GetBlock(hash, callback)
* bitcoind.getBlock(hash, callback)
2014-09-19 13:53:55 -07:00
*/
NAN_METHOD(GetBlock) {
NanScope();
if (args.Length() < 2
|| !args[0]->IsString()
|| !args[1]->IsFunction()) {
return NanThrowError(
"Usage: bitcoindjs.getBlock(hash, callback)");
}
String::Utf8Value hash(args[0]->ToString());
Local<Function> callback = Local<Function>::Cast(args[1]);
std::string hashp = std::string(*hash);
async_block_data *data = new async_block_data();
data->err_msg = std::string("");
data->hash = hashp;
data->callback = Persistent<Function>::New(callback);
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_get_block,
(uv_after_work_cb)async_get_block_after);
assert(status == 0);
NanReturnValue(Undefined());
}
static void
async_get_block(uv_work_t *req) {
async_block_data* data = static_cast<async_block_data*>(req->data);
std::string strHash = data->hash;
if (strHash[1] != 'x') {
strHash = "0x" + strHash;
}
uint256 hash(strHash);
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash];
if (ReadBlockFromDisk(block, pblockindex)) {
2014-09-19 15:39:05 -07:00
data->result_block = block;
data->result_blockindex = pblockindex;
2014-09-19 13:53:55 -07:00
} else {
data->err_msg = std::string("get_block(): failed.");
}
}
static void
async_get_block_after(uv_work_t *req) {
NanScope();
async_block_data* data = static_cast<async_block_data*>(req->data);
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
2014-09-19 15:39:05 -07:00
const CBlock& block = data->result_block;
const CBlockIndex* blockindex = data->result_blockindex;
Local<Object> obj = NanNew<Object>();
obj->Set(NanNew<String>("hash"), NanNew<String>(block.GetHash().GetHex().c_str()));
CMerkleTx txGen(block.vtx[0]);
txGen.SetMerkleBranch(&block);
obj->Set(NanNew<String>("confirmations"), NanNew<Number>((int)txGen.GetDepthInMainChain()));
obj->Set(NanNew<String>("size"), NanNew<Number>((int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
obj->Set(NanNew<String>("height"), NanNew<Number>(blockindex->nHeight));
obj->Set(NanNew<String>("version"), NanNew<Number>(block.nVersion));
obj->Set(NanNew<String>("merkleroot"), NanNew<String>(block.hashMerkleRoot.GetHex()));
Local<Array> txs = NanNew<Array>();
2014-09-22 12:40:46 -07:00
int ti = 0;
2014-09-19 15:39:05 -07:00
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
Local<Object> entry = NanNew<Object>();
entry->Set(NanNew<String>("txid"), NanNew<String>(tx.GetHash().GetHex()));
entry->Set(NanNew<String>("version"), NanNew<Number>(tx.nVersion));
entry->Set(NanNew<String>("locktime"), NanNew<Number>(tx.nLockTime));
Local<Array> vin = NanNew<Array>();
2014-09-22 12:38:33 -07:00
int vi = 0;
2014-09-19 15:39:05 -07:00
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
Local<Object> in = NanNew<Object>();
if (tx.IsCoinBase()) {
in->Set(NanNew<String>("coinbase"), NanNew<String>(HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
} else {
in->Set(NanNew<String>("txid"), NanNew<String>(txin.prevout.hash.GetHex()));
in->Set(NanNew<String>("vout"), NanNew<Number>((boost::int64_t)txin.prevout.n));
Local<Object> o = NanNew<Object>();
o->Set(NanNew<String>("asm"), NanNew<String>(txin.scriptSig.ToString()));
o->Set(NanNew<String>("hex"), NanNew<String>(HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
in->Set(NanNew<String>("scriptSig"), o);
}
in->Set(NanNew<String>("sequence"), NanNew<Number>((boost::int64_t)txin.nSequence));
2014-09-22 12:38:33 -07:00
vin->Set(vi, in);
vi++;
2014-09-19 15:39:05 -07:00
}
entry->Set(NanNew<String>("vin"), vin);
Local<Array> vout = NanNew<Array>();
2014-09-22 12:38:33 -07:00
for (unsigned int vo = 0; vo < tx.vout.size(); vo++) {
const CTxOut& txout = tx.vout[vo];
2014-09-19 15:39:05 -07:00
Local<Object> out = NanNew<Object>();
//out->Set(NanNew<String>("value"), NanNew<Number>(ValueFromAmount(txout.nValue)));
out->Set(NanNew<String>("value"), NanNew<Number>(txout.nValue));
2014-09-22 12:38:33 -07:00
out->Set(NanNew<String>("n"), NanNew<Number>((boost::int64_t)vo));
2014-09-19 15:39:05 -07:00
// ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
Local<Object> o = NanNew<Object>();
{
const CScript& scriptPubKey = txout.scriptPubKey;
Local<Object> out = o;
bool fIncludeHex = true;
// ---
txnouttype type;
vector<CTxDestination> addresses;
int nRequired;
out->Set(NanNew<String>("asm"), NanNew<String>(scriptPubKey.ToString()));
if (fIncludeHex) {
out->Set(NanNew<String>("hex"), NanNew<String>(HexStr(scriptPubKey.begin(), scriptPubKey.end())));
}
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
out->Set(NanNew<String>("type"), NanNew<String>(GetTxnOutputType(type)));
} else {
out->Set(NanNew<String>("reqSigs"), NanNew<Number>(nRequired));
out->Set(NanNew<String>("type"), NanNew<String>(GetTxnOutputType(type)));
Local<Array> a = NanNew<Array>();
int k = 0;
BOOST_FOREACH(const CTxDestination& addr, addresses) {
a->Set(k, NanNew<String>(CBitcoinAddress(addr).ToString()));
k++;
}
out->Set(NanNew<String>("addresses"), a);
}
}
out->Set(NanNew<String>("scriptPubKey"), o);
2014-09-22 12:38:33 -07:00
vout->Set(vo, out);
2014-09-19 15:39:05 -07:00
}
entry->Set(NanNew<String>("vout"), vout);
// TxToJSON(tx, hashBlock, result);
{
const uint256 hashBlock = block.GetHash();
if (hashBlock != 0) {
entry->Set(NanNew<String>("blockhash"), NanNew<String>(hashBlock.GetHex()));
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex)) {
entry->Set(NanNew<String>("confirmations"),
NanNew<Number>(1 + chainActive.Height() - pindex->nHeight));
entry->Set(NanNew<String>("time"), NanNew<Number>((boost::int64_t)pindex->nTime));
entry->Set(NanNew<String>("blocktime"), NanNew<Number>((boost::int64_t)pindex->nTime));
} else {
entry->Set(NanNew<String>("confirmations"), NanNew<Number>(0));
}
}
}
}
2014-09-22 12:40:46 -07:00
txs->Set(ti, entry);
ti++;
2014-09-19 15:39:05 -07:00
}
obj->Set(NanNew<String>("tx"), txs);
obj->Set(NanNew<String>("time"), NanNew<Number>((boost::int64_t)block.GetBlockTime()));
obj->Set(NanNew<String>("nonce"), NanNew<Number>((boost::uint64_t)block.nNonce));
obj->Set(NanNew<String>("bits"), NanNew<Number>(block.nBits));
obj->Set(NanNew<String>("difficulty"), NanNew<Number>(GetDifficulty(blockindex)));
obj->Set(NanNew<String>("chainwork"), NanNew<String>(blockindex->nChainWork.GetHex()));
if (blockindex->pprev) {
obj->Set(NanNew<String>("previousblockhash"), NanNew<String>(blockindex->pprev->GetBlockHash().GetHex()));
}
CBlockIndex *pnext = chainActive.Next(blockindex);
if (pnext) {
obj->Set(NanNew<String>("nextblockhash"), NanNew<String>(pnext->GetBlockHash().GetHex()));
}
2014-09-19 13:53:55 -07:00
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
2014-09-19 15:39:05 -07:00
Local<Value>::New(obj)
2014-09-19 13:53:55 -07:00
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
}
2014-09-22 10:19:37 -07:00
/**
* GetTx(hash, callback)
* bitcoind.getTx(hash, callback)
*/
NAN_METHOD(GetTx) {
NanScope();
if (args.Length() < 2
|| !args[0]->IsString()
2014-09-22 12:05:17 -07:00
|| !args[1]->IsString()
|| !args[2]->IsFunction()) {
2014-09-22 10:19:37 -07:00
return NanThrowError(
"Usage: bitcoindjs.getTx(hash, callback)");
}
2014-09-22 12:05:17 -07:00
String::Utf8Value txHash_(args[0]->ToString());
String::Utf8Value blockHash_(args[1]->ToString());
Local<Function> callback = Local<Function>::Cast(args[2]);
2014-09-22 10:19:37 -07:00
Persistent<Function> cb;
cb = Persistent<Function>::New(callback);
2014-09-22 12:05:17 -07:00
std::string txHash = std::string(*txHash_);
std::string blockHash = std::string(*blockHash_);
2014-09-22 12:27:33 -07:00
bool noBlockHash = false;
if (blockHash.empty()) {
blockHash = std::string("0x0000000000000000000000000000000000000000000000000000000000000000");
noBlockHash = true;
}
2014-09-22 12:05:17 -07:00
if (txHash[1] != 'x') {
txHash = "0x" + txHash;
}
if (blockHash[1] != 'x') {
blockHash = "0x" + blockHash;
}
2014-09-22 12:14:51 -07:00
printf("tx: %s\n", txHash.c_str());
printf("block: %s\n", blockHash.c_str());
2014-09-22 12:07:44 -07:00
2014-09-22 12:05:17 -07:00
uint256 hash(txHash);
uint256 hashBlock(blockHash);
// uint256 hashBlock = 0;
2014-09-22 12:27:33 -07:00
// if (noBlockHash) hashBlock = 0;
2014-09-22 12:05:17 -07:00
CTransaction tx;
2014-09-22 12:06:55 -07:00
2014-09-22 12:27:33 -07:00
if (!GetTransaction(hash, tx, hashBlock, noBlockHash ? true : false)) {
2014-09-22 12:05:17 -07:00
Local<Value> err = Exception::Error(String::New("Bad Transaction."));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
cb->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
cb.Dispose();
NanReturnValue(Undefined());
2014-09-22 12:06:55 -07:00
} else {
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
string strHex = HexStr(ssTx.begin(), ssTx.end());
2014-09-22 12:05:17 -07:00
2014-09-22 12:38:33 -07:00
Local<Object> entry = NanNew<Object>();
2014-09-22 12:40:46 -07:00
entry->Set(NanNew<String>("hex"), NanNew<String>(strHex));
2014-09-22 12:38:33 -07:00
entry->Set(NanNew<String>("txid"), NanNew<String>(tx.GetHash().GetHex()));
entry->Set(NanNew<String>("version"), NanNew<Number>(tx.nVersion));
entry->Set(NanNew<String>("locktime"), NanNew<Number>(tx.nLockTime));
Local<Array> vin = NanNew<Array>();
int vi = 0;
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
Local<Object> in = NanNew<Object>();
if (tx.IsCoinBase()) {
in->Set(NanNew<String>("coinbase"), NanNew<String>(HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
} else {
in->Set(NanNew<String>("txid"), NanNew<String>(txin.prevout.hash.GetHex()));
in->Set(NanNew<String>("vout"), NanNew<Number>((boost::int64_t)txin.prevout.n));
Local<Object> o = NanNew<Object>();
o->Set(NanNew<String>("asm"), NanNew<String>(txin.scriptSig.ToString()));
o->Set(NanNew<String>("hex"), NanNew<String>(HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
in->Set(NanNew<String>("scriptSig"), o);
}
in->Set(NanNew<String>("sequence"), NanNew<Number>((boost::int64_t)txin.nSequence));
vin->Set(vi, in);
vi++;
}
entry->Set(NanNew<String>("vin"), vin);
Local<Array> vout = NanNew<Array>();
for (unsigned int vo = 0; vo < tx.vout.size(); vo++) {
const CTxOut& txout = tx.vout[vo];
Local<Object> out = NanNew<Object>();
//out->Set(NanNew<String>("value"), NanNew<Number>(ValueFromAmount(txout.nValue)));
out->Set(NanNew<String>("value"), NanNew<Number>(txout.nValue));
out->Set(NanNew<String>("n"), NanNew<Number>((boost::int64_t)vo));
// ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
Local<Object> o = NanNew<Object>();
{
const CScript& scriptPubKey = txout.scriptPubKey;
Local<Object> out = o;
bool fIncludeHex = true;
// ---
txnouttype type;
vector<CTxDestination> addresses;
int nRequired;
out->Set(NanNew<String>("asm"), NanNew<String>(scriptPubKey.ToString()));
if (fIncludeHex) {
out->Set(NanNew<String>("hex"), NanNew<String>(HexStr(scriptPubKey.begin(), scriptPubKey.end())));
}
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
out->Set(NanNew<String>("type"), NanNew<String>(GetTxnOutputType(type)));
} else {
out->Set(NanNew<String>("reqSigs"), NanNew<Number>(nRequired));
out->Set(NanNew<String>("type"), NanNew<String>(GetTxnOutputType(type)));
Local<Array> a = NanNew<Array>();
int k = 0;
BOOST_FOREACH(const CTxDestination& addr, addresses) {
a->Set(k, NanNew<String>(CBitcoinAddress(addr).ToString()));
k++;
}
out->Set(NanNew<String>("addresses"), a);
}
}
out->Set(NanNew<String>("scriptPubKey"), o);
vout->Set(vo, out);
}
entry->Set(NanNew<String>("vout"), vout);
if (hashBlock != 0) {
entry->Set(NanNew<String>("blockhash"), NanNew<String>(hashBlock.GetHex()));
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex)) {
entry->Set(NanNew<String>("confirmations"),
NanNew<Number>(1 + chainActive.Height() - pindex->nHeight));
entry->Set(NanNew<String>("time"), NanNew<Number>((boost::int64_t)pindex->nTime));
entry->Set(NanNew<String>("blocktime"), NanNew<Number>((boost::int64_t)pindex->nTime));
} else {
entry->Set(NanNew<String>("confirmations"), NanNew<Number>(0));
}
}
}
2014-09-22 12:05:17 -07:00
2014-09-22 12:06:55 -07:00
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
2014-09-22 12:38:33 -07:00
Local<Value>::New(entry)
2014-09-22 12:06:55 -07:00
};
TryCatch try_catch;
cb->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
cb.Dispose();
NanReturnValue(Undefined());
2014-09-22 12:05:17 -07:00
}
}
2014-09-22 10:19:37 -07:00
2014-08-12 12:03:04 -07:00
/**
* Init
*/
extern "C" void
init(Handle<Object> target) {
NanScope();
NODE_SET_METHOD(target, "start", StartBitcoind);
2014-09-11 17:18:36 -07:00
NODE_SET_METHOD(target, "stop", StopBitcoind);
2014-09-17 14:08:26 -07:00
NODE_SET_METHOD(target, "stopping", IsStopping);
2014-09-17 12:52:35 -07:00
NODE_SET_METHOD(target, "stopped", IsStopped);
2014-09-18 15:32:19 -07:00
NODE_SET_METHOD(target, "getBlock", GetBlock);
2014-09-22 10:19:37 -07:00
NODE_SET_METHOD(target, "getTx", GetTx);
2014-08-12 12:03:04 -07:00
}
NODE_MODULE(bitcoindjs, init)