bitcore-node-zcash/src/bitcoindjs.cc

2169 lines
59 KiB
C++
Raw Normal View History

2014-08-12 12:03:04 -07:00
/**
* bitcoind.js
* Copyright (c) 2014, BitPay (MIT License)
*
* bitcoindjs.cc:
* A bitcoind node.js binding.
*/
#include "nan.h"
#include "bitcoindjs.h"
2014-08-20 17:00:09 -07:00
/**
* Bitcoin headers
*/
2014-09-17 12:14:20 -07:00
#if defined(HAVE_CONFIG_H)
#include "bitcoin-config.h"
#endif
#include "core.h"
#include "addrman.h"
#include "checkpoints.h"
#include "crypter.h"
#include "main.h"
// #include "random.h"
// #include "timedata.h"
2014-09-17 12:14:20 -07:00
#ifdef ENABLE_WALLET
#include "db.h"
#include "wallet.h"
#include "walletdb.h"
2014-09-17 12:14:20 -07:00
#endif
// #include "walletdb.h"
#include "alert.h"
#include "checkqueue.h"
2014-09-17 12:14:20 -07:00
// #include "db.h"
#include "miner.h"
#include "rpcclient.h"
#include "tinyformat.h"
2014-09-17 12:14:20 -07:00
// #include "wallet.h"
#include "allocators.h"
#include "clientversion.h"
#include "hash.h"
#include "mruset.h"
#include "rpcprotocol.h"
#include "txdb.h"
#include "base58.h"
#include "coincontrol.h"
#include "init.h"
#include "netbase.h"
#include "rpcserver.h"
#include "txmempool.h"
#include "bloom.h"
#include "coins.h"
#include "key.h"
#include "net.h"
#include "script.h"
#include "ui_interface.h"
// #include "chainparamsbase.h"
#include "compat.h"
#include "keystore.h"
#include "noui.h"
#include "serialize.h"
#include "uint256.h"
#include "chainparams.h"
#include "core.h"
#include "leveldbwrapper.h"
// #include "pow.h"
#include "sync.h"
#include "util.h"
// #include "chainparamsseeds.h"
// #include "core_io.h"
#include "limitedmap.h"
#include "protocol.h"
#include "threadsafety.h"
#include "version.h"
2014-08-20 17:00:09 -07:00
/**
* Bitcoin Globals
* Relevant:
* ~/bitcoin/src/init.cpp
* ~/bitcoin/src/bitcoind.cpp
* ~/bitcoin/src/main.h
*/
2014-09-17 12:14:20 -07:00
#include <stdint.h>
#include <signal.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include <openssl/crypto.h>
using namespace std;
using namespace boost;
2014-09-17 11:23:38 -07:00
extern void DetectShutdownThread(boost::thread_group*);
extern int nScriptCheckThreads;
extern bool fDaemon;
extern std::map<std::string, std::string> mapArgs;
#ifdef ENABLE_WALLET
extern std::string strWalletFile;
extern CWallet *pwalletMain;
#endif
2014-08-20 17:00:09 -07:00
2014-09-22 13:21:42 -07:00
/**
* Node and Templates
*/
#include <node.h>
#include <string>
2014-08-12 12:03:04 -07:00
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
using namespace node;
using namespace v8;
2014-09-29 13:38:27 -07:00
Handle<Object> bitcoindjs_obj;
2014-08-12 12:03:04 -07:00
NAN_METHOD(StartBitcoind);
2014-09-19 13:53:55 -07:00
NAN_METHOD(IsStopping);
NAN_METHOD(IsStopped);
NAN_METHOD(StopBitcoind);
NAN_METHOD(GetBlock);
2014-09-22 15:31:56 -07:00
NAN_METHOD(GetTx);
2014-09-22 17:58:59 -07:00
NAN_METHOD(PollBlocks);
2014-09-23 13:57:49 -07:00
NAN_METHOD(PollMempool);
2014-09-25 12:05:39 -07:00
NAN_METHOD(BroadcastTx);
2014-09-26 11:23:21 -07:00
NAN_METHOD(VerifyBlock);
2014-09-26 11:34:55 -07:00
NAN_METHOD(VerifyTransaction);
2014-09-26 12:42:04 -07:00
2014-09-26 12:20:00 -07:00
NAN_METHOD(WalletNewAddress);
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletGetAccountAddress);
NAN_METHOD(WalletSetAccount);
NAN_METHOD(WalletGetAccount);
2014-09-29 11:59:57 -07:00
NAN_METHOD(WalletSendTo);
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletSignMessage);
NAN_METHOD(WalletVerifyMessage);
NAN_METHOD(WalletGetBalance);
NAN_METHOD(WalletGetUnconfirmedBalance);
NAN_METHOD(WalletSendFrom);
NAN_METHOD(WalletListTransactions);
NAN_METHOD(WalletListAccounts);
NAN_METHOD(WalletGetTransaction);
NAN_METHOD(WalletBackup);
2014-09-26 12:42:04 -07:00
NAN_METHOD(WalletPassphrase);
NAN_METHOD(WalletPassphraseChange);
NAN_METHOD(WalletLock);
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletEncrypt);
NAN_METHOD(WalletSetTxFee);
2014-08-12 12:03:04 -07:00
static void
async_start_node_work(uv_work_t *req);
static void
async_start_node_after(uv_work_t *req);
2014-08-12 12:03:04 -07:00
2014-09-11 17:18:36 -07:00
static void
async_stop_node_work(uv_work_t *req);
static void
async_stop_node_after(uv_work_t *req);
static int
start_node(void);
2014-09-17 14:08:26 -07:00
static void
start_node_thread(void);
2014-09-17 12:52:35 -07:00
2014-09-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-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-09-22 17:58:59 -07:00
static void
async_poll_blocks(uv_work_t *req);
static void
async_poll_blocks_after(uv_work_t *req);
static void
2014-09-23 13:57:49 -07:00
async_poll_mempool(uv_work_t *req);
static void
2014-09-23 13:57:49 -07:00
async_poll_mempool_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-09-29 11:59:57 -07:00
static void
async_wallet_sendto(uv_work_t *req);
static void
async_wallet_sendto_after(uv_work_t *req);
2014-09-29 12:15:59 -07:00
static void
async_wallet_sendfrom(uv_work_t *req);
static void
async_wallet_sendfrom_after(uv_work_t *req);
2014-09-23 13:57:49 -07:00
static inline void
2014-09-29 13:38:27 -07:00
ctx_to_jstx(const CTransaction& tx, uint256 hashBlock, Local<Object> entry);
static inline void
cblock_to_jsblock(const CBlock& block, const CBlockIndex* blockindex, Local<Object> obj);
2014-09-29 13:49:13 -07:00
#if 0
2014-09-29 13:38:27 -07:00
static inline void
jsblock_to_cblock(Local<Object> jsblock, CBlock& cblock);
2014-09-23 13:57:49 -07:00
static inline void
2014-09-29 13:38:27 -07:00
jstx_to_ctx(Local<Object> jstx, CTransaction& ctx);
2014-09-29 13:49:13 -07:00
#endif
2014-08-12 12:03:04 -07:00
extern "C" void
init(Handle<Object>);
2014-09-19 13:53:55 -07:00
/**
2014-09-22 13:21:42 -07:00
* Private Variables
2014-09-19 13:53:55 -07:00
*/
2014-09-22 13:21:42 -07:00
static volatile bool shutdownComplete = false;
2014-09-19 13:53:55 -07:00
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-09-04 15:16:32 -07:00
Persistent<Function> callback;
};
2014-09-22 13:21:42 -07:00
/**
* async_block_data
*/
struct async_block_data {
std::string err_msg;
std::string hash;
CBlock result_block;
CBlockIndex* result_blockindex;
Persistent<Function> callback;
};
/**
* async_tx_data
*/
struct async_tx_data {
std::string err_msg;
std::string txHash;
std::string blockHash;
CTransaction result_tx;
Persistent<Function> callback;
};
2014-09-22 17:16:27 -07:00
/**
* async_poll_blocks_data
*/
struct async_poll_blocks_data {
std::string err_msg;
2014-09-22 18:34:38 -07:00
int poll_saved_height;
int poll_top_height;
2014-09-22 17:16:27 -07:00
Persistent<Array> result_array;
Persistent<Function> callback;
};
2014-09-23 13:57:49 -07:00
/**
* async_poll_mempool_data
*/
struct async_poll_mempool_data {
std::string err_msg;
int poll_saved_height;
int poll_top_height;
Persistent<Array> result_array;
Persistent<Function> callback;
};
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;
2014-09-25 12:38:42 -07:00
std::string tx_hex;
std::string tx_hash;
2014-09-25 12:05:39 -07:00
bool override_fees;
2014-09-25 13:12:28 -07:00
bool own_only;
2014-09-25 12:05:39 -07:00
Persistent<Function> callback;
};
2014-09-23 13:57:49 -07:00
2014-09-29 11:59:57 -07:00
/**
* async_wallet_sendto_data
*/
struct async_wallet_sendto_data {
std::string err_msg;
std::string tx_hash;
std::string address;
int64_t nAmount;
CWalletTx wtx;
Persistent<Function> callback;
};
2014-09-29 12:15:59 -07:00
/**
* async_wallet_sendfrom_data
*/
struct async_wallet_sendfrom_data {
std::string err_msg;
std::string tx_hash;
std::string address;
int64_t nAmount;
int nMinDepth;
CWalletTx wtx;
Persistent<Function> callback;
};
2014-08-12 12:03:04 -07:00
/**
* StartBitcoind
* bitcoind.start(callback)
*/
NAN_METHOD(StartBitcoind) {
NanScope();
if (args.Length() < 1 || !args[0]->IsFunction()) {
return NanThrowError(
2014-09-22 12:57:25 -07:00
"Usage: bitcoind.start(callback)");
2014-08-12 12:03:04 -07:00
}
Local<Function> callback = Local<Function>::Cast(args[0]);
//
// 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("");
data->callback = Persistent<Function>::New(callback);
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(),
req, async_start_node_work,
(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
2014-09-17 14:08:26 -07:00
NanReturnValue(NanNew<Number>(-1));
2014-08-12 12:03:04 -07:00
}
2014-08-20 17:00:09 -07:00
/**
* async_start_node_work()
2014-08-20 17:00:09 -07:00
* Call start_node() and start all our boost threads.
*/
static void
async_start_node_work(uv_work_t *req) {
2014-09-29 12:18:29 -07:00
async_node_data *data = static_cast<async_node_data*>(req->data);
2014-09-05 15:07:38 -07:00
start_node();
2014-09-29 12:18:29 -07:00
data->result = std::string("start_node(): bitcoind opened.");
}
2014-08-20 17:00:09 -07:00
/**
* async_start_node_after()
2014-08-20 17:00:09 -07:00
* Execute our callback.
*/
static void
async_start_node_after(uv_work_t *req) {
NanScope();
2014-09-29 12:18:29 -07:00
async_node_data *data = static_cast<async_node_data*>(req->data);
2014-09-29 12:18:29 -07:00
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
2014-09-29 12:18:29 -07:00
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
2014-09-29 12:18:29 -07:00
Local<Value>::New(String::New(data->result.c_str()))
};
TryCatch try_catch;
2014-09-29 12:18:29 -07:00
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
2014-09-29 12:18:29 -07:00
// data->callback.Dispose();
2014-09-29 12:18:29 -07:00
delete data;
delete req;
2014-08-12 12:03:04 -07:00
}
2014-09-17 14:08:26 -07:00
/**
* IsStopping()
* bitcoind.stopping()
*/
NAN_METHOD(IsStopping) {
NanScope();
NanReturnValue(NanNew<Boolean>(ShutdownRequested()));
}
2014-09-17 12:52:35 -07:00
/**
* IsStopped()
* bitcoind.stopped()
*/
2014-09-17 14:08:26 -07:00
NAN_METHOD(IsStopped) {
2014-09-17 12:52:35 -07:00
NanScope();
2014-09-17 14:08:26 -07:00
NanReturnValue(NanNew<Boolean>(shutdownComplete));
2014-09-17 12:52:35 -07:00
}
2014-08-20 17:00:09 -07:00
/**
* start_node(void)
2014-09-17 14:08:26 -07:00
* start_node_thread(void)
2014-08-20 17:00:09 -07:00
* A reimplementation of AppInit2 minus
* the logging and argument parsing.
*/
static int
start_node(void) {
2014-09-17 12:14:20 -07:00
noui_connect();
2014-09-17 14:08:26 -07:00
(boost::thread *)new boost::thread(boost::bind(&start_node_thread));
2014-09-17 12:14:20 -07:00
2014-09-29 11:40:00 -07:00
// wait for wallet to be instantiated
// this also avoids a race condition with signals not being set up
while (!pwalletMain) {
useconds_t usec = 100 * 1000;
usleep(usec);
}
// 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);
2014-09-17 12:14:20 -07:00
2014-09-17 12:52:35 -07:00
return 0;
}
2014-09-17 12:14:20 -07:00
2014-09-17 14:08:26 -07:00
static void
start_node_thread(void) {
2014-09-17 12:52:35 -07:00
boost::thread_group threadGroup;
2014-09-19 15:39:05 -07:00
boost::thread *detectShutdownThread = NULL;
2014-09-17 12:14:20 -07:00
2014-09-17 12:52:35 -07:00
const int argc = 0;
const char *argv[argc + 1] = {
//"-server",
NULL
};
ParseParameters(argc, argv);
ReadConfigFile(mapArgs, mapMultiArgs);
if (!SelectParamsFromCommandLine()) {
2014-09-17 14:08:26 -07:00
return;
2014-09-17 12:14:20 -07:00
}
2014-09-17 12:52:35 -07:00
// CreatePidFile(GetPidFile(), getpid());
detectShutdownThread = new boost::thread(
boost::bind(&DetectShutdownThread, &threadGroup));
2014-09-17 12:14:20 -07:00
2014-09-17 12:52:35 -07:00
int fRet = AppInit2(threadGroup);
2014-09-17 12:14:20 -07:00
if (!fRet) {
if (detectShutdownThread)
detectShutdownThread->interrupt();
threadGroup.interrupt_all();
}
if (detectShutdownThread) {
detectShutdownThread->join();
delete detectShutdownThread;
detectShutdownThread = NULL;
}
Shutdown();
2014-09-17 14:08:26 -07:00
shutdownComplete = true;
}
2014-09-11 17:18:36 -07:00
/**
* StopBitcoind
* bitcoind.stop(callback)
*/
NAN_METHOD(StopBitcoind) {
NanScope();
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("");
data->callback = Persistent<Function>::New(callback);
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(),
req, async_stop_node_work,
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);
2014-09-11 17:18:36 -07:00
NanReturnValue(Undefined());
}
/**
* async_stop_node_work()
* Call StartShutdown() to join the boost threads, which will call Shutdown().
*/
static void
async_stop_node_work(uv_work_t *req) {
2014-09-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
StartShutdown();
2014-09-29 12:18:29 -07:00
data->result = std::string("stop_node(): 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) {
NanScope();
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
2014-09-29 12:18:29 -07:00
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
2014-09-11 17:18:36 -07:00
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
2014-09-29 12:18:29 -07:00
data->callback->Call(Context::GetCurrent()->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] = {
Local<Value>::New(Null()),
2014-09-29 12:18:29 -07:00
Local<Value>::New(String::New(data->result.c_str()))
2014-09-11 17:18:36 -07:00
};
TryCatch try_catch;
2014-09-29 12:18:29 -07:00
data->callback->Call(Context::GetCurrent()->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
data->callback.Dispose();
2014-09-11 17:18:36 -07:00
2014-09-29 12:18:29 -07:00
delete data;
2014-09-11 17:18:36 -07:00
delete req;
}
2014-09-19 13:53:55 -07:00
/**
2014-09-25 13:54:20 -07:00
* GetBlock
* bitcoind.getBlock(blockHash, callback)
2014-09-19 13:53:55 -07:00
*/
NAN_METHOD(GetBlock) {
NanScope();
if (args.Length() < 2
|| !args[0]->IsString()
|| !args[1]->IsFunction()) {
return NanThrowError(
2014-09-22 12:57:25 -07:00
"Usage: bitcoindjs.getBlock(blockHash, callback)");
2014-09-19 13:53:55 -07:00
}
String::Utf8Value hash(args[0]->ToString());
Local<Function> callback = Local<Function>::Cast(args[1]);
std::string hashp = std::string(*hash);
async_block_data *data = new async_block_data();
data->err_msg = std::string("");
data->hash = hashp;
data->callback = Persistent<Function>::New(callback);
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_get_block,
(uv_after_work_cb)async_get_block_after);
assert(status == 0);
NanReturnValue(Undefined());
}
static void
async_get_block(uv_work_t *req) {
async_block_data* data = static_cast<async_block_data*>(req->data);
std::string strHash = data->hash;
if (strHash[1] != 'x') {
strHash = "0x" + strHash;
}
uint256 hash(strHash);
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash];
if (ReadBlockFromDisk(block, pblockindex)) {
2014-09-19 15:39:05 -07:00
data->result_block = block;
data->result_blockindex = pblockindex;
2014-09-19 13:53:55 -07:00
} else {
data->err_msg = std::string("get_block(): failed.");
}
}
static void
async_get_block_after(uv_work_t *req) {
NanScope();
async_block_data* data = static_cast<async_block_data*>(req->data);
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
2014-09-19 15:39:05 -07:00
const CBlock& block = data->result_block;
const CBlockIndex* blockindex = data->result_blockindex;
Local<Object> obj = NanNew<Object>();
2014-09-29 13:38:27 -07:00
cblock_to_jsblock(block, blockindex, obj);
2014-09-19 15:39:05 -07:00
2014-09-19 13:53:55 -07:00
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
2014-09-19 15:39:05 -07:00
Local<Value>::New(obj)
2014-09-19 13:53:55 -07:00
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
}
2014-09-22 10:19:37 -07:00
/**
2014-09-25 13:54:20 -07:00
* GetTx
* bitcoind.getTx(txHash, [blockHash], callback)
2014-09-22 10:19:37 -07:00
*/
2014-09-22 13:21:42 -07:00
NAN_METHOD(GetTx) {
NanScope();
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()
|| !args[2]->IsFunction()) {
return NanThrowError(
"Usage: bitcoindjs.getTx(txHash, [blockHash], callback)");
}
String::Utf8Value txHash_(args[0]->ToString());
String::Utf8Value blockHash_(args[1]->ToString());
Local<Function> callback = Local<Function>::Cast(args[2]);
Persistent<Function> cb;
cb = Persistent<Function>::New(callback);
std::string txHash = std::string(*txHash_);
std::string blockHash = std::string(*blockHash_);
if (blockHash.empty()) {
blockHash = std::string("0x0000000000000000000000000000000000000000000000000000000000000000");
}
if (txHash[1] != 'x') {
txHash = "0x" + txHash;
}
if (blockHash[1] != 'x') {
blockHash = "0x" + blockHash;
}
async_tx_data *data = new async_tx_data();
data->err_msg = std::string("");
data->txHash = txHash;
data->blockHash = blockHash;
data->callback = Persistent<Function>::New(callback);
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_get_tx,
(uv_after_work_cb)async_get_tx_after);
assert(status == 0);
NanReturnValue(Undefined());
}
static void
async_get_tx(uv_work_t *req) {
async_tx_data* data = static_cast<async_tx_data*>(req->data);
uint256 hash(data->txHash);
uint256 hashBlock(data->blockHash);
CTransaction tx;
2014-09-26 10:16:10 -07:00
if (GetTransaction(hash, tx, hashBlock, true)) {
2014-09-22 13:21:42 -07:00
data->result_tx = tx;
} else {
2014-09-26 10:16:10 -07:00
data->err_msg = std::string("get_tx(): failed.");
2014-09-22 13:21:42 -07:00
}
}
static void
async_get_tx_after(uv_work_t *req) {
NanScope();
async_tx_data* data = static_cast<async_tx_data*>(req->data);
std::string txHash = data->txHash;
std::string blockHash = data->blockHash;
CTransaction tx = data->result_tx;
uint256 hash(txHash);
uint256 hashBlock(blockHash);
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
2014-09-29 12:18:29 -07:00
std::string strHex = HexStr(ssTx.begin(), ssTx.end());
2014-09-22 13:21:42 -07:00
Local<Object> entry = NanNew<Object>();
entry->Set(NanNew<String>("hex"), NanNew<String>(strHex));
2014-09-29 13:38:27 -07:00
ctx_to_jstx(tx, hashBlock, entry);
2014-09-22 13:21:42 -07:00
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(entry)
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
}
2014-09-22 10:19:37 -07:00
2014-09-22 16:36:36 -07:00
/**
2014-09-25 13:54:20 -07:00
* PollBlocks
2014-09-22 17:58:59 -07:00
* bitcoind.pollBlocks(callback)
2014-09-22 16:36:36 -07:00
*/
2014-09-22 17:16:27 -07:00
NAN_METHOD(PollBlocks) {
2014-09-22 16:36:36 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsFunction()) {
return NanThrowError(
2014-09-22 17:16:27 -07:00
"Usage: bitcoindjs.pollBlocks(callback)");
2014-09-22 16:36:36 -07:00
}
Local<Function> callback = Local<Function>::Cast(args[0]);
2014-09-22 17:16:27 -07:00
async_poll_blocks_data *data = new async_poll_blocks_data();
2014-09-22 18:34:38 -07:00
data->poll_saved_height = -1;
data->poll_top_height = -1;
2014-09-22 17:16:27 -07:00
data->err_msg = std::string("");
data->callback = Persistent<Function>::New(callback);
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_poll_blocks,
(uv_after_work_cb)async_poll_blocks_after);
assert(status == 0);
2014-09-22 16:36:36 -07:00
NanReturnValue(Undefined());
}
2014-09-22 16:47:45 -07:00
static void
2014-09-22 17:16:27 -07:00
async_poll_blocks(uv_work_t *req) {
async_poll_blocks_data* data = static_cast<async_poll_blocks_data*>(req->data);
2014-09-22 18:34:38 -07:00
data->poll_saved_height = data->poll_top_height;
2014-09-22 17:58:59 -07:00
2014-09-22 18:34:38 -07:00
while (chainActive.Tip()) {
int cur_height = chainActive.Height();
if (cur_height != data->poll_top_height) {
data->poll_top_height = cur_height;
2014-09-22 17:16:27 -07:00
break;
2014-09-22 18:21:08 -07:00
} else {
// 100 milliseconds
useconds_t usec = 100 * 1000;
usleep(usec);
2014-09-22 17:16:27 -07:00
}
2014-09-22 16:47:45 -07:00
}
2014-09-22 17:16:27 -07:00
}
static void
async_poll_blocks_after(uv_work_t *req) {
NanScope();
async_poll_blocks_data* data = static_cast<async_poll_blocks_data*>(req->data);
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
2014-09-22 16:47:45 -07:00
}
2014-09-22 17:16:27 -07:00
} else {
const unsigned argc = 2;
2014-09-22 17:58:59 -07:00
Local<Array> blocks = NanNew<Array>();
2014-09-22 18:34:38 -07:00
for (int i = data->poll_saved_height, j = 0; i < data->poll_top_height; i++) {
if (i == -1) continue;
CBlockIndex *pindex = chainActive[i];
if (pindex != NULL) {
2014-09-22 17:58:59 -07:00
CBlock block;
2014-09-22 18:34:38 -07:00
if (ReadBlockFromDisk(block, pindex)) {
2014-09-23 10:21:44 -07:00
Local<Object> obj = NanNew<Object>();
2014-09-29 13:38:27 -07:00
cblock_to_jsblock(block, pindex, obj);
2014-09-23 10:21:44 -07:00
blocks->Set(j, obj);
2014-09-22 18:34:38 -07:00
j++;
2014-09-22 17:58:59 -07:00
}
}
}
2014-09-22 17:16:27 -07:00
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
2014-09-22 17:58:59 -07:00
Local<Value>::New(blocks)
2014-09-22 17:16:27 -07:00
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
}
2014-09-23 13:57:49 -07:00
/**
2014-09-25 13:54:20 -07:00
* PollMempool
2014-09-23 13:57:49 -07:00
* bitcoind.pollMempool(callback)
*/
NAN_METHOD(PollMempool) {
NanScope();
if (args.Length() < 1 || !args[0]->IsFunction()) {
return NanThrowError(
"Usage: bitcoindjs.pollMempool(callback)");
}
Local<Function> callback = Local<Function>::Cast(args[0]);
async_poll_mempool_data *data = new async_poll_mempool_data();
data->poll_saved_height = -1;
data->poll_top_height = -1;
data->err_msg = std::string("");
data->callback = Persistent<Function>::New(callback);
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_poll_mempool,
(uv_after_work_cb)async_poll_mempool_after);
assert(status == 0);
NanReturnValue(Undefined());
}
static void
async_poll_mempool(uv_work_t *req) {
// async_poll_blocks_data* data = static_cast<async_poll_blocks_data*>(req->data);
// Nothing really async to do here. It's all in memory. Placeholder for now.
useconds_t usec = 20 * 1000;
usleep(usec);
}
static void
async_poll_mempool_after(uv_work_t *req) {
NanScope();
async_poll_blocks_data* data = static_cast<async_poll_blocks_data*>(req->data);
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
int ti = 0;
Local<Array> txs = NanNew<Array>();
{
std::map<uint256, CTxMemPoolEntry>::const_iterator it = mempool.mapTx.begin();
for (; it != mempool.mapTx.end(); it++) {
const CTransaction& tx = it->second.GetTx();
Local<Object> entry = NanNew<Object>();
2014-09-29 13:38:27 -07:00
ctx_to_jstx(tx, 0, entry);
2014-09-23 13:57:49 -07:00
txs->Set(ti, entry);
ti++;
}
}
{
std::map<COutPoint, CInPoint>::const_iterator it = mempool.mapNextTx.begin();
for (; it != mempool.mapNextTx.end(); it++) {
const CTransaction tx = *it->second.ptx;
Local<Object> entry = NanNew<Object>();
2014-09-29 13:38:27 -07:00
ctx_to_jstx(tx, 0, entry);
2014-09-23 13:57:49 -07:00
txs->Set(ti, entry);
ti++;
}
}
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(txs)
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
}
2014-09-25 12:05:39 -07:00
/**
2014-09-25 13:54:20 -07:00
* BroadcastTx
2014-09-25 13:12:28 -07:00
* bitcoind.broadcastTx(tx, override_fees, own_only, callback)
2014-09-25 12:05:39 -07:00
*/
NAN_METHOD(BroadcastTx) {
NanScope();
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
}
Local<Object> js_tx = 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
String::Utf8Value tx_hex_(js_tx->Get(NanNew<String>("hex"))->ToString());
std::string tx_hex = std::string(*tx_hex_);
2014-09-25 12:38:42 -07:00
async_broadcast_tx_data *data = new async_broadcast_tx_data();
2014-09-25 13:12:28 -07:00
data->tx_hex = tx_hex;
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("");
data->callback = Persistent<Function>::New(callback);
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_broadcast_tx,
(uv_after_work_cb)async_broadcast_tx_after);
assert(status == 0);
NanReturnValue(Undefined());
}
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
2014-09-25 13:12:28 -07:00
CDataStream ssData(ParseHex(data->tx_hex), SER_NETWORK, PROTOCOL_VERSION);
2014-09-25 12:05:39 -07:00
CTransaction tx;
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;
}
2014-09-29 13:38:27 -07:00
// jstx_to_ctx(jstx, ctx);
2014-09-25 12:05:39 -07:00
try {
ssData >> tx;
} catch (std::exception &e) {
data->err_msg = std::string("TX decode failed");
return;
}
uint256 hashTx = tx.GetHash();
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;
if (!AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees)) {
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;
}
} else {
SyncWithWallets(hashTx, tx, NULL);
}
RelayTransaction(tx, hashTx);
data->tx_hash = hashTx.GetHex();
}
static void
async_broadcast_tx_after(uv_work_t *req) {
NanScope();
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
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
2014-09-29 13:38:27 -07:00
// jstx_to_ctx(jstx, ctx);
2014-09-25 14:01:50 -07:00
CDataStream ssData(ParseHex(data->tx_hex), SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
ssData >> tx;
Local<Object> entry = NanNew<Object>();
2014-09-29 13:38:27 -07:00
ctx_to_jstx(tx, 0, entry);
2014-09-25 14:01:50 -07:00
const unsigned argc = 3;
2014-09-25 12:05:39 -07:00
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
2014-09-25 14:01:50 -07:00
Local<Value>::New(NanNew<String>(data->tx_hash)),
Local<Value>::New(entry)
2014-09-25 12:05:39 -07:00
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
}
2014-09-26 11:23:21 -07:00
/**
* VerifyBlock
*/
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-09-26 11:39:25 -07:00
Local<Object> js_block = Local<Object>::Cast(args[0]);
String::Utf8Value block_hex_(js_block->Get(NanNew<String>("hex"))->ToString());
std::string block_hex = std::string(*block_hex_);
2014-09-26 11:23:21 -07:00
2014-09-29 13:38:27 -07:00
// jsblock_to_cblock(jsblock, cblock);
2014-09-26 11:23:21 -07:00
CBlock block;
2014-09-26 11:39:25 -07:00
CDataStream ssData(ParseHex(block_hex), SER_NETWORK, PROTOCOL_VERSION);
2014-09-26 11:23:21 -07:00
ssData >> block;
CValidationState state;
bool valid = CheckBlock(block, state);
NanReturnValue(NanNew<Boolean>(valid));
}
2014-09-26 11:34:55 -07:00
/**
* VerifyTransaction
*/
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-09-26 11:39:25 -07:00
Local<Object> js_tx = Local<Object>::Cast(args[0]);
String::Utf8Value tx_hex_(js_tx->Get(NanNew<String>("hex"))->ToString());
std::string tx_hex = std::string(*tx_hex_);
2014-09-26 11:34:55 -07:00
2014-09-29 13:38:27 -07:00
// jstx_to_ctx(jstx, ctx);
2014-09-26 11:34:55 -07:00
CTransaction tx;
2014-09-26 11:39:25 -07:00
CDataStream ssData(ParseHex(tx_hex), SER_NETWORK, PROTOCOL_VERSION);
2014-09-26 11:34:55 -07:00
ssData >> tx;
CValidationState state;
bool valid = CheckTransaction(tx, state);
2014-09-29 12:18:29 -07:00
std::string reason;
2014-09-26 11:34:55 -07:00
bool standard = IsStandardTx(tx, reason);
NanReturnValue(NanNew<Boolean>(valid && standard));
}
2014-09-26 12:20:00 -07:00
/**
* Wallet
*/
int64_t
2014-09-29 12:18:29 -07:00
GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth) {
int64_t nBalance = 0;
// Tally wallet transactions
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
it != pwalletMain->mapWallet.end(); ++it) {
const CWalletTx& wtx = (*it).second;
if (!IsFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) {
continue;
}
int64_t nReceived, nSent, nFee;
wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee);
if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) {
nBalance += nReceived;
}
nBalance -= nSent + nFee;
}
// Tally internal accounting entries
nBalance += walletdb.GetAccountCreditDebit(strAccount);
return nBalance;
}
int64_t
2014-09-29 12:18:29 -07:00
GetAccountBalance(const std::string& strAccount, int nMinDepth) {
CWalletDB walletdb(pwalletMain->strWalletFile);
return GetAccountBalance(walletdb, strAccount, nMinDepth);
}
2014-09-26 12:20:00 -07:00
NAN_METHOD(WalletNewAddress) {
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
"Usage: bitcoindjs.walletNewAddress(options)");
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
if (!pwalletMain->IsLocked()) {
pwalletMain->TopUpKeyPool();
}
// Generate a new key that is added to wallet
CPubKey newKey;
if (!pwalletMain->GetKeyFromPool(newKey)) {
// return NanThrowError("Keypool ran out, please call keypoolrefill first");
// EnsureWalletIsUnlocked();
if (pwalletMain->IsLocked()) {
return NanThrowError("Please enter the wallet passphrase with walletpassphrase first.");
}
2014-09-26 12:20:00 -07:00
pwalletMain->TopUpKeyPool(100);
if (pwalletMain->GetKeyPoolSize() < 100) {
return NanThrowError("Error refreshing keypool.");
}
}
CKeyID keyID = newKey.GetID();
pwalletMain->SetAddressBook(keyID, strAccount, "receive");
NanReturnValue(NanNew<String>(CBitcoinAddress(keyID).ToString()));
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletGetAccountAddress) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletGetAccountAddress(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletSetAccount) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletSetAccount(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletGetAccount) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletGetAccount(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 11:59:57 -07:00
NAN_METHOD(WalletSendTo) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 11:59:57 -07:00
"Usage: bitcoindjs.walletSendTo(options)");
2014-09-26 12:42:04 -07:00
}
Local<Object> options = Local<Object>::Cast(args[0]);
2014-09-29 11:59:57 -07:00
async_wallet_sendto_data *data = new async_wallet_sendto_data();
2014-09-26 13:18:23 -07:00
String::Utf8Value addr_(options->Get(NanNew<String>("address"))->ToString());
std::string addr = std::string(*addr_);
2014-09-29 11:59:57 -07:00
data->address = addr;
2014-09-26 12:42:04 -07:00
// Amount
int64_t nAmount = options->Get(NanNew<String>("amount"))->IntegerValue();
2014-09-29 11:59:57 -07:00
data->nAmount = nAmount;
2014-09-26 12:42:04 -07:00
// Wallet comments
CWalletTx wtx;
if (options->Get(NanNew<String>("comment"))->IsString()) {
2014-09-26 13:18:23 -07:00
String::Utf8Value comment_(options->Get(NanNew<String>("comment"))->ToString());
std::string comment = std::string(*comment_);
wtx.mapValue["comment"] = comment;
}
if (options->Get(NanNew<String>("to"))->IsString()) {
2014-09-26 13:18:23 -07:00
String::Utf8Value to_(options->Get(NanNew<String>("to"))->ToString());
std::string to = std::string(*to_);
wtx.mapValue["to"] = to;
}
2014-09-29 11:59:57 -07:00
data->wtx = wtx;
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_wallet_sendto,
(uv_after_work_cb)async_wallet_sendto_after);
assert(status == 0);
NanReturnValue(Undefined());
}
static void
async_wallet_sendto(uv_work_t *req) {
async_wallet_sendto_data* data = static_cast<async_wallet_sendto_data*>(req->data);
CBitcoinAddress address(data->address);
if (!address.IsValid()) {
data->err_msg = std::string("Invalid Bitcoin address");
return;
}
// Amount
int64_t nAmount = data->nAmount;
// Wallet Transaction
CWalletTx wtx = data->wtx;
2014-09-26 12:42:04 -07:00
// EnsureWalletIsUnlocked();
if (pwalletMain->IsLocked()) {
2014-09-29 11:59:57 -07:00
data->err_msg = std::string("Please enter the wallet passphrase with walletpassphrase first.");
return;
}
2014-09-26 12:42:04 -07:00
2014-09-29 11:59:57 -07:00
std::string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
2014-09-26 13:18:23 -07:00
if (strError != "") {
2014-09-29 11:59:57 -07:00
data->err_msg = strError;
return;
2014-09-26 13:18:23 -07:00
}
2014-09-26 12:42:04 -07:00
2014-09-29 11:59:57 -07:00
data->tx_hash = wtx.GetHash().GetHex();
}
2014-09-26 12:42:04 -07:00
2014-09-29 11:59:57 -07:00
static void
async_wallet_sendto_after(uv_work_t *req) {
NanScope();
async_wallet_sendto_data* data = static_cast<async_wallet_sendto_data*>(req->data);
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(NanNew<String>(data->tx_hash))
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
2014-09-26 12:42:04 -07:00
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletSignMessage) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletSignMessage(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletVerifyMessage) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletVerifyMessage(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletGetBalance) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletGetBalance(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletGetUnconfirmedBalance) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletGetUnconfirmedBalance(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletSendFrom) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletSendFrom(options)");
2014-09-26 12:42:04 -07:00
}
Local<Object> options = Local<Object>::Cast(args[0]);
2014-09-29 12:15:59 -07:00
async_wallet_sendfrom_data *data = new async_wallet_sendfrom_data();
2014-09-26 13:18:23 -07:00
String::Utf8Value addr_(options->Get(NanNew<String>("address"))->ToString());
std::string addr = std::string(*addr_);
2014-09-29 12:15:59 -07:00
data->address = addr;
2014-09-26 13:18:23 -07:00
2014-09-29 12:15:59 -07:00
String::Utf8Value from_(options->Get(NanNew<String>("from"))->ToString());
std::string from = std::string(*from_);
std::string strAccount = from;
2014-09-26 13:18:23 -07:00
int64_t nAmount = options->Get(NanNew<String>("amount"))->IntegerValue();
2014-09-29 12:15:59 -07:00
data->nAmount = nAmount;
2014-09-26 12:42:04 -07:00
int nMinDepth = 1;
if (options->Get(NanNew<String>("minDepth"))->IsNumber()) {
2014-09-26 13:18:23 -07:00
nMinDepth = options->Get(NanNew<String>("minDepth"))->IntegerValue();
}
2014-09-29 12:15:59 -07:00
data->nMinDepth = nMinDepth;
2014-09-26 12:42:04 -07:00
CWalletTx wtx;
wtx.strFromAccount = strAccount;
if (options->Get(NanNew<String>("comment"))->IsString()) {
2014-09-26 13:18:23 -07:00
String::Utf8Value comment_(options->Get(NanNew<String>("comment"))->ToString());
std::string comment = std::string(*comment_);
wtx.mapValue["comment"] = comment;
}
if (options->Get(NanNew<String>("to"))->IsString()) {
2014-09-26 13:18:23 -07:00
String::Utf8Value to_(options->Get(NanNew<String>("to"))->ToString());
std::string to = std::string(*to_);
wtx.mapValue["to"] = to;
}
2014-09-29 12:15:59 -07:00
data->wtx = wtx;
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_wallet_sendfrom,
(uv_after_work_cb)async_wallet_sendfrom_after);
assert(status == 0);
NanReturnValue(Undefined());
}
static void
async_wallet_sendfrom(uv_work_t *req) {
async_wallet_sendfrom_data* data = static_cast<async_wallet_sendfrom_data*>(req->data);
CBitcoinAddress address(data->address);
if (!address.IsValid()) {
data->err_msg = std::string("Invalid Bitcoin address");
return;
}
int64_t nAmount = data->nAmount;
int nMinDepth = data->nMinDepth;
CWalletTx wtx = data->wtx;
std::string strAccount = data->wtx.strFromAccount;
2014-09-26 12:42:04 -07:00
// EnsureWalletIsUnlocked();
if (pwalletMain->IsLocked()) {
2014-09-29 12:15:59 -07:00
data->err_msg = std::string("Please enter the wallet passphrase with walletpassphrase first.");
return;
}
2014-09-26 12:42:04 -07:00
// Check funds
int64_t nBalance = GetAccountBalance(strAccount, nMinDepth);
2014-09-26 13:18:23 -07:00
if (nAmount > nBalance) {
2014-09-29 12:15:59 -07:00
data->err_msg = std::string("Account has insufficient funds");
return;
2014-09-26 13:18:23 -07:00
}
2014-09-26 12:42:04 -07:00
// Send
2014-09-29 12:15:59 -07:00
std::string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx);
2014-09-26 13:18:23 -07:00
if (strError != "") {
2014-09-29 12:15:59 -07:00
data->err_msg = strError;
return;
2014-09-26 13:18:23 -07:00
}
2014-09-26 12:42:04 -07:00
2014-09-29 12:15:59 -07:00
data->tx_hash = wtx.GetHash().GetHex();
}
static void
async_wallet_sendfrom_after(uv_work_t *req) {
NanScope();
async_wallet_sendfrom_data* data = static_cast<async_wallet_sendfrom_data*>(req->data);
2014-09-26 12:42:04 -07:00
2014-09-29 12:15:59 -07:00
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(NanNew<String>(data->tx_hash))
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
2014-09-26 12:42:04 -07:00
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletListTransactions) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletListTransactions(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletListAccounts) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletListAccounts(options)");
2014-09-26 12:42:04 -07:00
}
Local<Object> options = Local<Object>::Cast(args[0]);
int nMinDepth = 1;
if (options->Get(NanNew<String>("minDepth"))->IsNumber()) {
nMinDepth = options->Get(NanNew<String>("minDepth"))->IntegerValue();
}
map<string, int64_t> mapAccountBalances;
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
if (IsMine(*pwalletMain, entry.first)) { // This address belongs to me
mapAccountBalances[entry.second.name] = 0;
}
}
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
it != pwalletMain->mapWallet.end(); ++it) {
const CWalletTx& wtx = (*it).second;
int64_t nFee;
2014-09-29 12:18:29 -07:00
std::string strSentAccount;
list<pair<CTxDestination, int64_t> > listReceived;
list<pair<CTxDestination, int64_t> > listSent;
int nDepth = wtx.GetDepthInMainChain();
if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0) {
continue;
}
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
mapAccountBalances[strSentAccount] -= nFee;
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent) {
mapAccountBalances[strSentAccount] -= s.second;
}
if (nDepth >= nMinDepth) {
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived) {
if (pwalletMain->mapAddressBook.count(r.first)) {
mapAccountBalances[pwalletMain->mapAddressBook[r.first].name] += r.second;
} else {
mapAccountBalances[""] += r.second;
}
}
}
}
list<CAccountingEntry> acentries;
CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
BOOST_FOREACH(const CAccountingEntry& entry, acentries) {
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
}
Local<Object> obj = NanNew<Object>();
BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
Local<Object> entry = NanNew<Object>();
entry->Set(NanNew<String>("balance"), NanNew<Number>(accountBalance.second));
Local<Array> addr = NanNew<Array>();
int i = 0;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook) {
const CBitcoinAddress& address = item.first;
2014-09-29 12:18:29 -07:00
const std::string& strName = item.second.name;
if (strName == accountBalance.first) {
Local<Object> a = NanNew<Object>();
a->Set(NanNew<String>("address"), NanNew<String>(address.ToString()));
CKeyID keyID;
if (!address.GetKeyID(keyID)) {
return NanThrowError("Address does not refer to a key");
}
CKey vchSecret;
if (!pwalletMain->GetKey(keyID, vchSecret)) {
return NanThrowError("Private key for address is not known");
}
std::string priv = CBitcoinSecret(vchSecret).ToString();
a->Set(NanNew<String>("privkeycompressed"), NanNew<Boolean>(vchSecret.IsCompressed()));
a->Set(NanNew<String>("privkey"), NanNew<String>(priv));
CPubKey vchPubKey;
pwalletMain->GetPubKey(keyID, vchPubKey);
a->Set(NanNew<String>("pubkeycompressed"), NanNew<Boolean>(vchPubKey.IsCompressed()));
a->Set(NanNew<String>("pubkey"), NanNew<String>(HexStr(vchPubKey)));
addr->Set(i, a);
i++;
}
}
entry->Set(NanNew<String>("addresses"), addr);
obj->Set(NanNew<String>(accountBalance.first), entry);
}
NanReturnValue(obj);
2014-09-26 12:42:04 -07:00
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletGetTransaction) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletGetTransaction(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletBackup) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletBackup(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
NAN_METHOD(WalletPassphrase) {
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
"Usage: bitcoindjs.walletPassphrase(options)");
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
NAN_METHOD(WalletPassphraseChange) {
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
"Usage: bitcoindjs.walletPassphraseChange(options)");
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
NAN_METHOD(WalletLock) {
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
"Usage: bitcoindjs.walletLock(options)");
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletEncrypt) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletEncrypt(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
2014-09-29 12:26:46 -07:00
NAN_METHOD(WalletSetTxFee) {
2014-09-26 12:42:04 -07:00
NanScope();
if (args.Length() < 1 || !args[0]->IsObject()) {
return NanThrowError(
2014-09-29 12:26:46 -07:00
"Usage: bitcoindjs.walletSetTxFee(options)");
2014-09-26 12:42:04 -07:00
}
// Parse the account first so we don't generate a key if there's an error
Local<Object> options = Local<Object>::Cast(args[0]);
String::Utf8Value name_(options->Get(NanNew<String>("name"))->ToString());
std::string strAccount = std::string(*name_);
NanReturnValue(Undefined());
}
/**
* Conversions
*/
2014-09-23 13:15:59 -07:00
static inline void
2014-09-29 13:38:27 -07:00
cblock_to_jsblock(const CBlock& block, const CBlockIndex* blockindex, Local<Object> obj) {
obj->Set(NanNew<String>("hash"), NanNew<String>(block.GetHash().GetHex().c_str()));
CMerkleTx txGen(block.vtx[0]);
txGen.SetMerkleBranch(&block);
obj->Set(NanNew<String>("confirmations"), NanNew<Number>((int)txGen.GetDepthInMainChain()));
obj->Set(NanNew<String>("size"), NanNew<Number>((int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
obj->Set(NanNew<String>("height"), NanNew<Number>(blockindex->nHeight));
obj->Set(NanNew<String>("version"), NanNew<Number>(block.nVersion));
obj->Set(NanNew<String>("merkleroot"), NanNew<String>(block.hashMerkleRoot.GetHex()));
Local<Array> txs = NanNew<Array>();
int ti = 0;
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
Local<Object> entry = NanNew<Object>();
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
2014-09-29 12:18:29 -07:00
std::string strHex = HexStr(ssTx.begin(), ssTx.end());
entry->Set(NanNew<String>("hex"), NanNew<String>(strHex));
entry->Set(NanNew<String>("txid"), NanNew<String>(tx.GetHash().GetHex()));
entry->Set(NanNew<String>("version"), NanNew<Number>(tx.nVersion));
entry->Set(NanNew<String>("locktime"), NanNew<Number>(tx.nLockTime));
Local<Array> vin = NanNew<Array>();
int vi = 0;
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
Local<Object> in = NanNew<Object>();
if (tx.IsCoinBase()) {
in->Set(NanNew<String>("coinbase"), NanNew<String>(HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
} else {
in->Set(NanNew<String>("txid"), NanNew<String>(txin.prevout.hash.GetHex()));
in->Set(NanNew<String>("vout"), NanNew<Number>((boost::int64_t)txin.prevout.n));
Local<Object> o = NanNew<Object>();
o->Set(NanNew<String>("asm"), NanNew<String>(txin.scriptSig.ToString()));
o->Set(NanNew<String>("hex"), NanNew<String>(HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
in->Set(NanNew<String>("scriptSig"), o);
}
in->Set(NanNew<String>("sequence"), NanNew<Number>((boost::int64_t)txin.nSequence));
vin->Set(vi, in);
vi++;
}
entry->Set(NanNew<String>("vin"), vin);
Local<Array> vout = NanNew<Array>();
for (unsigned int vo = 0; vo < tx.vout.size(); vo++) {
const CTxOut& txout = tx.vout[vo];
Local<Object> out = NanNew<Object>();
out->Set(NanNew<String>("value"), NanNew<Number>(txout.nValue));
out->Set(NanNew<String>("n"), NanNew<Number>((boost::int64_t)vo));
Local<Object> o = NanNew<Object>();
{
const CScript& scriptPubKey = txout.scriptPubKey;
Local<Object> out = o;
bool fIncludeHex = true;
txnouttype type;
vector<CTxDestination> addresses;
int nRequired;
out->Set(NanNew<String>("asm"), NanNew<String>(scriptPubKey.ToString()));
if (fIncludeHex) {
out->Set(NanNew<String>("hex"), NanNew<String>(HexStr(scriptPubKey.begin(), scriptPubKey.end())));
}
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
out->Set(NanNew<String>("type"), NanNew<String>(GetTxnOutputType(type)));
} else {
out->Set(NanNew<String>("reqSigs"), NanNew<Number>(nRequired));
out->Set(NanNew<String>("type"), NanNew<String>(GetTxnOutputType(type)));
Local<Array> a = NanNew<Array>();
int ai = 0;
BOOST_FOREACH(const CTxDestination& addr, addresses) {
a->Set(ai, NanNew<String>(CBitcoinAddress(addr).ToString()));
ai++;
}
out->Set(NanNew<String>("addresses"), a);
}
}
out->Set(NanNew<String>("scriptPubKey"), o);
vout->Set(vo, out);
}
entry->Set(NanNew<String>("vout"), vout);
{
const uint256 hashBlock = block.GetHash();
if (hashBlock != 0) {
entry->Set(NanNew<String>("blockhash"), NanNew<String>(hashBlock.GetHex()));
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex)) {
entry->Set(NanNew<String>("confirmations"),
NanNew<Number>(1 + chainActive.Height() - pindex->nHeight));
entry->Set(NanNew<String>("time"), NanNew<Number>((boost::int64_t)pindex->nTime));
entry->Set(NanNew<String>("blocktime"), NanNew<Number>((boost::int64_t)pindex->nTime));
} else {
entry->Set(NanNew<String>("confirmations"), NanNew<Number>(0));
}
}
}
}
txs->Set(ti, entry);
ti++;
}
obj->Set(NanNew<String>("tx"), txs);
obj->Set(NanNew<String>("time"), NanNew<Number>((boost::int64_t)block.GetBlockTime()));
obj->Set(NanNew<String>("nonce"), NanNew<Number>((boost::uint64_t)block.nNonce));
obj->Set(NanNew<String>("bits"), NanNew<Number>(block.nBits));
obj->Set(NanNew<String>("difficulty"), NanNew<Number>(GetDifficulty(blockindex)));
obj->Set(NanNew<String>("chainwork"), NanNew<String>(blockindex->nChainWork.GetHex()));
if (blockindex->pprev) {
obj->Set(NanNew<String>("previousblockhash"), NanNew<String>(blockindex->pprev->GetBlockHash().GetHex()));
}
CBlockIndex *pnext = chainActive.Next(blockindex);
if (pnext) {
obj->Set(NanNew<String>("nextblockhash"), NanNew<String>(pnext->GetBlockHash().GetHex()));
}
}
2014-09-23 13:15:59 -07:00
static inline void
2014-09-29 13:38:27 -07:00
ctx_to_jstx(const CTransaction& tx, uint256 hashBlock, Local<Object> entry) {
2014-09-25 14:12:09 -07:00
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
2014-09-29 12:18:29 -07:00
std::string strHex = HexStr(ssTx.begin(), ssTx.end());
2014-09-25 14:12:09 -07:00
entry->Set(NanNew<String>("hex"), NanNew<String>(strHex));
entry->Set(NanNew<String>("txid"), NanNew<String>(tx.GetHash().GetHex()));
entry->Set(NanNew<String>("version"), NanNew<Number>(tx.nVersion));
entry->Set(NanNew<String>("locktime"), NanNew<Number>(tx.nLockTime));
Local<Array> vin = NanNew<Array>();
int vi = 0;
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
Local<Object> in = NanNew<Object>();
if (tx.IsCoinBase()) {
in->Set(NanNew<String>("coinbase"), NanNew<String>(HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
} else {
in->Set(NanNew<String>("txid"), NanNew<String>(txin.prevout.hash.GetHex()));
in->Set(NanNew<String>("vout"), NanNew<Number>((boost::int64_t)txin.prevout.n));
Local<Object> o = NanNew<Object>();
o->Set(NanNew<String>("asm"), NanNew<String>(txin.scriptSig.ToString()));
o->Set(NanNew<String>("hex"), NanNew<String>(HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
in->Set(NanNew<String>("scriptSig"), o);
}
in->Set(NanNew<String>("sequence"), NanNew<Number>((boost::int64_t)txin.nSequence));
vin->Set(vi, in);
vi++;
}
entry->Set(NanNew<String>("vin"), vin);
Local<Array> vout = NanNew<Array>();
for (unsigned int vo = 0; vo < tx.vout.size(); vo++) {
const CTxOut& txout = tx.vout[vo];
Local<Object> out = NanNew<Object>();
out->Set(NanNew<String>("value"), NanNew<Number>(txout.nValue));
out->Set(NanNew<String>("n"), NanNew<Number>((boost::int64_t)vo));
Local<Object> o = NanNew<Object>();
{
const CScript& scriptPubKey = txout.scriptPubKey;
Local<Object> out = o;
bool fIncludeHex = true;
txnouttype type;
vector<CTxDestination> addresses;
int nRequired;
out->Set(NanNew<String>("asm"), NanNew<String>(scriptPubKey.ToString()));
if (fIncludeHex) {
out->Set(NanNew<String>("hex"), NanNew<String>(HexStr(scriptPubKey.begin(), scriptPubKey.end())));
}
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
out->Set(NanNew<String>("type"), NanNew<String>(GetTxnOutputType(type)));
} else {
out->Set(NanNew<String>("reqSigs"), NanNew<Number>(nRequired));
out->Set(NanNew<String>("type"), NanNew<String>(GetTxnOutputType(type)));
Local<Array> a = NanNew<Array>();
int ai = 0;
BOOST_FOREACH(const CTxDestination& addr, addresses) {
a->Set(ai, NanNew<String>(CBitcoinAddress(addr).ToString()));
ai++;
}
out->Set(NanNew<String>("addresses"), a);
}
}
out->Set(NanNew<String>("scriptPubKey"), o);
vout->Set(vo, out);
}
entry->Set(NanNew<String>("vout"), vout);
if (hashBlock != 0) {
entry->Set(NanNew<String>("blockhash"), NanNew<String>(hashBlock.GetHex()));
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex* pindex = (*mi).second;
if (chainActive.Contains(pindex)) {
entry->Set(NanNew<String>("confirmations"),
NanNew<Number>(1 + chainActive.Height() - pindex->nHeight));
entry->Set(NanNew<String>("time"), NanNew<Number>((boost::int64_t)pindex->nTime));
entry->Set(NanNew<String>("blocktime"), NanNew<Number>((boost::int64_t)pindex->nTime));
} else {
entry->Set(NanNew<String>("confirmations"), NanNew<Number>(0));
}
}
}
}
2014-09-29 13:49:13 -07:00
#if 0
2014-09-29 13:38:27 -07:00
static inline void
jsblock_to_cblock(Local<Object> jsblock, CBlock& cblock) {
const unsigned argc = 1;
Local<Value> argv[argc] = {
Local<Value>::New(jsblock)
};
2014-09-29 14:08:56 -07:00
//Local<Object> object = Local<Object>::Cast(Context::GetCurrent()->Global()->Get(NanNew<String>("bitcoindjs")));
//Local<Object> object = Context::GetCurrent()->Global()->Get(NanNew<String>("bitcoindjs"));
//Local<Function> toHex = Local<Function>::Cast(object->Get(NanNew<String>("txToHex")));
//Local<Function> toHex = Local<Function>::Cast(bitcoindjs_obj->Get(NanNew<String>("blockToHex")));
Local<Function> toHex = bitcoindjs_obj->Get(NanNew<String>("blockToHex")).As<Function>();
2014-09-29 13:49:13 -07:00
Local<String> block_hex__ = toHex->Call(Context::GetCurrent()->Global(), argc, argv);
2014-09-29 13:38:27 -07:00
String::Utf8Value block_hex_(block_hex__->ToString());
std::string block_hex = std::string(*block_hex_);
CDataStream ssData(ParseHex(block_hex), SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> cblock;
} catch (std::exception &e) {
2014-09-29 13:49:13 -07:00
NanThrowError("Block decode failed");
2014-09-29 13:38:27 -07:00
}
}
static inline void
jstx_to_ctx(Local<Object> jstx, CTransaction& ctx) {
const unsigned argc = 1;
Local<Value> argv[argc] = {
Local<Value>::New(jstx)
};
2014-09-29 14:08:56 -07:00
//Local<Object> object = Local<Object>::Cast(Context::GetCurrent()->Global()->Get(NanNew<String>("bitcoindjs")));
//Local<Object> object = Context::GetCurrent()->Global()->Get(NanNew<String>("bitcoindjs"));
//Local<Function> toHex = Local<Function>::Cast(object->Get(NanNew<String>("txToHex")));
//Local<Function> toHex = Local<Function>::Cast(bitcoindjs_obj->Get(NanNew<String>("txToHex")));
Local<Function> toHex = bitcoindjs_obj->Get(NanNew<String>("txToHex")).As<Function>();
2014-09-29 13:49:13 -07:00
Local<String> tx_hex__ = toHex->Call(Context::GetCurrent()->Global(), argc, argv);
2014-09-29 13:38:27 -07:00
String::Utf8Value tx_hex_(tx_hex__->ToString());
std::string tx_hex = std::string(*tx_hex_);
CDataStream ssData(ParseHex(tx_hex), SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> ctx;
} catch (std::exception &e) {
2014-09-29 13:49:13 -07:00
NanThrowError("TX decode failed");
2014-09-29 13:38:27 -07:00
}
}
2014-09-29 13:49:13 -07:00
#endif
2014-09-29 13:38:27 -07:00
2014-08-12 12:03:04 -07:00
/**
* Init
*/
extern "C" void
init(Handle<Object> target) {
NanScope();
2014-09-29 13:38:27 -07:00
bitcoindjs_obj = target;
2014-08-12 12:03:04 -07:00
NODE_SET_METHOD(target, "start", StartBitcoind);
2014-09-11 17:18:36 -07:00
NODE_SET_METHOD(target, "stop", StopBitcoind);
2014-09-17 14:08:26 -07:00
NODE_SET_METHOD(target, "stopping", IsStopping);
2014-09-17 12:52:35 -07:00
NODE_SET_METHOD(target, "stopped", IsStopped);
2014-09-18 15:32:19 -07:00
NODE_SET_METHOD(target, "getBlock", GetBlock);
2014-09-22 10:19:37 -07:00
NODE_SET_METHOD(target, "getTx", GetTx);
2014-09-22 17:58:59 -07:00
NODE_SET_METHOD(target, "pollBlocks", PollBlocks);
2014-09-23 13:57:49 -07:00
NODE_SET_METHOD(target, "pollMempool", PollMempool);
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-09-26 12:42:04 -07:00
2014-09-26 12:20:00 -07:00
NODE_SET_METHOD(target, "walletNewAddress", WalletNewAddress);
2014-09-29 12:26:46 -07:00
NODE_SET_METHOD(target, "walletGetAccountAddress", WalletGetAccountAddress);
NODE_SET_METHOD(target, "walletSetAccount", WalletSetAccount);
NODE_SET_METHOD(target, "walletGetAccount", WalletGetAccount);
2014-09-29 11:59:57 -07:00
NODE_SET_METHOD(target, "walletSendTo", WalletSendTo);
2014-09-29 12:26:46 -07:00
NODE_SET_METHOD(target, "walletSignMessage", WalletSignMessage);
NODE_SET_METHOD(target, "walletVerifyMessage", WalletVerifyMessage);
NODE_SET_METHOD(target, "walletGetBalance", WalletGetBalance);
NODE_SET_METHOD(target, "walletGetUnconfirmedBalance", WalletGetUnconfirmedBalance);
NODE_SET_METHOD(target, "walletSendFrom", WalletSendFrom);
NODE_SET_METHOD(target, "walletListTransactions", WalletListTransactions);
NODE_SET_METHOD(target, "walletListAccounts", WalletListAccounts);
NODE_SET_METHOD(target, "walletGetTransaction", WalletGetTransaction);
NODE_SET_METHOD(target, "walletBackup", WalletBackup);
2014-09-26 12:42:04 -07:00
NODE_SET_METHOD(target, "walletPassphrase", WalletPassphrase);
NODE_SET_METHOD(target, "walletPassphraseChange", WalletPassphraseChange);
NODE_SET_METHOD(target, "walletLock", WalletLock);
2014-09-29 12:26:46 -07:00
NODE_SET_METHOD(target, "walletEncrypt", WalletEncrypt);
NODE_SET_METHOD(target, "walletSetTxFee", WalletSetTxFee);
2014-08-12 12:03:04 -07:00
}
NODE_MODULE(bitcoindjs, init)