bitcore-node-zcash/src/bitcoindjs.cc

3625 lines
101 KiB
C++
Raw Normal View History

2014-08-12 12:03:04 -07:00
/**
* bitcoind.js - a binding for node.js which links to libbitcoind.so/dylib.
* Copyright (c) 2015, BitPay (MIT License)
2014-08-12 12:03:04 -07:00
*
* bitcoindjs.cc:
* A bitcoind node.js binding.
*/
#include "bitcoindjs.h"
2014-09-17 12:14:20 -07:00
using namespace std;
using namespace boost;
using namespace node;
using namespace v8;
2014-09-17 12:14:20 -07:00
2014-10-15 15:27:14 -07:00
/**
* Bitcoin Globals
*/
// These global functions and variables are
// required to be defined/exposed here.
2014-10-06 11:05:52 -07:00
2014-09-17 11:23:38 -07:00
extern void DetectShutdownThread(boost::thread_group*);
extern int nScriptCheckThreads;
extern std::map<std::string, std::string> mapArgs;
2014-10-13 14:00:01 -07:00
extern CFeeRate payTxFee;
2014-10-01 12:52:06 -07:00
extern const std::string strMessageMagic;
extern std::string EncodeDumpTime(int64_t nTime);
extern int64_t DecodeDumpTime(const std::string &str);
extern std::string EncodeDumpString(const std::string &str);
2014-10-29 15:07:25 -07:00
extern std::string DecodeDumpString(const std::string &str);
2014-12-10 11:12:31 -08:00
extern bool fTxIndex;
2014-12-10 11:42:33 -08:00
static termios orig_termios;
2014-09-26 12:42:04 -07:00
2014-10-15 15:27:14 -07:00
/**
* Node.js Internal Function Templates
*/
static void
2014-10-06 08:10:23 -07:00
async_start_node(uv_work_t *req);
static void
async_start_node_after(uv_work_t *req);
2014-08-12 12:03:04 -07:00
2015-07-07 14:02:03 -07:00
static void
async_blocks_ready(uv_work_t *req);
static void
async_blocks_ready_after(uv_work_t *req);
2014-09-11 17:18:36 -07:00
static void
2014-10-06 08:10:23 -07:00
async_stop_node(uv_work_t *req);
2014-09-11 17:18:36 -07:00
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-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-11-11 16:10:26 -08:00
static void
async_get_progress(uv_work_t *req);
2014-10-28 13:01:40 -07:00
static void
async_get_progress_after(uv_work_t *req);
2014-09-22 13:21:42 -07:00
static void
async_get_tx(uv_work_t *req);
static void
async_get_tx_after(uv_work_t *req);
2014-11-04 16:08:31 -08:00
static void
async_get_addrtx(uv_work_t *req);
static void
async_get_addrtx_after(uv_work_t *req);
2014-09-25 12:05:39 -07:00
static void
async_broadcast_tx(uv_work_t *req);
static void
async_broadcast_tx_after(uv_work_t *req);
2014-12-03 12:14:23 -08:00
static void
async_block_tx(uv_work_t *req);
static void
async_block_tx_after(uv_work_t *req);
2014-12-03 12:46:48 -08:00
static void
async_block_time(uv_work_t *req);
static void
async_block_time_after(uv_work_t *req);
2014-12-18 10:56:46 -08:00
static void
async_from_tx(uv_work_t *req);
static void
async_from_tx_after(uv_work_t *req);
2014-09-23 13:57:49 -07:00
static inline void
2014-10-23 15:50:15 -07:00
cblock_to_jsblock(const CBlock& cblock, CBlockIndex* cblock_index, Local<Object> jsblock, bool is_new);
2014-09-29 13:38:27 -07:00
static inline void
2014-12-08 11:31:00 -08:00
ctx_to_jstx(const CTransaction& ctx, uint256 blockhash, Local<Object> jstx);
2014-09-29 13:38:27 -07:00
static inline void
2014-10-02 13:13:54 -07:00
jsblock_to_cblock(const Local<Object> jsblock, CBlock& cblock);
2014-09-23 13:57:49 -07:00
static inline void
2014-10-02 13:13:54 -07:00
jstx_to_ctx(const Local<Object> jstx, CTransaction& ctx);
2014-10-21 18:06:17 -07:00
static void
hook_packets(void);
2014-10-21 18:06:17 -07:00
static void
unhook_packets(void);
2014-10-21 18:06:17 -07:00
static bool
process_packets(CNode* pfrom);
static bool
process_packet(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived);
2014-12-04 15:38:35 -08:00
static int
2014-12-08 13:36:54 -08:00
get_tx(uint256 txid, uint256& blockhash, CTransaction& ctx);
2014-12-04 15:38:35 -08:00
2014-08-12 12:03:04 -07:00
extern "C" void
init(Handle<Object>);
2014-09-19 13:53:55 -07:00
/**
2014-10-15 15:27:14 -07:00
* Private Global Variables
* Used only by bitcoindjs functions.
2014-09-19 13:53:55 -07:00
*/
2014-10-15 15:37:29 -07:00
static volatile bool shutdown_complete = false;
2014-10-15 15:36:35 -07:00
static char *g_data_dir = NULL;
2014-10-17 12:06:40 -07:00
static bool g_rpc = false;
2014-10-20 09:38:35 -07:00
static bool g_testnet = false;
static bool g_txindex = false;
2014-09-19 13:53:55 -07:00
2014-10-06 11:05:52 -07:00
/**
* Private Structs
* Used for async functions and necessary linked lists at points.
*/
2015-07-07 14:02:03 -07:00
/**
* async_node_data
* Where the uv async request data resides.
*/
struct async_block_ready_data {
std::string err_msg;
std::string result;
Eternal<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 {
2014-09-29 12:18:29 -07:00
std::string err_msg;
std::string result;
2014-10-15 15:36:35 -07:00
std::string datadir;
2014-10-17 12:06:40 -07:00
bool rpc;
2014-10-20 09:38:35 -07:00
bool testnet;
bool txindex;
Eternal<Function> callback;
};
2014-09-22 13:21:42 -07:00
/**
* async_block_data
*/
struct async_block_data {
std::string err_msg;
std::string hash;
2014-11-04 16:08:31 -08:00
int64_t height;
CBlock cblock;
CBlockIndex* cblock_index;
Eternal<Function> callback;
2014-09-22 13:21:42 -07:00
};
/**
* async_tx_data
*/
struct async_tx_data {
std::string err_msg;
2014-12-08 11:31:00 -08:00
std::string txid;
std::string blockhash;
CTransaction ctx;
Eternal<Function> callback;
2014-09-22 13:21:42 -07:00
};
2014-12-03 12:14:23 -08:00
/**
* async_block_tx_data
*/
struct async_block_tx_data {
std::string err_msg;
std::string txid;
CBlock cblock;
CBlockIndex* cblock_index;
2014-12-10 16:22:30 -08:00
CTransaction ctx;
Eternal<Function> callback;
2014-12-03 12:14:23 -08:00
};
2014-12-03 12:46:48 -08:00
/**
* async_block_time_data
*/
2014-12-04 11:12:29 -08:00
typedef struct _cblocks_list {
CBlock cblock;
CBlockIndex* cblock_index;
struct _cblocks_list *next;
std::string err_msg;
} cblocks_list;
2014-12-03 12:46:48 -08:00
struct async_block_time_data {
std::string err_msg;
uint32_t gte;
uint32_t lte;
2014-12-04 11:12:29 -08:00
int64_t limit;
cblocks_list *cblocks;
Eternal<Function> callback;
2014-12-03 12:46:48 -08:00
};
2014-11-04 16:08:31 -08:00
/**
* async_addrtx_data
*/
typedef struct _ctx_list {
CTransaction ctx;
2014-11-05 11:56:37 -08:00
uint256 blockhash;
2014-11-04 16:08:31 -08:00
struct _ctx_list *next;
2014-12-01 15:12:01 -08:00
std::string err_msg;
2014-11-04 16:08:31 -08:00
} ctx_list;
struct async_addrtx_data {
std::string err_msg;
std::string addr;
ctx_list *ctxs;
int64_t blockheight;
2014-12-03 21:16:47 -08:00
int64_t blocktime;
Eternal<Function> callback;
2014-11-04 16:08:31 -08:00
};
2014-09-25 12:05:39 -07:00
/**
2014-09-25 12:38:42 -07:00
* async_broadcast_tx_data
2014-09-25 12:05:39 -07:00
*/
2014-09-25 12:38:42 -07:00
struct async_broadcast_tx_data {
2014-09-25 12:05:39 -07:00
std::string err_msg;
Eternal<Object> jstx;
CTransaction ctx;
2014-12-08 11:31:00 -08:00
std::string txid;
2014-09-25 12:05:39 -07:00
bool override_fees;
2014-09-25 13:12:28 -07:00
bool own_only;
Eternal<Function> callback;
2014-09-25 12:05:39 -07:00
};
2014-09-23 13:57:49 -07:00
2014-12-16 14:41:00 -08:00
/**
* async_from_tx_data
*/
struct async_from_tx_data {
std::string err_msg;
std::string txid;
ctx_list *ctxs;
Eternal<Function> callback;
2014-12-16 14:41:00 -08:00
};
2014-11-05 11:56:37 -08:00
/**
* Read Raw DB
*/
2014-11-19 13:42:11 -08:00
#if USE_LDB_ADDR
2014-11-05 11:56:37 -08:00
static ctx_list *
2014-12-03 21:16:47 -08:00
read_addr(const std::string addr, const int64_t blockheight, const int64_t blocktime);
2014-11-18 17:10:17 -08:00
#endif
2014-11-05 11:56:37 -08:00
2014-12-08 10:21:50 -08:00
#if USE_LDB_TX
2014-12-03 12:14:23 -08:00
static bool
2014-12-10 16:22:30 -08:00
get_block_by_tx(const std::string itxid, CBlock& rcblock, CBlockIndex **rcblock_index, CTransaction& rctx);
2014-12-08 10:21:50 -08:00
#endif
2014-12-03 12:14:23 -08:00
2014-12-10 10:44:01 -08:00
/**
* Helpers
*/
static bool
2014-12-10 11:42:33 -08:00
set_cooked(void);
2014-12-10 10:44:01 -08:00
2014-10-15 15:27:14 -07:00
/**
* Functions
*/
2015-07-07 14:02:03 -07:00
NAN_METHOD(OnBlocksReady) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
Local<Function> callback;
callback = Local<Function>::Cast(args[0]);
async_block_ready_data *data = new async_block_ready_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_blocks_ready,
(uv_after_work_cb)async_blocks_ready_after);
assert(status == 0);
NanReturnValue(Undefined(isolate));
}
/**
* async_start_node()
* Call start_node() and start all our boost threads.
*/
static void
async_blocks_ready(uv_work_t *req) {
async_block_ready_data *data = static_cast<async_block_ready_data*>(req->data);
data->result = std::string("");
while(!chainActive.Tip()) {
usleep(1E4);
}
}
static void
async_blocks_ready_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
async_block_ready_data *data = static_cast<async_block_ready_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;
}
2014-08-12 12:03:04 -07:00
/**
2014-10-06 11:05:52 -07:00
* StartBitcoind()
2014-08-12 12:03:04 -07:00
* bitcoind.start(callback)
2014-10-06 11:05:52 -07:00
* Start the bitcoind node with AppInit2() on a separate thread.
2014-08-12 12:03:04 -07:00
*/
NAN_METHOD(StartBitcoind) {
2015-06-09 03:57:58 -07:00
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
2014-08-12 12:03:04 -07:00
2014-10-15 15:36:35 -07:00
Local<Function> callback;
std::string datadir = std::string("");
2014-10-17 12:06:40 -07:00
bool rpc = false;
2014-10-20 09:38:35 -07:00
bool testnet = false;
bool txindex = false;
2014-10-15 16:38:10 -07:00
if (args.Length() >= 2 && args[0]->IsObject() && args[1]->IsFunction()) {
2014-10-15 15:36:35 -07:00
Local<Object> options = Local<Object>::Cast(args[0]);
2014-10-15 16:38:10 -07:00
if (options->Get(NanNew<String>("datadir"))->IsString()) {
String::Utf8Value datadir_(options->Get(NanNew<String>("datadir"))->ToString());
datadir = std::string(*datadir_);
2014-10-15 15:36:35 -07:00
}
2014-10-17 12:06:40 -07:00
if (options->Get(NanNew<String>("rpc"))->IsBoolean()) {
rpc = options->Get(NanNew<String>("rpc"))->ToBoolean()->IsTrue();
}
2014-10-20 09:38:35 -07:00
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();
}
2014-10-15 16:38:10 -07:00
callback = Local<Function>::Cast(args[1]);
2014-10-16 11:24:21 -07:00
} else if (args.Length() >= 2
2014-10-15 16:38:10 -07:00
&& (args[0]->IsUndefined() || args[0]->IsNull())
&& args[1]->IsFunction()) {
callback = Local<Function>::Cast(args[1]);
2014-10-16 11:24:21 -07:00
} else if (args.Length() >= 1 && args[0]->IsFunction()) {
2014-10-15 15:36:35 -07:00
callback = Local<Function>::Cast(args[0]);
2014-10-15 16:38:10 -07:00
} else {
return NanThrowError(
"Usage: bitcoind.start(callback)");
2014-08-12 12:03:04 -07:00
}
//
// Run bitcoind's StartNode() on a separate thread.
//
2014-09-29 12:18:29 -07:00
async_node_data *data = new async_node_data();
data->err_msg = std::string("");
data->result = std::string("");
2014-10-15 15:36:35 -07:00
data->datadir = datadir;
2014-10-17 12:06:40 -07:00
data->rpc = rpc;
data->testnet = testnet;
data->txindex = txindex;
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
2014-09-29 12:18:29 -07:00
uv_work_t *req = new uv_work_t();
req->data = data;
2014-09-29 12:18:29 -07:00
int status = uv_queue_work(uv_default_loop(),
2014-10-06 08:10:23 -07:00
req, async_start_node,
(uv_after_work_cb)async_start_node_after);
2014-09-29 12:18:29 -07:00
assert(status == 0);
2014-08-12 12:03:04 -07:00
NanReturnValue(Undefined(isolate));
2014-08-12 12:03:04 -07:00
}
2014-08-20 17:00:09 -07:00
/**
2014-10-06 08:10:23 -07:00
* async_start_node()
2014-08-20 17:00:09 -07:00
* Call start_node() and start all our boost threads.
*/
static void
2014-10-06 08:10:23 -07:00
async_start_node(uv_work_t *req) {
2014-09-29 12:18:29 -07:00
async_node_data *data = static_cast<async_node_data*>(req->data);
2014-11-11 11:38:51 -08:00
if (data->datadir != "") {
2014-10-16 11:24:21 -07:00
g_data_dir = (char *)data->datadir.c_str();
2014-11-11 13:36:08 -08:00
} else {
g_data_dir = (char *)malloc(sizeof(char) * 512);
snprintf(g_data_dir, sizeof(char) * 512, "%s/.bitcoind.js", getenv("HOME"));
2014-10-15 15:36:35 -07:00
}
2014-10-17 12:06:40 -07:00
g_rpc = (bool)data->rpc;
2014-10-20 09:38:35 -07:00
g_testnet = (bool)data->testnet;
g_txindex = (bool)data->txindex;
2014-12-10 11:42:33 -08:00
tcgetattr(STDIN_FILENO, &orig_termios);
2014-09-05 15:07:38 -07:00
start_node();
2014-12-10 10:47:02 -08:00
data->result = std::string("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) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
async_node_data *data = static_cast<async_node_data*>(req->data);
Local<Function> cb = data->callback.Get(isolate);
2014-11-11 11:38:51 -08:00
if (data->err_msg != "") {
2014-11-11 11:36:20 -08:00
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);
}
}
2014-09-29 12:18:29 -07:00
delete data;
delete req;
2014-08-12 12:03:04 -07:00
}
2014-08-20 17:00:09 -07:00
/**
* start_node(void)
2014-10-06 11:05:52 -07:00
* 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.
2014-08-20 17:00:09 -07:00
*/
static int
start_node(void) {
2014-10-13 14:00:01 -07:00
SetupEnvironment();
2014-09-17 12:14:20 -07:00
noui_connect();
new boost::thread(boost::bind(&start_node_thread));
2014-09-17 12:14:20 -07:00
2014-10-06 11:05:52 -07:00
// Drop the bitcoind signal handlers: we want our own.
2014-09-17 14:08:26 -07:00
signal(SIGINT, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
2014-09-17 12:14:20 -07:00
2014-10-21 18:06:17 -07:00
// Hook into packet handling
new boost::thread(boost::bind(&hook_packets));
2014-10-21 18:06:17 -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-10-15 15:22:57 -07:00
boost::thread* detectShutdownThread = NULL;
2014-09-17 12:14:20 -07:00
2014-10-13 14:16:43 -07:00
// Workaround for AppInit2() arg parsing. Not ideal, but it works.
2014-10-15 15:36:35 -07:00
int argc = 0;
char **argv = (char **)malloc((4 + 1) * sizeof(char **));
2014-10-17 12:11:34 -07:00
argv[argc] = (char *)"bitcoind";
argc++;
2014-10-17 12:38:41 -07:00
2014-10-15 15:36:35 -07:00
if (g_data_dir) {
2014-10-21 18:06:17 -07:00
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);
2014-10-21 18:06:17 -07:00
if (w >= 10 && w <= argl) {
arg[w] = '\0';
argv[argc] = arg;
argc++;
} else {
2014-12-10 11:42:33 -08:00
if (set_cooked()) {
2014-12-10 10:44:01 -08:00
fprintf(stderr, "bitcoind.js: Bad -datadir value.\n");
}
}
2014-10-13 14:16:43 -07:00
}
2014-10-13 14:00:01 -07:00
2014-10-17 12:11:34 -07:00
if (g_rpc) {
argv[argc] = (char *)"-server";
argc++;
}
2014-10-20 09:38:35 -07:00
if (g_testnet) {
argv[argc] = (char *)"-testnet";
argc++;
}
if (g_txindex) {
argv[argc] = (char *)"-txindex";
argc++;
}
2014-10-17 12:11:34 -07:00
argv[argc] = NULL;
2014-10-13 14:00:01 -07:00
bool fRet = false;
try {
2014-10-15 15:36:35 -07:00
ParseParameters((const int)argc, (const char **)argv);
2014-10-13 14:00:01 -07:00
if (!boost::filesystem::is_directory(GetDataDir(false))) {
2014-12-10 11:42:33 -08:00
if (set_cooked()) {
2014-12-10 10:44:01 -08:00
fprintf(stderr,
"bitcoind.js: Specified data directory \"%s\" does not exist.\n",
mapArgs["-datadir"].c_str());
}
2014-12-10 11:12:31 -08:00
shutdown_complete = true;
2014-12-10 11:29:29 -08:00
_exit(1);
2014-10-13 14:00:01 -07:00
return;
}
try {
ReadConfigFile(mapArgs, mapMultiArgs);
} catch(std::exception &e) {
2014-12-10 11:42:33 -08:00
if (set_cooked()) {
2014-12-10 10:44:01 -08:00
fprintf(stderr,
"bitcoind.js: Error reading configuration file: %s\n", e.what());
}
2014-12-10 11:12:31 -08:00
shutdown_complete = true;
2014-12-10 11:29:29 -08:00
_exit(1);
2014-10-13 14:00:01 -07:00
return;
}
if (!SelectParamsFromCommandLine()) {
2014-12-10 11:42:33 -08:00
if (set_cooked()) {
2014-12-10 10:44:01 -08:00
fprintf(stderr,
"bitcoind.js: Invalid combination of -regtest and -testnet.\n");
}
2014-12-10 11:12:31 -08:00
shutdown_complete = true;
2014-12-10 11:29:29 -08:00
_exit(1);
2014-12-10 11:12:31 -08:00
return;
}
2014-10-15 15:36:35 -07:00
CreatePidFile(GetPidFile(), getpid());
2014-10-13 14:00:01 -07:00
detectShutdownThread = new boost::thread(
boost::bind(&DetectShutdownThread, &threadGroup));
2014-10-13 14:00:01 -07:00
fRet = AppInit2(threadGroup);
2014-10-13 14:00:01 -07:00
} catch (std::exception& e) {
if (set_cooked()) {
fprintf(stderr, "bitcoind.js: AppInit(): std::exception\n");
}
2014-10-13 14:00:01 -07:00
} catch (...) {
if (set_cooked()) {
fprintf(stderr, "bitcoind.js: AppInit(): other exception\n");
}
2014-10-13 14:00:01 -07:00
}
if (!fRet) {
if (detectShutdownThread) {
detectShutdownThread->interrupt();
}
threadGroup.interrupt_all();
}
if (detectShutdownThread) {
detectShutdownThread->join();
delete detectShutdownThread;
detectShutdownThread = NULL;
}
Shutdown();
2014-11-18 13:26:24 -08:00
// bitcoind is shutdown. Notify the main thread
// which is polling this variable:
2014-10-15 15:37:29 -07:00
shutdown_complete = true;
}
2014-09-11 17:18:36 -07:00
/**
2014-10-06 11:05:52 -07:00
* StopBitcoind()
2014-09-11 17:18:36 -07:00
* bitcoind.stop(callback)
*/
NAN_METHOD(StopBitcoind) {
fprintf(stderr, "Stopping Bitcoind please wait!");
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-09-11 17:18:36 -07:00
if (args.Length() < 1 || !args[0]->IsFunction()) {
return NanThrowError(
2014-09-22 12:57:25 -07:00
"Usage: bitcoind.stop(callback)");
2014-09-11 17:18:36 -07:00
}
Local<Function> callback = Local<Function>::Cast(args[0]);
//
// Run bitcoind's StartShutdown() on a separate thread.
//
2014-09-29 12:18:29 -07:00
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;
2014-09-11 17:18:36 -07:00
2014-09-29 12:18:29 -07:00
uv_work_t *req = new uv_work_t();
req->data = data;
2014-09-11 17:18:36 -07:00
2014-09-29 12:18:29 -07:00
int status = uv_queue_work(uv_default_loop(),
2014-10-06 08:10:23 -07:00
req, async_stop_node,
2014-09-11 17:18:36 -07:00
(uv_after_work_cb)async_stop_node_after);
2014-09-29 12:18:29 -07:00
assert(status == 0);
NanReturnValue(Undefined(isolate));
2014-09-11 17:18:36 -07:00
}
/**
2014-10-06 08:10:23 -07:00
* async_stop_node()
2014-10-06 11:05:52 -07:00
* Call StartShutdown() to join the boost threads, which will call Shutdown()
2014-10-15 15:37:29 -07:00
* and set shutdown_complete to true to notify the main node.js thread.
2014-09-11 17:18:36 -07:00
*/
static void
2014-10-06 08:10:23 -07:00
async_stop_node(uv_work_t *req) {
2014-09-29 12:18:29 -07:00
async_node_data *data = static_cast<async_node_data*>(req->data);
unhook_packets();
2014-09-11 17:18:36 -07:00
StartShutdown();
2014-12-10 10:47:02 -08:00
data->result = std::string("bitcoind shutdown.");
2014-09-11 17:18:36 -07:00
}
/**
* async_stop_node_after()
* Execute our callback.
*/
static void
async_stop_node_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-09-29 12:18:29 -07:00
async_node_data* data = static_cast<async_node_data*>(req->data);
2014-09-11 17:18:36 -07:00
Local<Function> cb = data->callback.Get(isolate);
2014-11-11 11:38:51 -08:00
if (data->err_msg != "") {
2014-11-11 11:36:20 -08:00
Local<Value> err = Exception::Error(NanNew<String>(data->err_msg));
2014-09-11 17:18:36 -07:00
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-09-11 17:18:36 -07:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
2015-06-08 16:08:18 -07:00
Local<Value>::New(isolate, NanNull()),
Local<Value>::New(isolate, NanNew<String>(data->result))
2014-09-11 17:18:36 -07:00
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-09-11 17:18:36 -07:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
2014-09-29 12:18:29 -07:00
delete data;
2014-09-11 17:18:36 -07:00
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();
2014-10-15 15:37:29 -07:00
NanReturnValue(NanNew<Boolean>(shutdown_complete));
}
2014-09-19 13:53:55 -07:00
/**
2014-10-06 11:05:52 -07:00
* GetBlock()
2014-12-08 11:31:00 -08:00
* bitcoind.getBlock([blockhash,blockheight], callback)
2014-10-06 11:05:52 -07:00
* Read any block from disk asynchronously.
2014-09-19 13:53:55 -07:00
*/
NAN_METHOD(GetBlock) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-09-19 13:53:55 -07:00
if (args.Length() < 2
2014-11-19 17:04:19 -08:00
|| (!args[0]->IsString() && !args[0]->IsNumber())
2014-09-19 13:53:55 -07:00
|| !args[1]->IsFunction()) {
return NanThrowError(
2014-12-08 11:31:00 -08:00
"Usage: bitcoindjs.getBlock([blockhash,blockheight], callback)");
2014-09-19 13:53:55 -07:00
}
2014-11-04 16:08:31 -08:00
async_block_data *data = new async_block_data();
2014-09-19 13:53:55 -07:00
2014-11-04 16:08:31 -08:00
if (args[0]->IsNumber()) {
int64_t height = args[0]->IntegerValue();
data->err_msg = std::string("");
data->hash = std::string("");
data->height = height;
} else {
String::Utf8Value hash_(args[0]->ToString());
std::string hash = std::string(*hash_);
data->err_msg = std::string("");
data->hash = hash;
data->height = -1;
}
Local<Function> callback = Local<Function>::Cast(args[1]);
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
2014-09-19 13:53:55 -07:00
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(isolate));
2014-09-19 13:53:55 -07:00
}
static void
async_get_block(uv_work_t *req) {
async_block_data* data = static_cast<async_block_data*>(req->data);
2014-11-04 16:08:31 -08:00
if (data->height != -1) {
CBlockIndex* pblockindex = chainActive[data->height];
CBlock cblock;
if (ReadBlockFromDisk(cblock, pblockindex)) {
data->cblock = cblock;
data->cblock_index = pblockindex;
} else {
2014-12-10 10:47:02 -08:00
data->err_msg = std::string("Block not found.");
2014-11-04 16:08:31 -08:00
}
return;
}
2014-09-19 13:53:55 -07:00
std::string strHash = data->hash;
uint256 hash(strHash);
2014-11-04 16:08:31 -08:00
2015-07-07 12:36:17 -07:00
if (mapBlockIndex.count(hash) == 0) {
data->err_msg = std::string("Block not found.");
2014-09-19 13:53:55 -07:00
} else {
2015-07-07 12:36:17 -07:00
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash];
if(!ReadBlockFromDisk(block, pblockindex)) {
data->err_msg = std::string("Can't read block from disk");
} else {
data->cblock = block;
data->cblock_index = pblockindex;
}
2014-09-19 13:53:55 -07:00
}
}
static void
async_get_block_after(uv_work_t *req) {
Isolate *isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-09-19 13:53:55 -07:00
async_block_data* data = static_cast<async_block_data*>(req->data);
Local<Function> cb = data->callback.Get(isolate);
2014-09-19 13:53:55 -07:00
2014-11-11 11:38:51 -08:00
if (data->err_msg != "") {
2014-11-11 11:36:20 -08:00
Local<Value> err = Exception::Error(NanNew<String>(data->err_msg));
2014-09-19 13:53:55 -07:00
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-09-19 13:53:55 -07:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
2014-11-04 16:08:31 -08:00
const CBlock& cblock = data->cblock;
CBlockIndex* cblock_index = data->cblock_index;
2014-09-19 15:39:05 -07:00
2014-10-02 13:24:18 -07:00
Local<Object> jsblock = NanNew<Object>();
2014-10-23 15:04:28 -07:00
cblock_to_jsblock(cblock, cblock_index, jsblock, false);
2014-09-19 15:39:05 -07:00
2014-09-19 13:53:55 -07:00
const unsigned argc = 2;
Local<Value> argv[argc] = {
2015-06-08 16:08:18 -07:00
Local<Value>::New(isolate, NanNull()),
Local<Value>::New(isolate, jsblock)
2014-09-19 13:53:55 -07:00
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-09-19 13:53:55 -07:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
delete data;
delete req;
}
2014-09-22 10:19:37 -07:00
/**
2014-12-03 10:57:56 -08:00
* GetTransaction()
2014-12-08 11:31:00 -08:00
* bitcoind.getTransaction(txid, [blockhash], callback)
2014-10-06 11:05:52 -07:00
* Read any transaction from disk asynchronously.
2014-09-22 10:19:37 -07:00
*/
2014-12-03 10:57:56 -08:00
NAN_METHOD(GetTransaction) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-09-26 11:23:21 -07:00
if (args.Length() < 3
2014-09-22 13:21:42 -07:00
|| !args[0]->IsString()
|| !args[1]->IsString()
2014-12-08 13:36:54 -08:00
|| !args[2]->IsFunction()) {
2014-09-22 13:21:42 -07:00
return NanThrowError(
2014-12-08 13:36:54 -08:00
"Usage: bitcoindjs.getTransaction(txid, [blockhash], callback)");
2014-09-22 13:21:42 -07:00
}
2014-12-08 11:31:00 -08:00
String::Utf8Value txid_(args[0]->ToString());
String::Utf8Value blockhash_(args[1]->ToString());
2014-12-08 13:36:54 -08:00
Local<Function> callback = Local<Function>::Cast(args[2]);
2014-09-22 13:21:42 -07:00
2014-12-08 11:31:00 -08:00
std::string txid = std::string(*txid_);
std::string blockhash = std::string(*blockhash_);
2014-09-22 13:21:42 -07:00
2014-12-08 11:31:00 -08:00
if (blockhash == "") {
blockhash = uint256(0).GetHex();
2014-09-22 13:21:42 -07:00
}
async_tx_data *data = new async_tx_data();
data->err_msg = std::string("");
2014-12-08 11:31:00 -08:00
data->txid = txid;
data->blockhash = blockhash;
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
2014-09-22 13:21:42 -07:00
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_get_tx,
(uv_after_work_cb)async_get_tx_after);
assert(status == 0);
NanReturnValue(Undefined(isolate));
2014-09-22 13:21:42 -07:00
}
static void
async_get_tx(uv_work_t *req) {
async_tx_data* data = static_cast<async_tx_data*>(req->data);
2014-12-08 11:31:00 -08:00
uint256 hash(data->txid);
uint256 blockhash(data->blockhash);
2014-10-02 13:24:18 -07:00
CTransaction ctx;
2014-09-22 13:21:42 -07:00
2014-12-08 13:36:54 -08:00
if (get_tx(hash, blockhash, ctx)) {
data->ctx = ctx;
2014-12-08 11:32:11 -08:00
data->blockhash = blockhash.GetHex();
2014-09-22 13:21:42 -07:00
} else {
2014-12-10 10:47:02 -08:00
data->err_msg = std::string("Transaction not found.");
2014-12-04 15:38:35 -08:00
}
2014-09-22 13:21:42 -07:00
}
static void
async_get_tx_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-09-22 13:21:42 -07:00
async_tx_data* data = static_cast<async_tx_data*>(req->data);
CTransaction ctx = data->ctx;
2014-12-08 11:31:00 -08:00
uint256 blockhash(data->blockhash);
Local<Function> cb = data->callback.Get(isolate);
2014-09-22 13:21:42 -07:00
2014-11-11 11:38:51 -08:00
if (data->err_msg != "") {
2014-11-11 11:36:20 -08:00
Local<Value> err = Exception::Error(NanNew<String>(data->err_msg));
2014-09-22 13:21:42 -07:00
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-09-22 13:21:42 -07:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
2014-10-02 13:24:18 -07:00
Local<Object> jstx = NanNew<Object>();
2014-12-08 11:31:00 -08:00
ctx_to_jstx(ctx, blockhash, jstx);
2014-09-22 13:21:42 -07:00
const unsigned argc = 2;
Local<Value> argv[argc] = {
2015-06-08 16:08:18 -07:00
Local<Value>::New(isolate, NanNull()),
Local<Value>::New(isolate, jstx)
2014-09-22 13:21:42 -07:00
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-09-22 13:21:42 -07:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
delete data;
delete req;
}
2014-09-22 10:19:37 -07:00
2014-09-25 12:05:39 -07:00
/**
2014-10-06 11:05:52 -07:00
* BroadcastTx()
2014-09-25 13:12:28 -07:00
* bitcoind.broadcastTx(tx, override_fees, own_only, callback)
2014-10-06 11:05:52 -07:00
* Broadcast a raw transaction. This can be used to relay transaction received
* or to broadcast one's own transaction.
2014-09-25 12:05:39 -07:00
*/
NAN_METHOD(BroadcastTx) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-09-25 13:12:28 -07:00
if (args.Length() < 4
2014-09-25 12:05:39 -07:00
|| !args[0]->IsObject()
2014-09-25 12:38:42 -07:00
|| !args[1]->IsBoolean()
2014-09-25 13:12:28 -07:00
|| !args[2]->IsBoolean()
|| !args[3]->IsFunction()) {
2014-09-25 12:05:39 -07:00
return NanThrowError(
2014-09-25 13:12:28 -07:00
"Usage: bitcoindjs.broadcastTx(tx, override_fees, own_only, callback)");
2014-09-25 12:05:39 -07:00
}
2014-10-02 13:24:18 -07:00
Local<Object> jstx = Local<Object>::Cast(args[0]);
2014-09-25 13:12:28 -07:00
Local<Function> callback = Local<Function>::Cast(args[3]);
2014-09-25 12:05:39 -07:00
2014-09-25 12:38:42 -07:00
async_broadcast_tx_data *data = new async_broadcast_tx_data();
2014-09-25 12:05:39 -07:00
data->override_fees = args[1]->ToBoolean()->IsTrue();
2014-09-25 13:12:28 -07:00
data->own_only = args[2]->ToBoolean()->IsTrue();
2014-09-25 12:05:39 -07:00
data->err_msg = std::string("");
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
2014-09-25 12:05:39 -07:00
Eternal<Object> eternalObject(isolate, jstx);
data->jstx = eternalObject;
CTransaction ctx;
jstx_to_ctx(jstx, ctx);
data->ctx = ctx;
2014-09-25 12:05:39 -07:00
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_broadcast_tx,
(uv_after_work_cb)async_broadcast_tx_after);
assert(status == 0);
NanReturnValue(Undefined(isolate));
2014-09-25 12:05:39 -07:00
}
static void
async_broadcast_tx(uv_work_t *req) {
2014-09-25 12:38:42 -07:00
async_broadcast_tx_data* data = static_cast<async_broadcast_tx_data*>(req->data);
2014-09-25 12:05:39 -07:00
bool fOverrideFees = false;
2014-09-25 13:12:28 -07:00
bool fOwnOnly = false;
2014-09-25 12:38:42 -07:00
2014-09-25 12:05:39 -07:00
if (data->override_fees) {
fOverrideFees = true;
}
2014-09-25 13:12:28 -07:00
if (data->own_only) {
fOwnOnly = true;
}
CTransaction ctx = data->ctx;
2014-09-25 12:05:39 -07:00
2014-10-02 13:24:18 -07:00
uint256 hashTx = ctx.GetHash();
2014-09-25 12:05:39 -07:00
bool fHave = false;
CCoinsViewCache &view = *pcoinsTip;
CCoins existingCoins;
2014-09-25 13:40:18 -07:00
if (fOwnOnly) {
2014-09-25 12:05:39 -07:00
fHave = view.GetCoins(hashTx, existingCoins);
if (!fHave) {
CValidationState state;
2014-10-02 13:24:18 -07:00
if (!AcceptToMemoryPool(mempool, state, ctx, false, NULL, !fOverrideFees)) {
2014-09-25 12:05:39 -07:00
data->err_msg = std::string("TX rejected");
return;
}
}
}
if (fHave) {
if (existingCoins.nHeight < 1000000000) {
data->err_msg = std::string("transaction already in block chain");
return;
}
}
RelayTransaction(ctx);
2014-09-25 12:05:39 -07:00
2014-12-08 11:31:00 -08:00
data->txid = hashTx.GetHex();
2014-09-25 12:05:39 -07:00
}
static void
async_broadcast_tx_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-09-25 12:38:42 -07:00
async_broadcast_tx_data* data = static_cast<async_broadcast_tx_data*>(req->data);
Local<Function> cb = data->callback.Get(isolate);
Local<Object> obj = data->jstx.Get(isolate);
2014-09-25 12:05:39 -07:00
2014-11-11 11:38:51 -08:00
if (data->err_msg != "") {
2014-11-11 11:36:20 -08:00
Local<Value> err = Exception::Error(NanNew<String>(data->err_msg));
2014-09-25 12:05:39 -07:00
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-09-25 12:05:39 -07:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
2014-09-25 14:01:50 -07:00
const unsigned argc = 3;
2014-09-25 12:05:39 -07:00
Local<Value> argv[argc] = {
2015-06-08 16:08:18 -07:00
Local<Value>::New(isolate, NanNull()),
Local<Value>::New(isolate, NanNew<String>(data->txid)),
Local<Value>::New(isolate, obj)
2014-09-25 12:05:39 -07:00
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-09-25 12:05:39 -07:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
delete data;
delete req;
}
2014-09-26 11:23:21 -07:00
/**
2014-10-06 11:05:52 -07:00
* VerifyBlock()
* bitcoindjs.verifyBlock(block)
* This will verify the authenticity of a block (merkleRoot, etc)
* using the internal bitcoind functions.
2014-09-26 11:23:21 -07:00
*/
NAN_METHOD(VerifyBlock) {
NanScope();
2014-09-26 11:39:25 -07:00
if (args.Length() < 1 || !args[0]->IsObject()) {
2014-09-26 11:23:21 -07:00
return NanThrowError(
2014-09-26 11:39:25 -07:00
"Usage: bitcoindjs.verifyBlock(block)");
2014-09-26 11:23:21 -07:00
}
2014-10-02 13:24:18 -07:00
Local<Object> jsblock = Local<Object>::Cast(args[0]);
2014-09-26 11:39:25 -07:00
2014-10-02 13:24:18 -07:00
String::Utf8Value block_hex_(jsblock->Get(NanNew<String>("hex"))->ToString());
2014-09-26 11:39:25 -07:00
std::string block_hex = std::string(*block_hex_);
2014-09-26 11:23:21 -07:00
2014-10-02 13:24:18 -07:00
CBlock cblock;
jsblock_to_cblock(jsblock, cblock);
2014-09-26 11:23:21 -07:00
CValidationState state;
2014-10-02 13:24:18 -07:00
bool valid = CheckBlock(cblock, state);
2014-09-26 11:23:21 -07:00
NanReturnValue(NanNew<Boolean>(valid));
}
2014-09-26 11:34:55 -07:00
/**
2014-10-06 11:05:52 -07:00
* VerifyTransaction()
* bitcoindjs.verifyTransaction(tx)
* This will verify a transaction, ensuring it is signed properly using the
* internal bitcoind functions.
2014-09-26 11:34:55 -07:00
*/
NAN_METHOD(VerifyTransaction) {
NanScope();
2014-09-26 11:39:25 -07:00
if (args.Length() < 1 || !args[0]->IsObject()) {
2014-09-26 11:34:55 -07:00
return NanThrowError(
2014-09-26 11:39:25 -07:00
"Usage: bitcoindjs.verifyTransaction(tx)");
2014-09-26 11:34:55 -07:00
}
2014-10-02 13:24:18 -07:00
Local<Object> jstx = Local<Object>::Cast(args[0]);
2014-09-26 11:39:25 -07:00
2014-10-02 13:24:18 -07:00
String::Utf8Value tx_hex_(jstx->Get(NanNew<String>("hex"))->ToString());
2014-09-26 11:39:25 -07:00
std::string tx_hex = std::string(*tx_hex_);
2014-09-26 11:34:55 -07:00
2014-10-02 13:24:18 -07:00
CTransaction ctx;
jstx_to_ctx(jstx, ctx);
2014-09-26 11:34:55 -07:00
CValidationState state;
2014-10-02 13:24:18 -07:00
bool valid = CheckTransaction(ctx, state);
2014-09-26 11:34:55 -07:00
2014-09-29 12:18:29 -07:00
std::string reason;
2014-10-02 13:24:18 -07:00
bool standard = IsStandardTx(ctx, reason);
2014-09-26 11:34:55 -07:00
NanReturnValue(NanNew<Boolean>(valid && standard));
}
2014-10-17 13:26:27 -07:00
/**
* GetInfo()
2014-10-17 16:12:57 -07:00
* bitcoindjs.getInfo()
2014-10-17 13:26:27 -07:00
* Get miscellaneous information
*/
NAN_METHOD(GetInfo) {
NanScope();
if (args.Length() > 0) {
return NanThrowError(
"Usage: bitcoindjs.getInfo()");
}
2014-10-17 13:47:56 -07:00
Local<Object> obj = NanNew<Object>();
2014-10-17 13:26:27 -07:00
proxyType proxy;
GetProxy(NET_IPV4, proxy);
2014-10-17 13:47:56 -07:00
obj->Set(NanNew<String>("version"), NanNew<Number>(CLIENT_VERSION));
obj->Set(NanNew<String>("protocolversion"), NanNew<Number>(PROTOCOL_VERSION));
obj->Set(NanNew<String>("blocks"), NanNew<Number>((int)chainActive.Height())->ToInt32());
obj->Set(NanNew<String>("timeoffset"), NanNew<Number>(GetTimeOffset()));
obj->Set(NanNew<String>("connections"), NanNew<Number>((int)vNodes.size())->ToInt32());
2014-10-17 14:00:12 -07:00
obj->Set(NanNew<String>("proxy"), NanNew<String>(proxy.IsValid() ? proxy.ToStringIPPort() : std::string("")));
2014-10-17 13:47:56 -07:00
obj->Set(NanNew<String>("difficulty"), NanNew<Number>((double)GetDifficulty()));
obj->Set(NanNew<String>("testnet"), NanNew<Boolean>(Params().NetworkIDString() == "test"));
2014-10-17 13:47:56 -07:00
obj->Set(NanNew<String>("relayfee"), NanNew<Number>(::minRelayTxFee.GetFeePerK())); // double
2014-10-17 14:00:12 -07:00
obj->Set(NanNew<String>("errors"), NanNew<String>(GetWarnings("statusbar")));
2014-10-17 13:26:27 -07:00
NanReturnValue(obj);
}
2014-10-17 13:47:56 -07:00
/**
* GetPeerInfo()
2014-10-17 16:12:57 -07:00
* bitcoindjs.getPeerInfo()
2014-10-17 13:47:56 -07:00
* Get peer information
*/
NAN_METHOD(GetPeerInfo) {
NanScope();
if (args.Length() > 0) {
return NanThrowError(
"Usage: bitcoindjs.getPeerInfo()");
}
Local<Array> array = NanNew<Array>();
int i = 0;
vector<CNodeStats> vstats;
2014-10-17 14:00:12 -07:00
vstats.clear();
LOCK(cs_vNodes);
vstats.reserve(vNodes.size());
BOOST_FOREACH(CNode* pnode, vNodes) {
CNodeStats stats;
pnode->copyStats(stats);
vstats.push_back(stats);
}
2014-10-17 13:47:56 -07:00
BOOST_FOREACH(const CNodeStats& stats, vstats) {
Local<Object> obj = NanNew<Object>();
CNodeStateStats statestats;
bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
obj->Set(NanNew<String>("id"), NanNew<Number>(stats.nodeid));
obj->Set(NanNew<String>("addr"), NanNew<String>(stats.addrName));
if (!(stats.addrLocal.empty())) {
obj->Set(NanNew<String>("addrlocal"), NanNew<String>(stats.addrLocal));
}
obj->Set(NanNew<String>("services"), NanNew<String>(strprintf("%016x", stats.nServices)));
obj->Set(NanNew<String>("lastsend"), NanNew<Number>(stats.nLastSend));
obj->Set(NanNew<String>("lastrecv"), NanNew<Number>(stats.nLastRecv));
obj->Set(NanNew<String>("bytessent"), NanNew<Number>(stats.nSendBytes));
obj->Set(NanNew<String>("bytesrecv"), NanNew<Number>(stats.nRecvBytes));
obj->Set(NanNew<String>("conntime"), NanNew<Number>(stats.nTimeConnected));
obj->Set(NanNew<String>("pingtime"), NanNew<Number>(stats.dPingTime)); // double
if (stats.dPingWait > 0.0) {
obj->Set(NanNew<String>("pingwait"), NanNew<Number>(stats.dPingWait)); // double
}
obj->Set(NanNew<String>("version"), NanNew<Number>(stats.nVersion));
obj->Set(NanNew<String>("subver"), NanNew<String>(stats.cleanSubVer));
obj->Set(NanNew<String>("inbound"), NanNew<Boolean>(stats.fInbound));
obj->Set(NanNew<String>("startingheight"), NanNew<Number>(stats.nStartingHeight));
if (fStateStats) {
obj->Set(NanNew<String>("banscore"), NanNew<Number>(statestats.nMisbehavior));
2014-10-17 14:00:12 -07:00
obj->Set(NanNew<String>("syncheight"), NanNew<Number>(statestats.nSyncHeight)->ToInt32());
obj->Set(NanNew<String>("synced_headers"), NanNew<Number>(statestats.nSyncHeight)->ToInt32());
obj->Set(NanNew<String>("synced_blocks"), NanNew<Number>(statestats.nCommonHeight)->ToInt32());
Local<Array> heights = NanNew<Array>();
int hi = 0;
BOOST_FOREACH(int height, statestats.vHeightInFlight) {
heights->Set(hi, NanNew<Number>(height));
hi++;
}
obj->Set(NanNew<String>("inflight"), heights);
2014-10-17 13:47:56 -07:00
}
2014-10-17 13:47:56 -07:00
obj->Set(NanNew<String>("whitelisted"), NanNew<Boolean>(stats.fWhitelisted));
2014-10-17 14:23:19 -07:00
// obj->Set(NanNew<String>("relaytxes"), NanNew<Boolean>(stats.fRelayTxes));
2014-10-17 13:47:56 -07:00
array->Set(i, obj);
i++;
}
NanReturnValue(array);
}
2014-10-17 16:12:57 -07:00
/**
* GetAddresses()
* bitcoindjs.getAddresses()
* Get all addresses
*/
NAN_METHOD(GetAddresses) {
NanScope();
if (args.Length() > 0) {
return NanThrowError(
"Usage: bitcoindjs.getAddresses()");
}
Local<Array> array = NanNew<Array>();
int i = 0;
std::vector<CAddress> vAddr = addrman.GetAddr();
BOOST_FOREACH(const CAddress& addr, vAddr) {
Local<Object> obj = NanNew<Object>();
char nServices[21] = {0};
2015-06-04 11:54:57 -07:00
int written = snprintf(nServices, sizeof(nServices), "%020llu", (uint64_t)addr.nServices);
2014-10-17 16:12:57 -07:00
assert(written == 20);
obj->Set(NanNew<String>("services"), NanNew<String>((char *)nServices));
obj->Set(NanNew<String>("time"), NanNew<Number>((unsigned int)addr.nTime)->ToUint32());
obj->Set(NanNew<String>("last"), NanNew<Number>((int64_t)addr.nLastTry));
obj->Set(NanNew<String>("ip"), NanNew<String>((std::string)addr.ToStringIP()));
obj->Set(NanNew<String>("port"), NanNew<Number>((unsigned short)addr.GetPort())->ToUint32());
obj->Set(NanNew<String>("address"), NanNew<String>((std::string)addr.ToStringIPPort()));
array->Set(i, obj);
i++;
}
NanReturnValue(array);
}
2014-10-28 13:01:40 -07:00
/**
* GetProgress()
* bitcoindjs.getProgress(callback)
* Get progress of blockchain download
*/
NAN_METHOD(GetProgress) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-10-28 13:01:40 -07:00
if (args.Length() < 1 || !args[0]->IsFunction()) {
return NanThrowError(
"Usage: bitcoindjs.getProgress(callback)");
}
Local<Function> callback = Local<Function>::Cast(args[0]);
async_block_data *data = new async_block_data();
data->err_msg = std::string("");
2014-11-12 11:57:04 -08:00
CBlockIndex *pindex = chainActive.Tip();
2014-11-17 13:13:55 -08:00
data->hash = pindex->GetBlockHash().GetHex();
2014-11-12 11:11:38 -08:00
data->height = -1;
2014-11-11 16:10:26 -08:00
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
2014-10-28 13:01:40 -07:00
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
2014-11-11 16:10:26 -08:00
req, async_get_progress,
2014-10-28 13:01:40 -07:00
(uv_after_work_cb)async_get_progress_after);
assert(status == 0);
NanReturnValue(Undefined(isolate));
2014-10-28 13:01:40 -07:00
}
static void
2014-11-11 16:10:26 -08:00
async_get_progress(uv_work_t *req) {
async_get_block(req);
}
2014-10-28 13:01:40 -07:00
static void
async_get_progress_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-10-28 13:01:40 -07:00
async_block_data* data = static_cast<async_block_data*>(req->data);
Local<Function> cb = data->callback.Get(isolate);
2014-10-28 13:01:40 -07:00
2014-11-11 11:38:51 -08:00
if (data->err_msg != "") {
2014-11-11 11:36:20 -08:00
Local<Value> err = Exception::Error(NanNew<String>(data->err_msg));
2014-10-28 13:01:40 -07:00
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-10-28 13:01:40 -07:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
2014-11-04 16:08:31 -08:00
const CBlock& cblock = data->cblock;
CBlockIndex* cblock_index = data->cblock_index;
Local<Object> jsblock = NanNew<Object>();
cblock_to_jsblock(cblock, cblock_index, jsblock, false);
const CBlock& cgenesis = Params().GenesisBlock();
Local<Object> genesis = NanNew<Object>();
cblock_to_jsblock(cgenesis, NULL, genesis, false);
2014-10-28 13:01:40 -07:00
2014-11-12 16:05:07 -08:00
// Get progress:
double progress = Checkpoints::GuessVerificationProgress(cblock_index, false);
2014-10-28 13:01:40 -07:00
2014-11-12 16:05:07 -08:00
// Get time left (assume last block was ten minutes ago):
int64_t now = ((int64_t)time(NULL) - (10 * 60));
int64_t left = now - (progress * now);
2014-11-12 16:05:07 -08:00
// Calculate tangible progress:
unsigned int hours_behind = left / 60 / 60;
unsigned int days_behind = left / 60 / 60 / 24;
2014-11-12 16:05:07 -08:00
unsigned int percent = (unsigned int)(progress * 100.0);
2014-11-12 16:20:38 -08:00
if (percent == 100 || left < 0) {
hours_behind = 0;
days_behind = 0;
}
Local<Object> result = NanNew<Object>();
2014-10-28 13:01:40 -07:00
result->Set(NanNew<String>("blocks"),
NanNew<Number>(cblock_index->nHeight));
result->Set(NanNew<String>("connections"),
NanNew<Number>((int)vNodes.size())->ToInt32());
result->Set(NanNew<String>("genesisBlock"), genesis);
result->Set(NanNew<String>("currentBlock"), jsblock);
result->Set(NanNew<String>("hoursBehind"), NanNew<Number>(hours_behind));
result->Set(NanNew<String>("daysBehind"), NanNew<Number>(days_behind));
result->Set(NanNew<String>("percent"), NanNew<Number>(percent));
2014-10-28 13:01:40 -07:00
const unsigned argc = 2;
Local<Value> argv[argc] = {
2015-06-08 16:08:18 -07:00
Local<Value>::New(isolate, NanNull()),
Local<Value>::New(isolate,result)
2014-10-28 13:01:40 -07:00
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-10-28 13:01:40 -07:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
delete data;
delete req;
}
2014-10-28 14:16:33 -07:00
/**
* GetMiningInfo()
* bitcoindjs.getMiningInfo()
* Get coin generation / mining information
*/
NAN_METHOD(GetMiningInfo) {
NanScope();
Local<Object> obj = NanNew<Object>();
2014-10-29 15:07:25 -07:00
json_spirit::Array empty_params;
obj->Set(NanNew<String>("blocks"), NanNew<Number>((int)chainActive.Height()));
obj->Set(NanNew<String>("currentblocksize"), NanNew<Number>((uint64_t)nLastBlockSize));
obj->Set(NanNew<String>("currentblocktx"), NanNew<Number>((uint64_t)nLastBlockTx));
obj->Set(NanNew<String>("difficulty"), NanNew<Number>((double)GetDifficulty()));
obj->Set(NanNew<String>("errors"), NanNew<String>(GetWarnings("statusbar")));
obj->Set(NanNew<String>("genproclimit"), NanNew<Number>((int)GetArg("-genproclimit", -1)));
obj->Set(NanNew<String>("networkhashps"), NanNew<Number>(
(int64_t)getnetworkhashps(empty_params, false).get_int64()));
obj->Set(NanNew<String>("pooledtx"), NanNew<Number>((uint64_t)mempool.size()));
obj->Set(NanNew<String>("testnet"), NanNew<Boolean>(Params().NetworkIDString() == "test"));
2014-10-29 15:07:25 -07:00
obj->Set(NanNew<String>("chain"), NanNew<String>(Params().NetworkIDString()));
2014-10-28 14:16:33 -07:00
NanReturnValue(obj);
}
2014-11-04 16:08:31 -08:00
/**
* GetAddrTransactions()
* bitcoind.getAddrTransactions(addr, callback)
* Read any transaction from disk asynchronously.
*/
NAN_METHOD(GetAddrTransactions) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-11-04 16:08:31 -08:00
if (args.Length() < 2
|| (!args[0]->IsString() && !args[0]->IsObject())
2014-11-04 16:08:31 -08:00
|| !args[1]->IsFunction()) {
return NanThrowError(
"Usage: bitcoindjs.getAddrTransactions(addr, callback)");
}
std::string addr = "";
int64_t blockheight = -1;
2014-12-03 21:16:47 -08:00
int64_t blocktime = -1;
if (args[0]->IsString()) {
String::Utf8Value addr_(args[0]->ToString());
addr = std::string(*addr_);
} else if (args[0]->IsObject()) {
Local<Object> options = Local<Object>::Cast(args[0]);
if (options->Get(NanNew<String>("address"))->IsString()) {
String::Utf8Value s_(options->Get(NanNew<String>("address"))->ToString());
addr = std::string(*s_);
}
if (options->Get(NanNew<String>("addr"))->IsString()) {
String::Utf8Value s_(options->Get(NanNew<String>("addr"))->ToString());
addr = std::string(*s_);
}
if (options->Get(NanNew<String>("height"))->IsNumber()) {
blockheight = options->Get(NanNew<String>("height"))->IntegerValue();
}
if (options->Get(NanNew<String>("blockheight"))->IsNumber()) {
blockheight = options->Get(NanNew<String>("blockheight"))->IntegerValue();
}
2014-12-03 21:16:47 -08:00
if (options->Get(NanNew<String>("time"))->IsNumber()) {
blocktime = options->Get(NanNew<String>("time"))->IntegerValue();
}
if (options->Get(NanNew<String>("blocktime"))->IsNumber()) {
blocktime = options->Get(NanNew<String>("blocktime"))->IntegerValue();
}
}
2014-11-05 17:27:51 -08:00
Local<Function> callback = Local<Function>::Cast(args[1]);
2014-11-04 16:08:31 -08:00
async_addrtx_data *data = new async_addrtx_data();
data->err_msg = std::string("");
data->addr = addr;
2014-11-05 11:56:37 -08:00
data->ctxs = NULL;
data->blockheight = blockheight;
2014-12-03 21:16:47 -08:00
data->blocktime = blocktime;
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
2014-11-04 16:08:31 -08:00
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_get_addrtx,
(uv_after_work_cb)async_get_addrtx_after);
assert(status == 0);
NanReturnValue(Undefined(isolate));
2014-11-04 16:08:31 -08:00
}
static void
async_get_addrtx(uv_work_t *req) {
async_addrtx_data* data = static_cast<async_addrtx_data*>(req->data);
if (data->addr.empty()) {
data->err_msg = std::string("Invalid address.");
return;
}
2014-11-04 16:08:31 -08:00
CBitcoinAddress address = CBitcoinAddress(data->addr);
if (!address.IsValid()) {
2014-11-14 14:51:20 -08:00
data->err_msg = std::string("Invalid address.");
2014-11-04 16:08:31 -08:00
return;
}
2014-11-19 13:42:11 -08:00
#if !USE_LDB_ADDR
2014-11-04 16:08:31 -08:00
CScript expected = GetScriptForDestination(address.Get());
int64_t i = 0;
if (data->blockheight != -1) {
i = data->blockheight;
}
2014-11-04 16:08:31 -08:00
int64_t height = chainActive.Height();
for (; i <= height; i++) {
CBlockIndex* pblockindex = chainActive[i];
CBlock cblock;
if (ReadBlockFromDisk(cblock, pblockindex)) {
BOOST_FOREACH(const CTransaction& ctx, cblock.vtx) {
// vin
BOOST_FOREACH(const CTxIn& txin, ctx.vin) {
2014-11-06 16:16:41 -08:00
if (txin.scriptSig.ToString() == expected.ToString()) {
2014-11-04 16:08:31 -08:00
ctx_list *item = new ctx_list();
item->ctx = ctx;
item->blockhash = cblock.GetHash();
2014-11-04 16:08:31 -08:00
if (data->ctxs == NULL) {
data->ctxs = item;
} else {
data->ctxs->next = item;
data->ctxs = item;
}
goto done;
}
}
// vout
for (unsigned int vo = 0; vo < ctx.vout.size(); vo++) {
const CTxOut& txout = ctx.vout[vo];
const CScript& scriptPubKey = txout.scriptPubKey;
txnouttype type;
vector<CTxDestination> addresses;
int nRequired;
if (ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
BOOST_FOREACH(const CTxDestination& addr, addresses) {
std::string str_addr = CBitcoinAddress(addr).ToString();
if (data->addr == str_addr) {
ctx_list *item = new ctx_list();
item->ctx = ctx;
item->blockhash = cblock.GetHash();
2014-11-04 16:08:31 -08:00
if (data->ctxs == NULL) {
data->ctxs = item;
} else {
data->ctxs->next = item;
data->ctxs = item;
}
goto done;
}
}
}
}
}
done:
continue;
} else {
2014-12-10 10:47:02 -08:00
data->err_msg = std::string("Address not found.");
2014-11-04 16:08:31 -08:00
break;
}
}
return;
2014-11-06 16:16:18 -08:00
#else
2014-12-03 21:16:47 -08:00
ctx_list *ctxs = read_addr(data->addr, data->blockheight, data->blocktime);
2014-12-01 15:12:01 -08:00
if (!ctxs->err_msg.empty()) {
data->err_msg = ctxs->err_msg;
2014-12-01 15:09:47 -08:00
return;
}
2014-11-05 11:56:37 -08:00
data->ctxs = ctxs;
if (data->ctxs == NULL) {
data->err_msg = std::string("Could not read database.");
}
2014-11-10 15:28:38 -08:00
#endif
2014-11-04 16:08:31 -08:00
}
static void
async_get_addrtx_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-11-04 16:08:31 -08:00
async_addrtx_data* data = static_cast<async_addrtx_data*>(req->data);
Local<Function> cb = data->callback.Get(isolate);
2014-11-04 16:08:31 -08:00
2014-11-11 11:38:51 -08:00
if (data->err_msg != "") {
2014-11-11 11:36:20 -08:00
Local<Value> err = Exception::Error(NanNew<String>(data->err_msg));
2014-11-04 16:08:31 -08:00
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-11-04 16:08:31 -08:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Object> result = NanNew<Object>();
Local<Array> tx = NanNew<Array>();
int i = 0;
ctx_list *next;
for (ctx_list *item = data->ctxs; item; item = next) {
Local<Object> jstx = NanNew<Object>();
2014-11-05 11:56:37 -08:00
ctx_to_jstx(item->ctx, item->blockhash, jstx);
2014-11-04 16:08:31 -08:00
tx->Set(i, jstx);
i++;
next = item->next;
delete item;
}
result->Set(NanNew<String>("address"), NanNew<String>(data->addr));
result->Set(NanNew<String>("tx"), tx);
Local<Value> argv[argc] = {
2015-06-08 16:08:18 -07:00
Local<Value>::New(isolate, NanNull()),
Local<Value>::New(isolate, result)
2014-11-04 16:08:31 -08:00
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-11-04 16:08:31 -08:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
delete data;
delete req;
}
2014-11-06 13:37:15 -08:00
/**
* GetBestBlock()
* bitcoindjs.getBestBlock()
* Get the best block
*/
NAN_METHOD(GetBestBlock) {
NanScope();
if (args.Length() < 0) {
return NanThrowError(
"Usage: bitcoindjs.getBestBlock()");
}
2014-11-14 14:51:20 -08:00
uint256 hash = pcoinsTip->GetBestBlock();
2014-11-06 13:37:15 -08:00
2014-11-14 14:51:20 -08:00
NanReturnValue(NanNew<String>(hash.GetHex()));
2014-11-06 13:37:15 -08:00
}
/**
* GetChainHeight()
* bitcoindjs.getChainHeight()
* Get miscellaneous information
*/
NAN_METHOD(GetChainHeight) {
NanScope();
if (args.Length() > 0) {
return NanThrowError(
"Usage: bitcoindjs.getChainHeight()");
}
NanReturnValue(NanNew<Number>((int)chainActive.Height())->ToInt32());
}
2014-12-03 12:14:23 -08:00
/**
* GetBlockByTx()
* bitcoindjs.getBlockByTx()
2014-12-03 12:16:29 -08:00
* Get block by tx hash (requires -txindex or it's very slow)
2014-12-03 12:14:23 -08:00
*/
NAN_METHOD(GetBlockByTx) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-12-03 12:14:23 -08:00
if (args.Length() < 2
|| !args[0]->IsString()
|| !args[1]->IsFunction()) {
return NanThrowError(
"Usage: bitcoindjs.getBlockByTx(txid, callback)");
}
async_block_tx_data *data = new async_block_tx_data();
uv_work_t *req = new uv_work_t();
req->data = data;
2014-12-03 12:16:29 -08:00
String::Utf8Value txid_(args[0]->ToString());
std::string txid = std::string(*txid_);
2014-12-03 12:14:23 -08:00
data->err_msg = std::string("");
2014-12-03 12:16:29 -08:00
data->txid = txid;
2014-12-03 12:14:23 -08:00
Local<Function> callback = Local<Function>::Cast(args[1]);
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
2014-12-03 12:14:23 -08:00
int status = uv_queue_work(uv_default_loop(),
req, async_block_tx,
(uv_after_work_cb)async_block_tx_after);
assert(status == 0);
NanReturnValue(Undefined(isolate));
2014-12-03 12:14:23 -08:00
}
static void
async_block_tx(uv_work_t *req) {
async_block_tx_data* data = static_cast<async_block_tx_data*>(req->data);
2014-12-08 10:00:53 -08:00
#if USE_LDB_TX
2014-12-03 12:14:23 -08:00
if (!g_txindex) {
parse:
2014-12-08 10:00:53 -08:00
#endif
2014-12-03 12:14:23 -08:00
int64_t i = 0;
int64_t height = chainActive.Height();
for (; i <= height; i++) {
CBlockIndex* pblockindex = chainActive[i];
CBlock cblock;
if (ReadBlockFromDisk(cblock, pblockindex)) {
2014-12-10 16:22:30 -08:00
BOOST_FOREACH(const CTransaction& tx, cblock.vtx) {
if (tx.GetHash().GetHex() == data->txid) {
2014-12-03 12:14:23 -08:00
data->cblock = cblock;
data->cblock_index = pblockindex;
2014-12-10 16:22:30 -08:00
data->ctx = tx;
2014-12-03 12:14:23 -08:00
return;
}
}
}
}
data->err_msg = std::string("Block not found.");
return;
2014-12-08 10:00:53 -08:00
#if USE_LDB_TX
2014-12-03 12:14:23 -08:00
}
2014-12-10 16:22:30 -08:00
if (!get_block_by_tx(data->txid, data->cblock, &data->cblock_index, data->ctx)) {
2014-12-03 12:14:23 -08:00
goto parse;
}
2014-12-08 10:00:53 -08:00
#endif
2014-12-03 12:14:23 -08:00
}
static void
async_block_tx_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-12-03 12:14:23 -08:00
async_block_tx_data* data = static_cast<async_block_tx_data*>(req->data);
Local<Function> cb = data->callback.Get(isolate);
2014-12-03 12:14:23 -08:00
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);
2014-12-03 12:14:23 -08:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const CBlock& cblock = data->cblock;
CBlockIndex* cblock_index = data->cblock_index;
2014-12-10 16:22:30 -08:00
const CTransaction& ctx = data->ctx;
2014-12-03 12:14:23 -08:00
Local<Object> jsblock = NanNew<Object>();
cblock_to_jsblock(cblock, cblock_index, jsblock, false);
2014-12-10 16:22:30 -08:00
Local<Object> jstx = NanNew<Object>();
ctx_to_jstx(ctx, cblock.GetHash(), jstx);
2014-12-10 16:28:35 -08:00
const unsigned argc = 3;
2014-12-03 12:14:23 -08:00
Local<Value> argv[argc] = {
2015-06-08 16:08:18 -07:00
Local<Value>::New(isolate, NanNull()),
Local<Value>::New(isolate, jsblock),
Local<Value>::New(isolate, jstx)
2014-12-03 12:14:23 -08:00
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-12-03 12:14:23 -08:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
delete data;
delete req;
}
2014-12-03 12:46:48 -08:00
/**
2014-12-04 11:12:29 -08:00
* GetBlocksByTime()
* bitcoindjs.getBlocksByTime()
2014-12-03 12:46:48 -08:00
* Get block by tx hash (requires -txindex or it's very slow)
*/
2014-12-04 11:12:29 -08:00
NAN_METHOD(GetBlocksByTime) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-12-03 12:46:48 -08:00
if (args.Length() < 2
|| !args[0]->IsString()
|| !args[1]->IsFunction()) {
return NanThrowError(
2014-12-04 11:12:29 -08:00
"Usage: bitcoindjs.getBlocksByTime(options, callback)");
2014-12-03 12:46:48 -08:00
}
async_block_time_data *data = new async_block_time_data();
2014-12-03 12:51:36 -08:00
data->gte = 0;
data->lte = 0;
2014-12-03 12:46:48 -08:00
uv_work_t *req = new uv_work_t();
req->data = data;
Local<Object> options = Local<Object>::Cast(args[0]);
if (options->Get(NanNew<String>("gte"))->IsNumber()) {
2014-12-03 12:49:11 -08:00
data->gte = options->Get(NanNew<String>("gte"))->IntegerValue();
2014-12-03 12:46:48 -08:00
}
if (options->Get(NanNew<String>("lte"))->IsNumber()) {
2014-12-03 12:49:11 -08:00
data->lte = options->Get(NanNew<String>("lte"))->IntegerValue();
2014-12-03 12:46:48 -08:00
}
2014-12-04 11:12:29 -08:00
if (options->Get(NanNew<String>("limit"))->IsNumber()) {
data->limit = options->Get(NanNew<String>("limit"))->IntegerValue();
}
2014-12-03 12:46:48 -08:00
data->err_msg = std::string("");
2014-12-04 11:12:29 -08:00
data->cblocks = NULL;
2014-12-03 12:46:48 -08:00
Local<Function> callback = Local<Function>::Cast(args[1]);
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
2014-12-03 12:46:48 -08:00
int status = uv_queue_work(uv_default_loop(),
req, async_block_time,
(uv_after_work_cb)async_block_time_after);
assert(status == 0);
NanReturnValue(Undefined(isolate));
2014-12-03 12:46:48 -08:00
}
static void
async_block_time(uv_work_t *req) {
async_block_time_data* data = static_cast<async_block_time_data*>(req->data);
2014-12-03 12:51:36 -08:00
if (!data->gte && !data->lte) {
data->err_msg = std::string("gte and lte not found.");
return;
}
2014-12-03 12:46:48 -08:00
int64_t i = 0;
// XXX Slow: figure out how to ballpark the height based on gte and lte.
int64_t height = chainActive.Height();
2014-12-04 11:12:29 -08:00
bool found_range = false;
int64_t found = 0;
2014-12-03 12:46:48 -08:00
for (; i <= height; i++) {
CBlockIndex* pblockindex = chainActive[i];
CBlock cblock;
if (ReadBlockFromDisk(cblock, pblockindex)) {
uint32_t blocktime = cblock.GetBlockTime();
if (blocktime >= data->gte && blocktime <= data->lte) {
2014-12-04 11:12:29 -08:00
found_range = true;
cblocks_list *item = new cblocks_list();
item->cblock = cblock;
item->cblock_index = pblockindex;
if (data->cblocks == NULL) {
data->cblocks = item;
} else {
data->cblocks->next = item;
data->cblocks = item;
}
found++;
if (found >= data->limit) return;
} else {
if (found_range) return;
2014-12-03 12:46:48 -08:00
}
}
}
data->err_msg = std::string("Block not found.");
}
static void
async_block_time_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-12-03 12:46:48 -08:00
async_block_time_data* data = static_cast<async_block_time_data*>(req->data);
Local<Function> cb = data->callback.Get(isolate);
2014-12-03 12:46:48 -08:00
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);
2014-12-03 12:46:48 -08:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
2014-12-04 11:12:29 -08:00
Local<Array> jsblocks = NanNew<Array>();
int i = 0;
cblocks_list *next;
for (cblocks_list *item = data->cblocks; item; item = next) {
Local<Object> jsblock = NanNew<Object>();
cblock_to_jsblock(item->cblock, item->cblock_index, jsblock, false);
jsblocks->Set(i, jsblock);
i++;
next = item->next;
delete item;
}
2014-12-03 12:46:48 -08:00
const unsigned argc = 2;
Local<Value> argv[argc] = {
2015-06-08 16:08:18 -07:00
Local<Value>::New(isolate, NanNull()),
Local<Value>::New(isolate, jsblocks)
2014-12-03 12:46:48 -08:00
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-12-03 12:46:48 -08:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
delete data;
delete req;
}
2014-12-16 14:41:00 -08:00
/**
* GetFromTx()
* bitcoindjs.getFromTx()
* Get all TXes beyond a txid
*/
NAN_METHOD(GetFromTx) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-12-16 14:41:00 -08:00
if (args.Length() < 2
|| !args[0]->IsString()
|| !args[1]->IsFunction()) {
return NanThrowError(
"Usage: bitcoindjs.getFromTx(txid, callback)");
}
async_from_tx_data *data = new async_from_tx_data();
uv_work_t *req = new uv_work_t();
req->data = data;
String::Utf8Value txid_(args[0]->ToString());
std::string txid = std::string(*txid_);
data->txid = txid;
data->ctxs = NULL;
data->err_msg = std::string("");
Local<Function> callback = Local<Function>::Cast(args[1]);
Eternal<Function> eternal(isolate, callback);
data->callback = eternal;
2014-12-16 14:41:00 -08:00
int status = uv_queue_work(uv_default_loop(),
req, async_from_tx,
(uv_after_work_cb)async_from_tx_after);
assert(status == 0);
NanReturnValue(Undefined(isolate));
2014-12-16 14:41:00 -08:00
}
static void
async_from_tx(uv_work_t *req) {
async_from_tx_data* data = static_cast<async_from_tx_data*>(req->data);
uint256 txid(data->txid);
bool found = false;
int64_t i = 0;
int64_t height = chainActive.Height();
for (; i <= height; i++) {
CBlockIndex* pblockindex = chainActive[i];
CBlock cblock;
if (ReadBlockFromDisk(cblock, pblockindex)) {
BOOST_FOREACH(const CTransaction& ctx, cblock.vtx) {
if (found || ctx.GetHash() == txid) {
if (!found) found = true;
ctx_list *item = new ctx_list();
item->ctx = ctx;
item->blockhash = cblock.GetHash();
if (data->ctxs == NULL) {
data->ctxs = item;
} else {
data->ctxs->next = item;
data->ctxs = item;
}
}
}
} else {
data->err_msg = std::string("TX not found.");
break;
}
}
}
static void
async_from_tx_after(uv_work_t *req) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-12-16 14:41:00 -08:00
async_from_tx_data* data = static_cast<async_from_tx_data*>(req->data);
Local<Function> cb = data->callback.Get(isolate);
2014-12-16 14:41:00 -08:00
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);
2014-12-16 14:41:00 -08:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Array> tx = NanNew<Array>();
int i = 0;
ctx_list *next;
for (ctx_list *item = data->ctxs; item; item = next) {
Local<Object> jstx = NanNew<Object>();
ctx_to_jstx(item->ctx, item->blockhash, jstx);
tx->Set(i, jstx);
i++;
next = item->next;
delete item;
}
Local<Value> argv[argc] = {
2015-06-08 16:08:18 -07:00
Local<Value>::New(isolate, NanNull()),
Local<Value>::New(isolate, tx)
2014-12-16 14:41:00 -08:00
};
TryCatch try_catch;
cb->Call(isolate->GetCurrentContext()->Global(), argc, argv);
2014-12-16 14:41:00 -08:00
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
delete data;
delete req;
}
/**
* GetLastFileIndex()
* bitcoindjs.getLastFileIndex()
* Get last file index
*/
NAN_METHOD(GetLastFileIndex) {
NanScope();
if (args.Length() > 0) {
return NanThrowError(
"Usage: bitcoindjs.getLastFileIndex(callback)");
}
CBlockIndex *pindex = chainActive.Tip();
CDiskBlockPos blockPos = pindex->GetBlockPos();
NanReturnValue(NanNew<Number>(blockPos.nFile));
}
/**
2014-10-06 11:05:52 -07:00
* GetBlockHex()
* bitcoindjs.getBlockHex(callback)
* This will return the hex value as well as hash of a javascript block object
* (after being converted to a CBlock).
*/
NAN_METHOD(GetBlockHex) {
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
"Usage: bitcoindjs.getBlockHex(block)");
}
Local<Object> jsblock = Local<Object>::Cast(args[0]);
CBlock cblock;
jsblock_to_cblock(jsblock, cblock);
Local<Object> data = NanNew<Object>();
2014-11-11 11:11:12 -08:00
data->Set(NanNew<String>("hash"), NanNew<String>(cblock.GetHash().GetHex()));
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
ssBlock << cblock;
std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
data->Set(NanNew<String>("hex"), NanNew<String>(strHex));
NanReturnValue(data);
}
/**
2014-10-06 11:05:52 -07:00
* GetTxHex()
* bitcoindjs.getTxHex(tx)
* This will return the hex value and hash for any tx, converting a js tx
* object to a CTransaction.
*/
NAN_METHOD(GetTxHex) {
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
"Usage: bitcoindjs.getTxHex(tx)");
}
Local<Object> jstx = Local<Object>::Cast(args[0]);
CTransaction ctx;
jstx_to_ctx(jstx, ctx);
Local<Object> data = NanNew<Object>();
2014-11-11 11:11:12 -08:00
data->Set(NanNew<String>("hash"), NanNew<String>(ctx.GetHash().GetHex()));
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << ctx;
std::string strHex = HexStr(ssTx.begin(), ssTx.end());
data->Set(NanNew<String>("hex"), NanNew<String>(strHex));
NanReturnValue(data);
}
2014-10-03 18:27:06 -07:00
/**
2014-10-06 11:05:52 -07:00
* BlockFromHex()
* bitcoindjs.blockFromHex(hex)
* Create a javascript block from a hex string.
2014-10-03 18:27:06 -07:00
*/
NAN_METHOD(BlockFromHex) {
NanScope();
if (args.Length() < 1 || !args[0]->IsString()) {
return NanThrowError(
"Usage: bitcoindjs.blockFromHex(hex)");
}
String::Utf8Value hex_string_(args[0]->ToString());
2014-10-03 18:27:06 -07:00
std::string hex_string = *hex_string_;
CBlock cblock;
CDataStream ssData(ParseHex(hex_string), SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> cblock;
} catch (std::exception &e) {
2014-11-14 14:51:20 -08:00
return NanThrowError("Bad Block decode");
2014-10-03 18:27:06 -07:00
}
Local<Object> jsblock = NanNew<Object>();
2014-10-23 15:04:28 -07:00
cblock_to_jsblock(cblock, NULL, jsblock, false);
2014-10-03 18:27:06 -07:00
NanReturnValue(jsblock);
}
/**
2014-10-06 11:05:52 -07:00
* TxFromHex()
* bitcoindjs.txFromHex(hex)
* Create a javascript tx from a hex string.
2014-10-03 18:27:06 -07:00
*/
NAN_METHOD(TxFromHex) {
NanScope();
if (args.Length() < 1 || !args[0]->IsString()) {
return NanThrowError(
"Usage: bitcoindjs.txFromHex(hex)");
}
String::Utf8Value hex_string_(args[0]->ToString());
2014-10-03 18:27:06 -07:00
std::string hex_string = *hex_string_;
CTransaction ctx;
CDataStream ssData(ParseHex(hex_string), SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> ctx;
} catch (std::exception &e) {
2014-11-14 14:51:20 -08:00
return NanThrowError("Bad Block decode");
2014-10-03 18:27:06 -07:00
}
Local<Object> jstx = NanNew<Object>();
ctx_to_jstx(ctx, 0, jstx);
2014-10-03 18:27:06 -07:00
NanReturnValue(jstx);
}
2014-09-26 12:20:00 -07:00
/**
2014-10-27 10:59:52 -07:00
* Linked List for queued packets
2014-09-26 12:20:00 -07:00
*/
2014-10-27 10:59:52 -07:00
typedef struct _poll_packets_list {
CNode *pfrom;
char *strCommand;
CDataStream *vRecv;
int64_t nTimeReceived;
struct _poll_packets_list *next;
} poll_packets_list;
2014-09-26 12:20:00 -07:00
2014-10-27 10:59:52 -07:00
poll_packets_list *packets_queue_head = NULL;
poll_packets_list *packets_queue_tail = NULL;
boost::mutex poll_packets_mutex;
2014-09-26 12:20:00 -07:00
2014-10-27 10:59:52 -07:00
/**
* HookPackets()
* bitcoind.hookPackets(callback)
*/
2014-09-26 12:20:00 -07:00
2014-10-27 10:59:52 -07:00
NAN_METHOD(HookPackets) {
Isolate* isolate = Isolate::GetCurrent();
2015-06-09 03:57:58 -07:00
HandleScope scope(isolate);
2014-10-27 10:59:52 -07:00
Local<Array> obj = NanNew<Array>();
poll_packets_list *cur = NULL;
poll_packets_list *next = NULL;
int i = 0;
2014-09-26 12:20:00 -07:00
2014-10-27 10:59:52 -07:00
poll_packets_mutex.lock();
2014-09-26 12:20:00 -07:00
2014-10-27 10:59:52 -07:00
for (cur = packets_queue_head; cur; cur = next) {
CNode *pfrom = cur->pfrom;
std::string strCommand(cur->strCommand);
CDataStream vRecv = *cur->vRecv;
int64_t nTimeReceived = cur->nTimeReceived;
2014-09-26 12:20:00 -07:00
2014-10-27 10:59:52 -07:00
Local<Object> o = NanNew<Object>();
2014-09-26 12:20:00 -07:00
2014-11-11 11:11:12 -08:00
o->Set(NanNew<String>("name"), NanNew<String>(strCommand));
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("received"), NanNew<Number>((int64_t)nTimeReceived));
o->Set(NanNew<String>("peerId"), NanNew<Number>(pfrom->id));
o->Set(NanNew<String>("userAgent"),
2014-11-11 11:11:12 -08:00
NanNew<String>(pfrom->cleanSubVer));
2014-09-26 12:20:00 -07:00
2014-10-27 10:59:52 -07:00
if (strCommand == "version") {
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
bool fRelayTxes = false;
int nStartingHeight = 0;
int cleanSubVer = 0;
std::string strSubVer = pfrom->strSubVer;
int nVersion = pfrom->nVersion;
uint64_t nServices = pfrom->nServices;
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
int64_t nTime;
CAddress addrMe;
CAddress addrFrom;
uint64_t nNonce = 1;
vRecv >> nVersion >> nServices >> nTime >> addrMe;
if (pfrom->nVersion < MIN_PEER_PROTO_VERSION) {
// disconnect from peers older than this proto version
NanReturnValue(Undefined(isolate));
2014-10-27 10:59:52 -07:00
}
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
if (nVersion == 10300) {
nVersion = 300;
}
if (!vRecv.empty()) {
vRecv >> addrFrom >> nNonce;
}
if (!vRecv.empty()) {
vRecv >> LIMITED_STRING(strSubVer, 256);
//cleanSubVer = SanitizeString(strSubVer);
cleanSubVer = atoi(strSubVer.c_str());
}
if (!vRecv.empty()) {
vRecv >> nStartingHeight;
}
if (!vRecv.empty()) {
fRelayTxes = false;
} else {
fRelayTxes = true;
2014-10-01 14:24:07 -07:00
}
2014-10-27 10:59:52 -07:00
// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1) {
NanReturnValue(obj);
}
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("receiveVersion"), NanNew<Number>(cleanSubVer));
o->Set(NanNew<String>("version"), NanNew<Number>(nVersion));
o->Set(NanNew<String>("height"), NanNew<Number>(nStartingHeight));
o->Set(NanNew<String>("us"), NanNew<String>(addrMe.ToString()));
o->Set(NanNew<String>("address"), NanNew<String>(pfrom->addr.ToString()));
o->Set(NanNew<String>("relay"), NanNew<Boolean>(fRelayTxes));
} else if (pfrom->nVersion == 0) {
// Must have a version message before anything else
NanReturnValue(Undefined(isolate));
2014-10-27 10:59:52 -07:00
} else if (strCommand == "verack") {
o->Set(NanNew<String>("receiveVersion"), NanNew<Number>(min(pfrom->nVersion, PROTOCOL_VERSION)));
} else if (strCommand == "addr") {
vector<CAddress> vAddr;
vRecv >> vAddr;
2014-10-01 15:14:20 -07:00
2014-10-27 10:59:52 -07:00
// Don't want addr from older versions unless seeding
if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000) {
NanReturnValue(obj);
}
2014-10-06 11:05:52 -07:00
2014-10-27 10:59:52 -07:00
// Bad address size
if (vAddr.size() > 1000) {
NanReturnValue(Undefined(isolate));
2014-10-27 10:59:52 -07:00
}
2014-10-01 15:14:20 -07:00
2014-10-27 10:59:52 -07:00
Local<Array> array = NanNew<Array>();
int i = 0;
2014-10-01 15:14:20 -07:00
2014-10-27 10:59:52 -07:00
// Get the new addresses
int64_t nNow = GetAdjustedTime();
BOOST_FOREACH(CAddress& addr, vAddr) {
boost::this_thread::interruption_point();
2014-10-01 15:14:20 -07:00
2014-10-27 10:59:52 -07:00
unsigned int nTime = addr.nTime;
if (nTime <= 100000000 || nTime > nNow + 10 * 60) {
nTime = nNow - 5 * 24 * 60 * 60;
}
2014-10-01 15:14:20 -07:00
2014-10-27 10:59:52 -07:00
bool fReachable = IsReachable(addr);
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
Local<Object> obj = NanNew<Object>();
2014-10-06 11:05:52 -07:00
2014-10-27 10:59:52 -07:00
char nServices[21] = {0};
2015-06-04 11:54:57 -07:00
int written = snprintf(nServices, sizeof(nServices), "%020llu", (uint64_t)addr.nServices);
2014-10-27 10:59:52 -07:00
assert(written == 20);
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
obj->Set(NanNew<String>("services"), NanNew<String>((char *)nServices));
obj->Set(NanNew<String>("time"), NanNew<Number>((unsigned int)nTime)->ToUint32());
obj->Set(NanNew<String>("last"), NanNew<Number>((int64_t)addr.nLastTry));
obj->Set(NanNew<String>("ip"), NanNew<String>((std::string)addr.ToStringIP()));
obj->Set(NanNew<String>("port"), NanNew<Number>((unsigned short)addr.GetPort())->ToUint32());
obj->Set(NanNew<String>("address"), NanNew<String>((std::string)addr.ToStringIPPort()));
obj->Set(NanNew<String>("reachable"), NanNew<Boolean>((bool)fReachable));
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
array->Set(i, obj);
i++;
}
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("addresses"), array);
} else if (strCommand == "inv") {
vector<CInv> vInv;
vRecv >> vInv;
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
// Bad size
if (vInv.size() > MAX_INV_SZ) {
NanReturnValue(Undefined(isolate));
2014-10-27 10:59:52 -07:00
}
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
LOCK(cs_main);
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
Local<Array> array = NanNew<Array>();
int i = 0;
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
const CInv &inv = vInv[nInv];
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
boost::this_thread::interruption_point();
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
// Bad size
if (pfrom->nSendSize > (SendBufferSize() * 2)) {
NanReturnValue(Undefined(isolate));
2014-10-27 10:59:52 -07:00
}
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
Local<Object> item = NanNew<Object>();
2014-11-11 11:11:12 -08:00
item->Set(NanNew<String>("hash"), NanNew<String>(inv.hash.GetHex()));
2014-10-27 10:59:52 -07:00
item->Set(NanNew<String>("type"), NanNew<String>(
inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK
? "block" : "tx"));
if (inv.type == MSG_FILTERED_BLOCK) {
item->Set(NanNew<String>("filtered"), NanNew<Boolean>(true));
} else if (inv.type == MSG_BLOCK) {
item->Set(NanNew<String>("filtered"), NanNew<Boolean>(false));
}
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
array->Set(i, item);
i++;
}
2014-10-06 11:05:52 -07:00
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("items"), array);
} else if (strCommand == "getdata") {
vector<CInv> vInv;
vRecv >> vInv;
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
// Bad size
if (vInv.size() > MAX_INV_SZ) {
NanReturnValue(Undefined(isolate));
2014-10-27 10:59:52 -07:00
}
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("size"), NanNew<Number>(vInv.size()));
if (vInv.size() > 0) {
2014-11-11 11:11:12 -08:00
o->Set(NanNew<String>("first"), NanNew<String>(vInv[0].ToString()));
2014-10-27 10:59:52 -07:00
}
} else if (strCommand == "getblocks") {
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
LOCK(cs_main);
2014-09-29 11:59:57 -07:00
2014-10-27 10:59:52 -07:00
// Find the last block the caller has in the main chain
CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator);
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
// Send the rest of the chain
if (pindex) {
pindex = chainActive.Next(pindex);
}
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("fromHeight"), NanNew<Number>(pindex ? pindex->nHeight : -1));
o->Set(NanNew<String>("toHash"), NanNew<String>(
2014-11-11 11:11:12 -08:00
hashStop == uint256(0) ? "end" : hashStop.GetHex()));
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("limit"), NanNew<Number>(500));
} else if (strCommand == "getheaders") {
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
2014-09-29 11:59:57 -07:00
2014-10-27 10:59:52 -07:00
LOCK(cs_main);
2014-09-29 11:59:57 -07:00
2014-10-27 10:59:52 -07:00
CBlockIndex* pindex = NULL;
if (locator.IsNull()) {
// If locator is null, return the hashStop block
BlockMap::iterator mi = mapBlockIndex.find(hashStop);
if (mi == mapBlockIndex.end()) {
NanReturnValue(obj);
}
pindex = (*mi).second;
} else {
// Find the last block the caller has in the main chain
pindex = FindForkInGlobalIndex(chainActive, locator);
if (pindex) {
pindex = chainActive.Next(pindex);
}
}
2014-09-29 11:59:57 -07:00
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("fromHeight"), NanNew<Number>(pindex ? pindex->nHeight : -1));
2014-11-11 11:11:12 -08:00
o->Set(NanNew<String>("toHash"), NanNew<String>(hashStop.GetHex()));
2014-10-27 10:59:52 -07:00
} else if (strCommand == "tx") {
// XXX May be able to do prev_list asynchronously
2014-10-27 10:59:52 -07:00
// XXX Potentially check for "reject" in original code
CTransaction tx;
vRecv >> tx;
Local<Object> jstx = NanNew<Object>();
ctx_to_jstx(tx, 0, jstx);
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("tx"), jstx);
2014-12-18 14:24:06 -08:00
CNodeStats stats;
pfrom->copyStats(stats);
jstx->Set(NanNew<String>("from"), NanNew<String>(stats.addrName));
if (!stats.addrLocal.empty()) {
jstx->Set(NanNew<String>("fromlocal"), NanNew<String>(stats.addrLocal));
}
2014-10-27 10:59:52 -07:00
} else if (strCommand == "block" && !fImporting && !fReindex) {
// XXX May be able to do prev_list asynchronously
2014-10-27 10:59:52 -07:00
CBlock block;
vRecv >> block;
Local<Object> jsblock = NanNew<Object>();
cblock_to_jsblock(block, NULL, jsblock, true);
o->Set(NanNew<String>("block"), jsblock);
2014-12-18 14:24:06 -08:00
CNodeStats stats;
pfrom->copyStats(stats);
jsblock->Set(NanNew<String>("from"), NanNew<String>(stats.addrName));
if (!stats.addrLocal.empty()) {
jsblock->Set(NanNew<String>("fromlocal"), NanNew<String>(stats.addrLocal));
}
2014-10-27 10:59:52 -07:00
} else if (strCommand == "getaddr") {
; // not much other information in getaddr as long as we know we got a getaddr
} else if (strCommand == "mempool") {
; // not much other information in getaddr as long as we know we got a getaddr
} else if (strCommand == "ping") {
if (pfrom->nVersion > BIP0031_VERSION) {
uint64_t nonce = 0;
vRecv >> nonce;
char sNonce[21] = {0};
2015-06-04 11:54:57 -07:00
int written = snprintf(sNonce, sizeof(sNonce), "%020llu", (uint64_t)nonce);
2014-10-27 10:59:52 -07:00
assert(written == 20);
o->Set(NanNew<String>("nonce"), NanNew<String>(sNonce));
} else {
char sNonce[21] = {0};
2015-06-04 11:54:57 -07:00
int written = snprintf(sNonce, sizeof(sNonce), "%020llu", (uint64_t)0);
2014-10-27 10:59:52 -07:00
assert(written == 20);
o->Set(NanNew<String>("nonce"), NanNew<String>(sNonce));
}
} else if (strCommand == "pong") {
int64_t pingUsecEnd = nTimeReceived;
uint64_t nonce = 0;
size_t nAvail = vRecv.in_avail();
bool bPingFinished = false;
std::string sProblem;
2014-09-29 11:59:57 -07:00
2014-10-27 10:59:52 -07:00
if (nAvail >= sizeof(nonce)) {
vRecv >> nonce;
2014-09-29 11:59:57 -07:00
2014-10-27 10:59:52 -07:00
// Only process pong message if there is an outstanding ping (old ping without nonce should never pong)
if (pfrom->nPingNonceSent != 0) {
if (nonce == pfrom->nPingNonceSent) {
// Matching pong received, this ping is no longer outstanding
bPingFinished = true;
int64_t pingUsecTime = pingUsecEnd - pfrom->nPingUsecStart;
if (pingUsecTime > 0) {
// Successful ping time measurement, replace previous
;
} else {
// This should never happen
sProblem = "Timing mishap";
}
} else {
// Nonce mismatches are normal when pings are overlapping
sProblem = "Nonce mismatch";
if (nonce == 0) {
// This is most likely a bug in another implementation somewhere, cancel this ping
bPingFinished = true;
sProblem = "Nonce zero";
}
}
} else {
sProblem = "Unsolicited pong without ping";
}
} else {
// This is most likely a bug in another implementation somewhere, cancel this ping
bPingFinished = true;
sProblem = "Short payload";
}
2014-09-29 11:59:57 -07:00
2014-10-27 10:59:52 -07:00
char sNonce[21] = {0};
2015-06-04 11:54:57 -07:00
int written = snprintf(sNonce, sizeof(sNonce), "%020llu", (uint64_t)nonce);
2014-10-27 10:59:52 -07:00
assert(written == 20);
2014-09-29 11:59:57 -07:00
2014-10-27 10:59:52 -07:00
char sPingNonceSent[21] = {0};
2015-06-04 11:54:57 -07:00
written = snprintf(sPingNonceSent, sizeof(sPingNonceSent), "%020llu", (uint64_t)pfrom->nPingNonceSent);
2014-10-27 10:59:52 -07:00
assert(written == 20);
2014-09-29 11:59:57 -07:00
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("expected"), NanNew<String>(sPingNonceSent));
o->Set(NanNew<String>("received"), NanNew<String>(sNonce));
o->Set(NanNew<String>("bytes"), NanNew<Number>((unsigned int)nAvail));
2014-09-29 11:59:57 -07:00
2014-10-27 10:59:52 -07:00
if (!(sProblem.empty())) {
o->Set(NanNew<String>("problem"), NanNew<String>(sProblem));
}
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
if (bPingFinished) {
o->Set(NanNew<String>("finished"), NanNew<Boolean>(true));
} else {
o->Set(NanNew<String>("finished"), NanNew<Boolean>(false));
}
} else if (strCommand == "alert") {
CAlert alert;
vRecv >> alert;
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
uint256 alertHash = alert.GetHash();
2014-09-26 12:42:04 -07:00
2014-11-11 11:11:12 -08:00
o->Set(NanNew<String>("hash"), NanNew<String>(alertHash.GetHex()));
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
if (pfrom->setKnown.count(alertHash) == 0) {
if (alert.ProcessAlert()) {
std::string vchMsg(alert.vchMsg.begin(), alert.vchMsg.end());
std::string vchSig(alert.vchSig.begin(), alert.vchSig.end());
2014-11-11 11:11:12 -08:00
o->Set(NanNew<String>("message"), NanNew<String>(vchMsg));
o->Set(NanNew<String>("signature"), NanNew<String>(vchSig));
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("misbehaving"), NanNew<Boolean>(false));
} else {
// Small DoS penalty so peers that send us lots of
// duplicate/expired/invalid-signature/whatever alerts
// eventually get banned.
// This isn't a Misbehaving(100) (immediate ban) because the
// peer might be an older or different implementation with
// a different signature key, etc.
o->Set(NanNew<String>("misbehaving"), NanNew<Boolean>(true));
}
}
} else if (strCommand == "filterload") {
CBloomFilter filter;
vRecv >> filter;
2014-10-06 11:05:52 -07:00
2014-10-27 10:59:52 -07:00
if (!filter.IsWithinSizeConstraints()) {
// There is no excuse for sending a too-large filter
o->Set(NanNew<String>("misbehaving"), NanNew<Boolean>(true));
} else {
LOCK(pfrom->cs_filter);
filter.UpdateEmptyFull();
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
o->Set(NanNew<String>("misbehaving"), NanNew<Boolean>(false));
}
} else if (strCommand == "filteradd") {
vector<unsigned char> vData;
vRecv >> vData;
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
// Nodes must NEVER send a data item > 520 bytes (the max size for a script data object,
// and thus, the maximum size any matched object can have) in a filteradd message
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) {
o->Set(NanNew<String>("misbehaving"), NanNew<Boolean>(true));
} else {
LOCK(pfrom->cs_filter);
if (pfrom->pfilter) {
o->Set(NanNew<String>("misbehaving"), NanNew<Boolean>(false));
} else {
o->Set(NanNew<String>("misbehaving"), NanNew<Boolean>(true));
}
}
} else if (strCommand == "filterclear") {
; // nothing much to grab from this packet
} else if (strCommand == "reject") {
; // nothing much to grab from this packet
} else {
o->Set(NanNew<String>("unknown"), NanNew<Boolean>(true));
}
2014-10-01 12:52:06 -07:00
2014-10-27 10:59:52 -07:00
// Update the last seen time for this node's address
if (pfrom->fNetworkNode) {
if (strCommand == "version"
|| strCommand == "addr"
|| strCommand == "inv"
|| strCommand == "getdata"
|| strCommand == "ping") {
o->Set(NanNew<String>("connected"), NanNew<Boolean>(true));
}
}
2014-10-01 12:52:06 -07:00
2014-10-27 10:59:52 -07:00
obj->Set(i, o);
i++;
2014-10-01 12:52:06 -07:00
2014-10-27 10:59:52 -07:00
if (cur == packets_queue_head) {
packets_queue_head = NULL;
}
2014-10-01 12:52:06 -07:00
2014-10-27 10:59:52 -07:00
if (cur == packets_queue_tail) {
packets_queue_tail = NULL;
}
2014-10-01 12:52:06 -07:00
2014-10-27 10:59:52 -07:00
next = cur->next;
free(cur->strCommand);
delete cur->vRecv;
free(cur);
2014-10-01 12:52:06 -07:00
}
2014-10-27 10:59:52 -07:00
poll_packets_mutex.unlock();
2014-10-01 12:52:06 -07:00
2014-10-27 10:59:52 -07:00
NanReturnValue(obj);
2014-09-26 12:42:04 -07:00
}
2014-10-27 10:59:52 -07:00
static void
hook_packets(void) {
CNodeSignals& nodeSignals = GetNodeSignals();
2014-10-27 10:59:52 -07:00
nodeSignals.ProcessMessages.connect(&process_packets);
}
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
static void
unhook_packets(void) {
CNodeSignals& nodeSignals = GetNodeSignals();
2014-10-27 10:59:52 -07:00
nodeSignals.ProcessMessages.disconnect(&process_packets);
}
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
static bool
process_packets(CNode* pfrom) {
bool fOk = true;
2014-09-26 12:42:04 -07:00
2014-10-27 10:59:52 -07:00
std::deque<CNetMessage>::iterator it = pfrom->vRecvMsg.begin();
while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) {
// Don't bother if send buffer is too full to respond anyway
if (pfrom->nSendSize >= SendBufferSize()) {
break;
}
2014-10-01 14:24:07 -07:00
2014-10-27 10:59:52 -07:00
// get next message
CNetMessage& msg = *it;
2014-10-01 12:58:11 -07:00
2014-10-27 10:59:52 -07:00
// end, if an incomplete message is found
if (!msg.complete()) {
break;
}
2014-10-01 12:58:11 -07:00
2014-10-27 10:59:52 -07:00
// at this point, any failure means we can delete the current message
it++;
2014-10-01 12:58:11 -07:00
2014-10-27 10:59:52 -07:00
// Scan for message start
if (memcmp(msg.hdr.pchMessageStart,
Params().MessageStart(), MESSAGE_START_SIZE) != 0) {
fOk = false;
break;
}
2014-10-01 12:58:11 -07:00
2014-10-27 10:59:52 -07:00
// Read header
CMessageHeader& hdr = msg.hdr;
if (!hdr.IsValid()) {
continue;
}
string strCommand = hdr.GetCommand();
2014-10-01 12:58:11 -07:00
2014-10-27 10:59:52 -07:00
// Message size
unsigned int nMessageSize = hdr.nMessageSize;
2014-10-01 12:58:11 -07:00
2014-10-27 10:59:52 -07:00
// Checksum
CDataStream& vRecv = msg.vRecv;
uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
unsigned int nChecksum = 0;
memcpy(&nChecksum, &hash, sizeof(nChecksum));
if (nChecksum != hdr.nChecksum) {
continue;
}
// Process message
process_packet(pfrom, strCommand, vRecv, msg.nTime);
2014-10-27 10:59:52 -07:00
boost::this_thread::interruption_point();
break;
2014-10-01 12:58:11 -07:00
}
2014-10-27 10:59:52 -07:00
return fOk;
}
static bool
process_packet(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) {
poll_packets_mutex.lock();
poll_packets_list *cur = (poll_packets_list *)malloc(sizeof(poll_packets_list));
if (!packets_queue_head) {
packets_queue_head = cur;
packets_queue_tail = cur;
} else {
packets_queue_tail->next = cur;
packets_queue_tail = cur;
}
cur->pfrom = pfrom;
// NOTE: Copy the data stream.
CDataStream *vRecv_ = new CDataStream(vRecv.begin(), vRecv.end(), vRecv.GetType(), vRecv.GetVersion());
cur->vRecv = vRecv_;
cur->nTimeReceived = nTimeReceived;
cur->strCommand = strdup(strCommand.c_str());
cur->next = NULL;
poll_packets_mutex.unlock();
return true;
2014-09-26 12:42:04 -07:00
}
2014-10-06 11:05:52 -07:00
/**
* Conversions
* cblock_to_jsblock(cblock, cblock_index, jsblock, is_new)
* ctx_to_jstx(ctx, blockhash, jstx)
* jsblock_to_cblock(jsblock, cblock)
* jstx_to_ctx(jstx, ctx)
* These functions, only callable from C++, are used to convert javascript
* blocks and tx objects to bitcoin block and tx objects (CBlocks and
* CTransactions), and vice versa.
2014-10-06 11:05:52 -07:00
*/
// XXX Potentially add entire function's code. If there's a race
// condition, the duplicate check will handle it.
CBlockIndex *
find_new_block_index(uint256 hash, uint256 hashPrevBlock, bool *is_allocated) {
// Check for duplicate
BlockMap::iterator it = mapBlockIndex.find(hash);
if (it != mapBlockIndex.end()) {
return it->second;
}
2014-10-27 10:59:52 -07:00
// Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex();
assert(pindexNew);
BlockMap::iterator miPrev = mapBlockIndex.find(hashPrevBlock);
if (miPrev != mapBlockIndex.end()) {
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
2014-10-27 10:59:52 -07:00
}
*is_allocated = true;
2014-10-27 10:59:52 -07:00
return pindexNew;
2014-10-27 10:59:52 -07:00
}
static inline void
cblock_to_jsblock(const CBlock& cblock, CBlockIndex* cblock_index, Local<Object> jsblock, bool is_new) {
bool is_allocated = false;
if (!cblock_index && is_new) {
cblock_index = find_new_block_index(cblock.GetHash(), cblock.hashPrevBlock, &is_allocated);
}
uint256 blockhash = cblock.GetHash();
2014-10-27 10:59:52 -07:00
jsblock->Set(NanNew<String>("hash"), NanNew<String>(blockhash.GetHex()));
jsblock->Set(NanNew<String>("size"),
NanNew<Number>((int)::GetSerializeSize(cblock, SER_NETWORK, PROTOCOL_VERSION))->ToInt32());
2014-10-01 13:11:07 -07:00
if (cblock_index) {
jsblock->Set(NanNew<String>("height"), NanNew<Number>(cblock_index->nHeight));
2014-10-01 13:11:07 -07:00
}
//
// Headers
//
jsblock->Set(NanNew<String>("version"), NanNew<Number>((int32_t)cblock.nVersion));
jsblock->Set(NanNew<String>("previousblockhash"), NanNew<String>((std::string)cblock.hashPrevBlock.ToString()));
jsblock->Set(NanNew<String>("merkleroot"), NanNew<String>((std::string)cblock.hashMerkleRoot.GetHex()));
jsblock->Set(NanNew<String>("time"), NanNew<Number>((uint32_t)cblock.GetBlockTime())->ToUint32());
jsblock->Set(NanNew<String>("bits"), NanNew<Number>((uint32_t)cblock.nBits)->ToUint32());
jsblock->Set(NanNew<String>("nonce"), NanNew<Number>((uint32_t)cblock.nNonce)->ToUint32());
if (cblock_index) {
jsblock->Set(NanNew<String>("difficulty"), NanNew<Number>(GetDifficulty(cblock_index)));
jsblock->Set(NanNew<String>("chainwork"), NanNew<String>(cblock_index->nChainWork.GetHex()));
}
if (cblock_index) {
CBlockIndex *pnext = chainActive.Next(cblock_index);
if (pnext) {
jsblock->Set(NanNew<String>("nextblockhash"), NanNew<String>(pnext->GetBlockHash().GetHex()));
}
}
// Build merkle tree
if (cblock.vMerkleTree.empty()) {
cblock.BuildMerkleTree();
}
Local<Array> merkle = NanNew<Array>();
int mi = 0;
BOOST_FOREACH(uint256& hash, cblock.vMerkleTree) {
merkle->Set(mi, NanNew<String>(hash.ToString()));
mi++;
}
jsblock->Set(NanNew<String>("merkletree"), merkle);
Local<Array> txs = NanNew<Array>();
int ti = 0;
BOOST_FOREACH(const CTransaction& ctx, cblock.vtx) {
Local<Object> jstx = NanNew<Object>();
ctx_to_jstx(ctx, blockhash, jstx);
txs->Set(ti, jstx);
ti++;
2014-09-26 12:42:04 -07:00
}
jsblock->Set(NanNew<String>("tx"), txs);
2014-09-26 12:42:04 -07:00
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
ssBlock << cblock;
std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
jsblock->Set(NanNew<String>("hex"), NanNew<String>(strHex));
2014-09-26 12:42:04 -07:00
// Was it allocated in find_new_block_index(), or did it already exist?
// (race condition here)
if (is_allocated) {
delete cblock_index;
2014-10-01 13:37:18 -07:00
}
}
2014-10-01 13:37:18 -07:00
static int
get_tx(uint256 txid, uint256& blockhash, CTransaction& ctx) {
if (GetTransaction(txid, ctx, blockhash, true)) {
return 1;
} else if (blockhash != 0) {
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[blockhash];
if (ReadBlockFromDisk(block, pblockindex)) {
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
if (tx.GetHash() == txid) {
ctx = tx;
blockhash = block.GetHash();
return -1;
}
}
2014-12-04 15:38:35 -08:00
}
}
return 0;
}
2014-10-27 10:59:52 -07:00
static inline void
2014-12-08 11:31:00 -08:00
ctx_to_jstx(const CTransaction& ctx, uint256 blockhash, Local<Object> jstx) {
// Find block hash if it's in our wallet
2014-12-04 16:06:51 -08:00
jstx->Set(NanNew<String>("current_version"),
NanNew<Number>((int)ctx.CURRENT_VERSION)->ToInt32());
2014-10-27 10:59:52 -07:00
jstx->Set(NanNew<String>("txid"), NanNew<String>(ctx.GetHash().GetHex()));
2014-12-04 16:06:51 -08:00
jstx->Set(NanNew<String>("version"),
NanNew<Number>((int)ctx.nVersion)->ToInt32());
jstx->Set(NanNew<String>("locktime"),
NanNew<Number>((unsigned int)ctx.nLockTime)->ToUint32());
2014-10-27 10:59:52 -07:00
2014-11-13 17:18:56 -08:00
jstx->Set(NanNew<String>("size"),
NanNew<Number>((int)::GetSerializeSize(ctx, SER_NETWORK, PROTOCOL_VERSION))->ToInt32());
2014-10-27 10:59:52 -07:00
Local<Array> vin = NanNew<Array>();
int vi = 0;
BOOST_FOREACH(const CTxIn& txin, ctx.vin) {
Local<Object> in = NanNew<Object>();
if (ctx.IsCoinBase()) {
2014-12-04 16:06:51 -08:00
in->Set(NanNew<String>("coinbase"),
NanNew<String>(HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
2014-10-22 12:39:09 -07:00
}
2014-11-06 01:22:46 -08:00
2014-10-27 10:59:52 -07:00
in->Set(NanNew<String>("txid"), NanNew<String>(txin.prevout.hash.GetHex()));
2014-12-04 16:06:51 -08:00
in->Set(NanNew<String>("vout"),
NanNew<Number>((unsigned int)txin.prevout.n)->ToUint32());
2014-10-27 10:59:52 -07:00
Local<Object> o = NanNew<Object>();
2014-12-04 16:06:51 -08:00
o->Set(NanNew<String>("asm"),
NanNew<String>(txin.scriptSig.ToString()));
o->Set(NanNew<String>("hex"),
NanNew<String>(HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
2014-11-06 02:55:22 -08:00
2014-11-06 03:44:30 -08:00
Local<Object> jsprev = NanNew<Object>();
2014-11-06 02:55:22 -08:00
CTransaction prev_tx;
2014-12-09 14:19:44 -08:00
if (get_tx(txin.prevout.hash, blockhash, prev_tx)) {
2014-11-06 02:55:22 -08:00
CTxDestination from;
2014-11-06 03:44:30 -08:00
CTxOut prev_out = prev_tx.vout[txin.prevout.n];
ExtractDestination(prev_out.scriptPubKey, from);
2014-11-06 02:55:22 -08:00
CBitcoinAddress addrFrom(from);
2014-12-04 16:06:51 -08:00
jsprev->Set(NanNew<String>("address"),
NanNew<String>(addrFrom.ToString()));
jsprev->Set(NanNew<String>("value"),
NanNew<Number>((int64_t)prev_out.nValue)->ToInteger());
2014-11-06 03:44:30 -08:00
} else {
2014-12-04 15:38:35 -08:00
const CTxOut& txout = ctx.vout[0];
const CScript& scriptPubKey = txout.scriptPubKey;
txnouttype type;
vector<CTxDestination> addresses;
int nRequired;
if (ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
// Unknowns usually have the same first addr as the first output:
// https://blockexplorer.com/testnet/block/
const CTxDestination& addr = addresses[0];
2014-12-04 16:06:51 -08:00
jsprev->Set(NanNew<String>("address"),
NanNew<String>(CBitcoinAddress(addr).ToString() + std::string("?")));
jsprev->Set(NanNew<String>("value"),
NanNew<Number>((int64_t)txout.nValue)->ToInteger());
2014-12-04 15:38:35 -08:00
} else {
2014-12-04 16:06:51 -08:00
jsprev->Set(NanNew<String>("address"),
NanNew<String>(std::string("Unknown")));
2014-12-04 15:38:35 -08:00
jsprev->Set(NanNew<String>("value"), NanNew<Number>(0));
}
2014-11-06 02:55:22 -08:00
}
2014-11-06 03:44:30 -08:00
in->Set(NanNew<String>("prev"), jsprev);
2014-11-06 02:55:22 -08:00
2014-10-27 10:59:52 -07:00
in->Set(NanNew<String>("scriptSig"), o);
in->Set(NanNew<String>("sequence"), NanNew<Number>((unsigned int)txin.nSequence)->ToUint32());
vin->Set(vi, in);
vi++;
}
jstx->Set(NanNew<String>("vin"), vin);
Local<Array> vout = NanNew<Array>();
for (unsigned int vo = 0; vo < ctx.vout.size(); vo++) {
const CTxOut& txout = ctx.vout[vo];
Local<Object> out = NanNew<Object>();
out->Set(NanNew<String>("value"), NanNew<Number>((int64_t)txout.nValue)->ToInteger());
out->Set(NanNew<String>("n"), NanNew<Number>((unsigned int)vo)->ToUint32());
Local<Object> o = NanNew<Object>();
{
const CScript& scriptPubKey = txout.scriptPubKey;
Local<Object> out = o;
2014-10-22 12:39:09 -07:00
2014-10-27 10:59:52 -07:00
txnouttype type;
vector<CTxDestination> addresses;
int nRequired;
out->Set(NanNew<String>("asm"), NanNew<String>(scriptPubKey.ToString()));
2014-12-04 16:06:51 -08:00
out->Set(NanNew<String>("hex"),
NanNew<String>(HexStr(scriptPubKey.begin(), scriptPubKey.end())));
2014-10-27 10:59:52 -07:00
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
2014-12-04 16:06:51 -08:00
out->Set(NanNew<String>("type"),
NanNew<String>(GetTxnOutputType(type)));
2014-10-27 10:59:52 -07:00
} else {
2014-12-04 16:06:51 -08:00
out->Set(NanNew<String>("reqSigs"),
NanNew<Number>((int)nRequired)->ToInt32());
out->Set(NanNew<String>("type"),
NanNew<String>(GetTxnOutputType(type)));
2014-10-27 10:59:52 -07:00
Local<Array> a = NanNew<Array>();
int ai = 0;
BOOST_FOREACH(const CTxDestination& addr, addresses) {
a->Set(ai, NanNew<String>(CBitcoinAddress(addr).ToString()));
ai++;
}
out->Set(NanNew<String>("addresses"), a);
2014-10-22 12:39:09 -07:00
}
}
2014-10-27 10:59:52 -07:00
out->Set(NanNew<String>("scriptPubKey"), o);
2014-10-22 12:39:09 -07:00
2014-10-27 10:59:52 -07:00
vout->Set(vo, out);
}
jstx->Set(NanNew<String>("vout"), vout);
2014-10-21 18:51:05 -07:00
2014-12-08 11:31:00 -08:00
if (blockhash != 0) {
jstx->Set(NanNew<String>("blockhash"), NanNew<String>(blockhash.GetHex()));
2014-11-18 15:38:44 -08:00
if (ctx.IsCoinBase()) {
jstx->Set(NanNew<String>("generated"), NanNew<Boolean>(true));
}
2014-12-08 11:31:00 -08:00
if (mapBlockIndex.count(blockhash) > 0) {
CBlockIndex* pindex = mapBlockIndex[blockhash];
2014-11-18 15:51:43 -08:00
jstx->Set(NanNew<String>("confirmations"),
NanNew<Number>(pindex->nHeight));
// XXX Not really index:
2014-11-18 15:51:43 -08:00
jstx->Set(NanNew<String>("blockindex"),
NanNew<Number>(pindex->nHeight));
jstx->Set(NanNew<String>("blockheight"),
NanNew<Number>(pindex->nHeight));
2014-11-18 15:51:43 -08:00
jstx->Set(NanNew<String>("blocktime"),
NanNew<Number>((int64_t)pindex->GetBlockTime())->ToInteger());
2014-11-18 15:51:43 -08:00
jstx->Set(NanNew<String>("time"),
NanNew<Number>((int64_t)pindex->GetBlockTime())->ToInteger());
2014-11-18 15:51:43 -08:00
jstx->Set(NanNew<String>("timereceived"),
NanNew<Number>((int64_t)pindex->GetBlockTime())->ToInteger());
2014-11-18 15:51:43 -08:00
} else {
jstx->Set(NanNew<String>("confirmations"), NanNew<Number>(0));
// XXX Not really index:
2014-11-18 15:51:43 -08:00
jstx->Set(NanNew<String>("blockindex"), NanNew<Number>(-1));
jstx->Set(NanNew<String>("blockheight"), NanNew<Number>(-1));
2014-11-18 15:51:43 -08:00
jstx->Set(NanNew<String>("blocktime"), NanNew<Number>(0));
jstx->Set(NanNew<String>("time"), NanNew<Number>(0));
jstx->Set(NanNew<String>("timereceived"), NanNew<Number>(0));
}
2015-07-02 11:59:14 -07:00
jstx->Set(NanNew<String>("walletconflicts"), NanNew<Array>());
2014-11-05 17:27:51 -08:00
} else {
jstx->Set(NanNew<String>("blockhash"), NanNew<String>(uint256(0).GetHex()));
jstx->Set(NanNew<String>("generated"), NanNew<Boolean>(false));
2014-12-09 14:38:58 -08:00
jstx->Set(NanNew<String>("confirmations"), NanNew<Number>(-1));
// XXX Not really index:
2014-11-05 17:27:51 -08:00
jstx->Set(NanNew<String>("blockindex"), NanNew<Number>(-1));
jstx->Set(NanNew<String>("blockheight"), NanNew<Number>(-1));
2014-11-05 17:27:51 -08:00
jstx->Set(NanNew<String>("blocktime"), NanNew<Number>(0));
jstx->Set(NanNew<String>("walletconflicts"), NanNew<Array>());
jstx->Set(NanNew<String>("time"), NanNew<Number>(0));
jstx->Set(NanNew<String>("timereceived"), NanNew<Number>(0));
2014-10-27 10:59:52 -07:00
}
2014-10-21 18:51:05 -07:00
2014-10-27 10:59:52 -07:00
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << ctx;
std::string strHex = HexStr(ssTx.begin(), ssTx.end());
jstx->Set(NanNew<String>("hex"), NanNew<String>(strHex));
}
static inline void
jsblock_to_cblock(const Local<Object> jsblock, CBlock& cblock) {
cblock.nVersion = (int32_t)jsblock->Get(NanNew<String>("version"))->Int32Value();
if (jsblock->Get(NanNew<String>("previousblockhash"))->IsString()) {
String::Utf8Value hash__(jsblock->Get(NanNew<String>("previousblockhash"))->ToString());
2014-10-27 10:59:52 -07:00
std::string hash_ = *hash__;
uint256 hash(hash_);
cblock.hashPrevBlock = (uint256)hash;
} else {
// genesis block
cblock.hashPrevBlock = (uint256)uint256(0);
2014-10-21 18:06:17 -07:00
}
String::Utf8Value mhash__(jsblock->Get(NanNew<String>("merkleroot"))->ToString());
2014-10-27 10:59:52 -07:00
std::string mhash_ = *mhash__;
uint256 mhash(mhash_);
cblock.hashMerkleRoot = (uint256)mhash;
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
cblock.nTime = (uint32_t)jsblock->Get(NanNew<String>("time"))->Uint32Value();
cblock.nBits = (uint32_t)jsblock->Get(NanNew<String>("bits"))->Uint32Value();
cblock.nNonce = (uint32_t)jsblock->Get(NanNew<String>("nonce"))->Uint32Value();
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
Local<Array> txs = Local<Array>::Cast(jsblock->Get(NanNew<String>("tx")));
for (unsigned int ti = 0; ti < txs->Length(); ti++) {
Local<Object> jstx = Local<Object>::Cast(txs->Get(ti));
CTransaction ctx;
jstx_to_ctx(jstx, ctx);
cblock.vtx.push_back(ctx);
}
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
if (cblock.vMerkleTree.empty()) {
cblock.BuildMerkleTree();
}
2014-10-21 18:06:17 -07:00
}
2014-10-27 10:59:52 -07:00
// NOTE: For whatever reason when converting a jstx to a CTransaction via
// setting CTransaction properties, the binary output of a jstx is not the same
// as what went in. It is unknow why this occurs. For now we are are using a
// workaround by carrying the original hex value on the object which is changed
// when the tx is changed.
static inline void
jstx_to_ctx(const Local<Object> jstx, CTransaction& ctx_) {
String::Utf8Value hex_string_(jstx->Get(NanNew<String>("hex"))->ToString());
2014-10-27 10:59:52 -07:00
std::string hex_string = *hex_string_;
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
CDataStream ssData(ParseHex(hex_string), SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> ctx_;
} catch (std::exception &e) {
2014-11-14 14:59:51 -08:00
NanThrowError("Bad TX decode");
return;
2014-10-27 10:59:52 -07:00
}
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
return;
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
CMutableTransaction& ctx = (CMutableTransaction&)ctx_;
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
// With v0.9.0
// ctx.nMinTxFee = (int64_t)jstx->Get(NanNew<String>("mintxfee"))->IntegerValue();
// ctx.nMinRelayTxFee = (int64_t)jstx->Get(NanNew<String>("minrelaytxfee"))->IntegerValue();
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
// ctx.CURRENT_VERSION = (unsigned int)jstx->Get(NanNew<String>("current_version"))->Int32Value();
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
ctx.nVersion = (int)jstx->Get(NanNew<String>("version"))->Int32Value();
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
Local<Array> vin = Local<Array>::Cast(jstx->Get(NanNew<String>("vin")));
for (unsigned int vi = 0; vi < vin->Length(); vi++) {
CTxIn txin;
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
Local<Object> in = Local<Object>::Cast(vin->Get(vi));
2014-10-21 18:06:17 -07:00
String::Utf8Value phash__(in->Get(NanNew<String>("txid"))->ToString());
std::string phash_ = *phash__;
uint256 phash(phash_);
2014-10-21 18:06:17 -07:00
txin.prevout.hash = phash;
txin.prevout.n = (unsigned int)in->Get(NanNew<String>("vout"))->Uint32Value();
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
std::string shash_;
Local<Object> script_obj = Local<Object>::Cast(in->Get(NanNew<String>("scriptSig")));
String::Utf8Value shash__(script_obj->Get(NanNew<String>("hex"))->ToString());
2014-10-27 10:59:52 -07:00
shash_ = *shash__;
std::vector<unsigned char> shash(shash_.begin(), shash_.end());
CScript scriptSig(shash.begin(), shash.end());
2014-10-21 18:20:27 -07:00
2014-10-27 10:59:52 -07:00
txin.scriptSig = scriptSig;
txin.nSequence = (unsigned int)in->Get(NanNew<String>("sequence"))->Uint32Value();
ctx.vin.push_back(txin);
2014-10-21 18:06:17 -07:00
}
2014-10-27 10:59:52 -07:00
Local<Array> vout = Local<Array>::Cast(jstx->Get(NanNew<String>("vout")));
for (unsigned int vo = 0; vo < vout->Length(); vo++) {
CTxOut txout;
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
Local<Object> out = Local<Object>::Cast(vout->Get(vo));
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
int64_t nValue = (int64_t)out->Get(NanNew<String>("value"))->IntegerValue();
txout.nValue = nValue;
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
Local<Object> script_obj = Local<Object>::Cast(out->Get(NanNew<String>("scriptPubKey")));
String::Utf8Value phash__(script_obj->Get(NanNew<String>("hex")));
2014-10-27 10:59:52 -07:00
std::string phash_ = *phash__;
std::vector<unsigned char> phash(phash_.begin(), phash_.end());
CScript scriptPubKey(phash.begin(), phash.end());
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
txout.scriptPubKey = scriptPubKey;
2014-10-21 18:06:17 -07:00
2014-10-27 10:59:52 -07:00
ctx.vout.push_back(txout);
}
ctx.nLockTime = (unsigned int)jstx->Get(NanNew<String>("locktime"))->Uint32Value();
2014-10-21 18:06:17 -07:00
}
2014-11-19 13:42:11 -08:00
#if USE_LDB_ADDR
/**
LevelDB Parser
DB: blocks/blk/revXXXXX.dat
*/
static ctx_list *
2014-12-03 21:16:47 -08:00
read_addr(const std::string addr, const int64_t blockheight, const int64_t blocktime) {
ctx_list *head = new ctx_list();
ctx_list *cur = NULL;
2014-12-01 15:12:01 -08:00
head->err_msg = std::string("");
2014-12-01 15:09:47 -08:00
2014-12-01 15:02:58 -08:00
CScript expectedScriptSig = GetScriptForDestination(CBitcoinAddress(addr).Get());
leveldb::Iterator* pcursor = pblocktree->pdb->NewIterator(pblocktree->iteroptions);
pcursor->SeekToFirst();
while (pcursor->Valid()) {
boost::this_thread::interruption_point();
try {
leveldb::Slice slKey = pcursor->key();
2014-12-01 20:29:44 -08:00
2014-12-01 19:57:15 -08:00
CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
2014-12-01 20:29:44 -08:00
2014-12-01 17:01:00 -08:00
char type;
ssKey >> type;
2014-12-01 19:57:15 -08:00
2014-12-01 20:29:44 -08:00
// Blockchain Index Structure:
// http://bitcoin.stackexchange.com/questions/28168
// File info record structure
// 'f' + 4-byte file number
2014-12-01 20:29:44 -08:00
// Number of blocks stored in block file
// Size of block file: blocks/blkXXXXX.dat
// Size of undo file: blocks/revXXXXX.dat
// Low and high heights of blocks stored in file
// Low and high timestamps of blocks stored in file
if (type == 'f') {
2014-12-03 20:42:58 -08:00
goto next;
2014-12-01 20:29:44 -08:00
}
// Last block file number used structure
// 'l'
2014-12-01 20:29:44 -08:00
// 4-byte file number
if (type == 'l') {
2014-12-03 20:42:58 -08:00
goto next;
2014-12-01 20:29:44 -08:00
}
// Reindexing structure
// 'R'
2014-12-01 20:29:44 -08:00
// 1-byte Boolean (1 if reindexing)
if (type == 'R') {
2014-12-03 20:42:58 -08:00
goto next;
2014-12-01 20:29:44 -08:00
}
// Flags structure
// 'F' + 1-byte flag name + flag name string
2014-12-01 20:29:44 -08:00
// 1-byte Boolean (key may be `txindex` if transaction index is enabled)
if (type == 'F') {
2014-12-03 20:42:58 -08:00
goto next;
2014-12-01 20:29:44 -08:00
}
// Block Structure:
// 'b' + 32-byte block hash
// The block header
// The block height
// The number of transactions
// The block validation state
// The block file and pos
// The undo file and pos
2014-12-01 17:12:53 -08:00
if (type == 'b') {
2014-12-01 14:55:42 -08:00
leveldb::Slice slValue = pcursor->value();
2014-12-01 17:12:53 -08:00
2014-12-01 14:55:42 -08:00
CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
2014-12-01 17:12:53 -08:00
2014-12-01 17:01:00 -08:00
uint256 blockhash;
ssKey >> blockhash;
2014-12-01 19:57:15 -08:00
// class CBlockIndex {
// const uint256* phashBlock;
// CBlockIndex* pprev;
// CBlockIndex* pskip;
// int nHeight;
// int nFile;
// unsigned int nDataPos;
// unsigned int nUndoPos;
// uint256 nChainWork;
// unsigned int nTx;
// unsigned int nChainTx;
// unsigned int nStatus;
// int nVersion;
// uint256 hashMerkleRoot;
// unsigned int nTime;
// unsigned int nBits;
// unsigned int nNonce;
// uint32_t nSequenceId;
// };
// class CDiskBlockIndex : public CBlockIndex {
// uint256 hashPrev;
// };
2014-12-03 20:34:12 -08:00
CDiskBlockIndex index;
ssValue >> index;
2014-12-03 14:58:35 -08:00
2014-12-03 21:16:47 -08:00
if (blocktime != -1 && index.GetBlockTime() < blocktime) {
goto next;
}
// struct CDiskBlockPos {
// int nFile;
// unsigned int nPos;
// };
2014-12-03 20:34:12 -08:00
CDiskBlockPos blockPos;
blockPos.nFile = index.nFile;
blockPos.nPos = index.nDataPos;
2014-12-01 14:55:42 -08:00
CBlock cblock;
2014-12-01 19:57:15 -08:00
2014-12-01 20:29:44 -08:00
if (!ReadBlockFromDisk(cblock, blockPos)) {
2014-12-03 20:42:58 -08:00
goto next;
2014-12-01 20:29:44 -08:00
}
BOOST_FOREACH(const CTransaction& ctx, cblock.vtx) {
BOOST_FOREACH(const CTxIn& txin, ctx.vin) {
if (txin.scriptSig.ToString() != expectedScriptSig.ToString()) {
continue;
}
if (cur == NULL) {
head->ctx = ctx;
head->blockhash = blockhash;
head->next = NULL;
cur = head;
} else {
ctx_list *item = new ctx_list();
item->ctx = ctx;
item->blockhash = blockhash;
item->next = NULL;
cur->next = item;
cur = item;
}
2014-12-03 20:42:58 -08:00
goto next;
2014-12-01 20:29:44 -08:00
}
for (unsigned int vo = 0; vo < ctx.vout.size(); vo++) {
const CTxOut& txout = ctx.vout[vo];
const CScript& scriptPubKey = txout.scriptPubKey;
int nRequired;
txnouttype type;
vector<CTxDestination> addresses;
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
continue;
}
BOOST_FOREACH(const CTxDestination& address, addresses) {
if (CBitcoinAddress(address).ToString() != addr) {
2014-12-01 14:55:42 -08:00
continue;
}
if (cur == NULL) {
head->ctx = ctx;
head->blockhash = blockhash;
head->next = NULL;
cur = head;
} else {
ctx_list *item = new ctx_list();
item->ctx = ctx;
item->blockhash = blockhash;
item->next = NULL;
cur->next = item;
cur = item;
}
2014-12-03 20:42:58 -08:00
goto next;
2014-12-01 14:55:42 -08:00
}
}
}
}
2014-12-01 19:57:15 -08:00
2014-12-01 20:29:44 -08:00
// Transaction Structure:
// 't' + 32-byte tx hash
// Which block file the tx is stored in
// Which offset in the block file the tx resides
// The offset from the top of the block containing the tx
2014-12-01 19:57:15 -08:00
if (type == 't') {
leveldb::Slice slValue = pcursor->value();
CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
2014-12-08 11:31:00 -08:00
uint256 txid;
ssKey >> txid;
2014-12-01 19:57:15 -08:00
// struct CDiskBlockPos {
// int nFile;
// unsigned int nPos;
// };
// struct CDiskTxPos : public CDiskBlockPos {
// unsigned int nTxOffset;
// };
2014-12-01 19:57:15 -08:00
CDiskTxPos txPos;
2014-12-03 14:21:37 -08:00
ssValue >> txPos;
2014-12-01 19:57:15 -08:00
2014-12-01 20:29:44 -08:00
CTransaction ctx;
uint256 blockhash;
2014-12-01 19:57:15 -08:00
2014-12-08 11:31:00 -08:00
if (!pblocktree->ReadTxIndex(txid, txPos)) {
2014-12-03 20:42:58 -08:00
goto next;
2014-12-01 20:29:44 -08:00
}
2014-12-01 19:57:15 -08:00
2014-12-01 20:29:44 -08:00
CAutoFile file(OpenBlockFile(txPos, true), SER_DISK, CLIENT_VERSION);
CBlockHeader header;
try {
file >> header;
fseek(file.Get(), txPos.nTxOffset, SEEK_CUR);
file >> ctx;
} catch (std::exception &e) {
goto error;
}
2014-12-08 11:31:00 -08:00
if (ctx.GetHash() != txid) {
2014-12-01 20:29:44 -08:00
goto error;
}
blockhash = header.GetHash();
2014-12-01 19:57:15 -08:00
2014-12-01 20:29:44 -08:00
BOOST_FOREACH(const CTxIn& txin, ctx.vin) {
if (txin.scriptSig.ToString() != expectedScriptSig.ToString()) {
continue;
}
if (cur == NULL) {
head->ctx = ctx;
head->blockhash = blockhash;
head->next = NULL;
cur = head;
} else {
ctx_list *item = new ctx_list();
item->ctx = ctx;
item->blockhash = blockhash;
item->next = NULL;
cur->next = item;
cur = item;
}
2014-12-03 20:42:58 -08:00
goto next;
2014-12-01 20:29:44 -08:00
}
2014-12-01 16:48:37 -08:00
2014-12-01 20:29:44 -08:00
for (unsigned int vo = 0; vo < ctx.vout.size(); vo++) {
const CTxOut& txout = ctx.vout[vo];
const CScript& scriptPubKey = txout.scriptPubKey;
int nRequired;
txnouttype type;
vector<CTxDestination> addresses;
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
continue;
}
BOOST_FOREACH(const CTxDestination& address, addresses) {
if (CBitcoinAddress(address).ToString() != addr) {
continue;
}
if (cur == NULL) {
head->ctx = ctx;
head->blockhash = blockhash;
head->next = NULL;
cur = head;
} else {
ctx_list *item = new ctx_list();
item->ctx = ctx;
item->blockhash = blockhash;
item->next = NULL;
cur->next = item;
cur = item;
}
2014-12-03 20:42:58 -08:00
goto next;
2014-12-01 20:29:44 -08:00
}
}
2014-12-01 16:48:37 -08:00
}
2014-12-03 12:31:39 -08:00
2014-12-03 20:42:58 -08:00
next:
2014-12-01 20:29:44 -08:00
pcursor->Next();
} catch (std::exception &e) {
head->err_msg = std::string(e.what()
+ std::string(" : Deserialize error. Key: ")
+ pcursor->key().ToString());
2014-12-01 19:57:15 -08:00
delete pcursor;
return head;
}
}
2014-12-01 15:02:58 -08:00
delete pcursor;
2014-12-01 20:29:44 -08:00
return head;
error:
head->err_msg = std::string("Deserialize Error.");
delete pcursor;
return head;
}
#endif
2014-11-11 16:10:26 -08:00
/**
LevelDB Parser
DB: blocks/blk/revXXXXX.dat
*/
2014-12-08 10:21:50 -08:00
#if USE_LDB_TX
2014-12-03 12:14:23 -08:00
static bool
2014-12-10 16:22:30 -08:00
get_block_by_tx(const std::string itxid, CBlock& rcblock, CBlockIndex **rcblock_index, CTransaction& rctx) {
const char *txkey = std::string(std::string("t") + itxid).c_str();
std::string slValue;
//leveldb::Slice slValue;
2014-12-03 12:14:23 -08:00
2014-12-10 16:22:30 -08:00
pblocktree->pdb->Get(leveldb::ReadOptions(), txkey, &slValue);
2014-12-03 12:14:23 -08:00
2014-12-10 16:22:30 -08:00
CDataStream ssValue(slValue.begin(), slValue.end(), SER_DISK, CLIENT_VERSION);
//CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
2014-12-03 12:14:23 -08:00
2014-12-10 16:22:30 -08:00
// Blockchain Index Structure:
// http://bitcoin.stackexchange.com/questions/28168
2014-12-03 12:14:23 -08:00
2014-12-10 16:22:30 -08:00
// Transaction Structure:
// 't' + 32-byte tx hash
// Which block file the tx is stored in
// Which offset in the block file the tx resides
// The offset from the top of the block containing the tx
2014-12-03 12:14:23 -08:00
2014-12-10 16:22:30 -08:00
// struct CDiskBlockPos {
// int nFile;
// unsigned int nPos;
// };
// struct CDiskTxPos : public CDiskBlockPos {
// unsigned int nTxOffset;
// };
2014-12-10 16:22:30 -08:00
CDiskTxPos txPos;
ssValue >> txPos;
2014-12-03 12:14:23 -08:00
2014-12-10 16:22:30 -08:00
CTransaction ctx;
uint256 blockhash;
2014-12-03 12:14:23 -08:00
2014-12-10 16:22:30 -08:00
if (!pblocktree->ReadTxIndex(txid, txPos)) {
goto error;
}
2014-12-03 12:14:23 -08:00
2014-12-10 16:22:30 -08:00
CAutoFile file(OpenBlockFile(txPos, true), SER_DISK, CLIENT_VERSION);
CBlockHeader header;
try {
file >> header;
fseek(file.Get(), txPos.nTxOffset, SEEK_CUR);
file >> ctx;
} catch (std::exception &e) {
goto error;
}
if (ctx.GetHash() != txid) {
goto error;
}
blockhash = header.GetHash();
2014-12-03 12:14:23 -08:00
2014-12-10 16:22:30 -08:00
CBlockIndex* pblockindex = mapBlockIndex[blockhash];
2014-12-03 12:31:39 -08:00
2014-12-10 16:22:30 -08:00
if (ReadBlockFromDisk(rcblock, pblockindex)) {
*rcblock_index = pblockindex;
rctx = ctx;
return true;
2014-12-03 12:14:23 -08:00
}
2014-12-03 12:31:39 -08:00
return false;
2014-12-03 12:14:23 -08:00
}
2014-12-08 10:21:50 -08:00
#endif
2014-12-03 12:14:23 -08:00
2014-12-10 10:44:01 -08:00
/**
* Helpers
*/
static bool
2014-12-10 11:42:33 -08:00
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;
2014-12-10 10:44:01 -08:00
}
return false;
}
2014-11-13 11:56:15 -08:00
2014-08-12 12:03:04 -07:00
/**
2014-10-06 11:05:52 -07:00
* Init()
* Initialize the singleton object known as bitcoindjs.
2014-08-12 12:03:04 -07:00
*/
extern "C" void
init(Handle<Object> target) {
NanScope();
2014-09-29 13:38:27 -07:00
2014-08-12 12:03:04 -07:00
NODE_SET_METHOD(target, "start", StartBitcoind);
2015-07-07 14:02:03 -07:00
NODE_SET_METHOD(target, "onBlocksReady", OnBlocksReady);
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-12-03 11:03:54 -08:00
NODE_SET_METHOD(target, "getTransaction", GetTransaction);
2014-09-25 12:05:39 -07:00
NODE_SET_METHOD(target, "broadcastTx", BroadcastTx);
2014-09-26 11:23:21 -07:00
NODE_SET_METHOD(target, "verifyBlock", VerifyBlock);
2014-09-26 11:34:55 -07:00
NODE_SET_METHOD(target, "verifyTransaction", VerifyTransaction);
2014-10-17 13:26:27 -07:00
NODE_SET_METHOD(target, "getInfo", GetInfo);
2014-10-17 13:47:56 -07:00
NODE_SET_METHOD(target, "getPeerInfo", GetPeerInfo);
2014-10-17 16:12:57 -07:00
NODE_SET_METHOD(target, "getAddresses", GetAddresses);
2014-10-28 13:01:40 -07:00
NODE_SET_METHOD(target, "getProgress", GetProgress);
2014-10-28 14:16:33 -07:00
NODE_SET_METHOD(target, "getMiningInfo", GetMiningInfo);
2014-11-04 16:08:31 -08:00
NODE_SET_METHOD(target, "getAddrTransactions", GetAddrTransactions);
2014-11-06 13:37:15 -08:00
NODE_SET_METHOD(target, "getBestBlock", GetBestBlock);
NODE_SET_METHOD(target, "getChainHeight", GetChainHeight);
2014-12-03 12:14:23 -08:00
NODE_SET_METHOD(target, "getBlockByTx", GetBlockByTx);
2014-12-04 11:12:29 -08:00
NODE_SET_METHOD(target, "getBlocksByTime", GetBlocksByTime);
2014-12-16 14:41:00 -08:00
NODE_SET_METHOD(target, "getFromTx", GetFromTx);
NODE_SET_METHOD(target, "getLastFileIndex", GetLastFileIndex);
NODE_SET_METHOD(target, "getBlockHex", GetBlockHex);
NODE_SET_METHOD(target, "getTxHex", GetTxHex);
2014-10-03 18:27:06 -07:00
NODE_SET_METHOD(target, "blockFromHex", BlockFromHex);
NODE_SET_METHOD(target, "txFromHex", TxFromHex);
2014-10-27 10:59:52 -07:00
NODE_SET_METHOD(target, "hookPackets", HookPackets);
2014-09-26 12:42:04 -07:00
2014-08-12 12:03:04 -07:00
}
NODE_MODULE(bitcoindjs, init)